diff --git a/.mailmap b/.mailmap index 679e9d79847c..63a49cd41328 100644 --- a/.mailmap +++ b/.mailmap @@ -155,6 +155,8 @@ Mark Sinclair =Mark Sinclair <=125axel125@gmail.com> Markus Westerlind Markus Martin Hafskjold Thoresen Matej Lach Matej Ľach +Mateusz Mikuła +Mateusz Mikuła Matt Brubeck Matthew Auld Matthew McPherrin diff --git a/Cargo.lock b/Cargo.lock index f6334e9bdb81..db9f0069ced0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,11 +13,19 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "aho-corasick" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "alloc" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -115,7 +123,7 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -181,6 +189,14 @@ dependencies = [ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bstr" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bufstream" version = "0.1.4" @@ -246,7 +262,7 @@ dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crates-io 0.25.0", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (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.21 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)", @@ -261,7 +277,7 @@ dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -373,12 +389,11 @@ dependencies = [ "compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "derive-new 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0", "rustc_tools_util 0.1.1", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -396,10 +411,9 @@ dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.5.0 (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.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (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.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -448,7 +462,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.12" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", @@ -461,13 +475,12 @@ version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -486,7 +499,7 @@ dependencies = [ "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", @@ -553,13 +566,10 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.3.4" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -578,7 +588,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -602,7 +612,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -618,10 +628,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.6.2" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -733,7 +744,7 @@ name = "dlmalloc" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -749,7 +760,7 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -781,7 +792,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -793,7 +804,7 @@ dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -899,7 +910,7 @@ name = "fortanix-sgx-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -1010,14 +1021,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1034,7 +1045,7 @@ dependencies = [ "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1049,7 +1060,7 @@ dependencies = [ "pest 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1060,7 +1071,7 @@ name = "hashbrown" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-alloc 1.0.0", "rustc-std-workspace-core 1.0.0", ] @@ -1135,19 +1146,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ignore" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1471,7 +1482,7 @@ dependencies = [ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "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 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1483,7 +1494,7 @@ dependencies = [ [[package]] name = "measureme" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1761,7 +1772,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1771,7 +1782,7 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc 0.0.0", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "unwind 0.0.0", @@ -1956,7 +1967,7 @@ name = "profiler_builtins" version = "0.0.0" dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1974,7 +1985,7 @@ dependencies = [ "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2182,12 +2193,12 @@ dependencies = [ [[package]] name = "regex" -version = "1.1.0" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2202,7 +2213,7 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2231,7 +2242,7 @@ dependencies = [ "cargo 0.37.0", "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "clippy_lints 0.0.212", - "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2249,7 +2260,7 @@ dependencies = [ "racer 2.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rls-analysis 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2348,7 +2359,7 @@ dependencies = [ "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2481,7 +2492,7 @@ name = "rustc-demangle" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2609,7 +2620,7 @@ dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2839,7 +2850,7 @@ dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2901,7 +2912,7 @@ dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -3018,7 +3029,7 @@ dependencies = [ "alloc 0.0.0", "build_helper 0.1.0", "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -3092,11 +3103,11 @@ dependencies = [ "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-rustc_target 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax_pos 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3132,7 +3143,7 @@ name = "same-file" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3287,7 +3298,7 @@ dependencies = [ "alloc 0.0.0", "backtrace-sys 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "dlmalloc 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "fortanix-sgx-abi 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3553,7 +3564,7 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3614,7 +3625,7 @@ name = "tokio-executor" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3658,7 +3669,7 @@ name = "tokio-reactor" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3704,9 +3715,9 @@ name = "tokio-threadpool" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3719,7 +3730,7 @@ name = "tokio-timer" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3792,7 +3803,7 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3878,7 +3889,7 @@ name = "unwind" version = "0.0.0" dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3957,7 +3968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3986,7 +3997,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4003,7 +4014,7 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4039,6 +4050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" +"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c" "checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477" "checksum annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e8bcdcd5b291ce85a78f2b9d082a8de9676c12b1840d386d67bc5eea6f9d2b4e" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" @@ -4055,6 +4067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +"checksum bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "853b090ce0f45d0265902666bf88039ea3da825e33796716c511a1ec9c170036" "checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" @@ -4074,20 +4087,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -"checksum compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6549720ae78db799196d4af8f719facb4c7946710b4b64148482553e54b56d15" +"checksum compiler_builtins 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "e3f235c329e5cb9fa3d2ca2cc36256ba9a7f23fa76e0f4db6f68c23b73b2ac69" "checksum compiletest_rs 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "f40ecc9332b68270998995c00f8051ee856121764a0d3230e64c9efd059d27b6" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2640d6d0bf22e82bed1b73c6aef8d5dd31e5abe6666c57e6d45e2649f4f887" "checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192" -"checksum crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2a9ea8f77c7f9efd317a8a5645f515d903a2d86ee14d2337a5facd1bd52c12" +"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" "checksum curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "a85f2f95f2bd277d316d1aa8a477687ab4a6942258c7db7c89c187534669979c" "checksum curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "9d91a0052d5b982887d8e829bee0faffc7218ea3c6ebd3d6c2c8f678a93c9a42" @@ -4131,7 +4144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0" "checksum git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d58551e903ed7e2d6fe3a2f3c7efa3a784ec29b19d0fbb035aaf0497c183fbdd" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" -"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865" +"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454" "checksum handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d89ec99d1594f285d4590fc32bac5f75cdab383f1123d504d27862c644a807dd" "checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166" "checksum hashbrown 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "570178d5e4952010d138b0f1d581271ff3a02406d990f887d1e87e3d6e43b0ac" @@ -4143,7 +4156,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec" -"checksum ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ad03ca67dc12474ecd91fdb94d758cbd20cb4e7a78ebe831df26a9b7511e1162" +"checksum ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002" "checksum im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9460397452f537fd51808056ff209f4c4c4c9d20d42ae952f517708726284972" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" @@ -4176,7 +4189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum mdbook 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba0d44cb4089c741b9a91f3e5218298a40699c2f3a070a85014eed290c60819" -"checksum measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "36bb2b263a6795d352035024d6b30ce465bb79a5e5280d74c3b5f8464c657bcc" +"checksum measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" @@ -4249,9 +4262,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26" "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" -"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" +"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" +"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rls-analysis 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d53d49a28f75da9d02790d9256fecf6c0481e0871374326023c7a33131295579" "checksum rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ce1fdac03e138c4617ff87b194e1ff57a39bb985a044ccbd8673d30701e411" @@ -4365,7 +4378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" diff --git a/README.md b/README.md index 8fa12a6571b8..4a130d257770 100644 --- a/README.md +++ b/README.md @@ -130,9 +130,15 @@ build. #### MSVC [windows-msvc]: #windows-msvc -MSVC builds of Rust additionally require an installation of Visual Studio 2013 -(or later) so `rustc` can use its linker. Make sure to check the “C++ tools” -option. +MSVC builds of Rust additionally require an installation of Visual Studio 2017 +(or later) so `rustc` can use its linker. The simplest way is to get the +[Visual Studio Build Tools] and check the “C++ build tools” workload. + +[Visual Studio Build Tools]: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019 + +At last check (cmake 3.14.3 and msvc 16.0.3) using the 2019 tools fails to +build the in-tree LLVM build with a CMake error, so use 2017 instead by +including the “MSVC v141 – VS 2017 C++ x64/x86 build tools (v14.16)” component. With these dependencies installed, you can build the compiler in a `cmd.exe` shell with: diff --git a/RELEASES.md b/RELEASES.md index 3b4f4182702d..4185961187b3 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,109 @@ +Version 1.35.0 (2019-05-23) +========================== + +Language +-------- +- [`FnOnce`, `FnMut`, and the `Fn` traits are now implemented for `Box`, + `Box`, and `Box` respectively.][59500] +- [You can now coerce closures into unsafe function pointers.][59580] e.g. + ```rust + unsafe fn call_unsafe(func: unsafe fn()) { + func() + } + + pub fn main() { + unsafe { call_unsafe(|| {}); } + } + ``` + + +Compiler +-------- +- [Added the `armv6-unknown-freebsd-gnueabihf` and + `armv7-unknown-freebsd-gnueabihf` targets.][58080] +- [Added the `wasm32-unknown-wasi` target.][59464] + + +Libraries +--------- +- [`Thread` will now show its ID in `Debug` output.][59460] +- [`StdinLock`, `StdoutLock`, and `StderrLock` now implement `AsRawFd`.][59512] +- [`alloc::System` now implements `Default`.][59451] +- [Expanded `Debug` output (`{:#?}`) for structs now has a trailing comma on the + last field.][59076] +- [`char::{ToLowercase, ToUppercase}` now + implement `ExactSizeIterator`.][58778] +- [All `NonZero` numeric types now implement `FromStr`.][58717] +- [Removed the `Read` trait bounds + on the `BufReader::{get_ref, get_mut, into_inner}` methods.][58423] +- [You can now call the `dbg!` macro without any parameters to print the file + and line where it is called.][57847] +- [In place ASCII case conversions are now up to 4× faster.][59283] + e.g. `str::make_ascii_lowercase` +- [`hash_map::{OccupiedEntry, VacantEntry}` now implement `Sync` + and `Send`.][58369] + +Stabilized APIs +--------------- +- [`f32::copysign`] +- [`f64::copysign`] +- [`RefCell::replace_with`] +- [`RefCell::map_split`] +- [`ptr::hash`] +- [`Range::contains`] +- [`RangeFrom::contains`] +- [`RangeTo::contains`] +- [`RangeInclusive::contains`] +- [`RangeToInclusive::contains`] +- [`Option::copied`] + +Cargo +----- +- [You can now set `cargo:rustc-cdylib-link-arg` at build time to pass custom + linker arguments when building a `cdylib`.][cargo/6298] Its usage is highly + platform specific. + +Misc +---- +- [The Rust toolchain is now available natively for musl based distros.][58575] + +[59460]: https://github.com/rust-lang/rust/pull/59460/ +[59464]: https://github.com/rust-lang/rust/pull/59464/ +[59500]: https://github.com/rust-lang/rust/pull/59500/ +[59512]: https://github.com/rust-lang/rust/pull/59512/ +[59580]: https://github.com/rust-lang/rust/pull/59580/ +[59283]: https://github.com/rust-lang/rust/pull/59283/ +[59451]: https://github.com/rust-lang/rust/pull/59451/ +[59076]: https://github.com/rust-lang/rust/pull/59076/ +[58778]: https://github.com/rust-lang/rust/pull/58778/ +[58717]: https://github.com/rust-lang/rust/pull/58717/ +[58369]: https://github.com/rust-lang/rust/pull/58369/ +[58423]: https://github.com/rust-lang/rust/pull/58423/ +[58080]: https://github.com/rust-lang/rust/pull/58080/ +[57847]: https://github.com/rust-lang/rust/pull/57847/ +[58575]: https://github.com/rust-lang/rust/pull/58575 +[cargo/6298]: https://github.com/rust-lang/cargo/pull/6298/ +[`f32::copysign`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.copysign +[`f64::copysign`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.copysign +[`RefCell::replace_with`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.replace_with +[`RefCell::map_split`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.map_split +[`ptr::hash`]: https://doc.rust-lang.org/stable/std/ptr/fn.hash.html +[`Range::contains`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.contains +[`RangeFrom::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeFrom.html#method.contains +[`RangeTo::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeTo.html#method.contains +[`RangeInclusive::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html#method.contains +[`RangeToInclusive::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html#method.contains +[`Option::copied`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.copied + +Version 1.34.2 (2019-05-14) +=========================== + +* [Destabilize the `Error::type_id` function due to a security + vulnerability][60785] ([CVE-2019-12083]) + +[60785]: https://github.com/rust-lang/rust/pull/60785 +[CVE-2019-12083]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12083 + Version 1.34.1 (2019-04-25) =========================== diff --git a/config.toml.example b/config.toml.example index 8b2153cd2e63..556625b531d1 100644 --- a/config.toml.example +++ b/config.toml.example @@ -480,7 +480,7 @@ # linked binaries #musl-root = "..." -# The root location of the `wasm32-unknown-wasi` sysroot. +# The root location of the `wasm32-wasi` sysroot. #wasi-root = "..." # Used in testing for configuring where the QEMU images are located, you diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 86c82adffa9b..1c2b882f6659 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -177,7 +177,6 @@ def default_build_triple(): # The goal here is to come up with the same triple as LLVM would, # at least for the subset of platforms we're willing to target. ostype_mapper = { - 'Bitrig': 'unknown-bitrig', 'Darwin': 'apple-darwin', 'DragonFly': 'unknown-dragonfly', 'FreeBSD': 'unknown-freebsd', diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 9c4e856f0b88..e1cdd226fd6e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -168,7 +168,7 @@ pub fn std_cargo(builder: &Builder<'_>, .arg("--manifest-path") .arg(builder.src.join("src/liballoc/Cargo.toml")) .arg("--features") - .arg("compiler-builtins-mem"); + .arg("compiler-builtins-mem compiler-builtins-c"); } else { let features = builder.std_features(); diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 5777331b9bfd..da2e03a1a084 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -317,6 +317,10 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { fn configure_cmake(builder: &Builder<'_>, target: Interned, cfg: &mut cmake::Config) { + // Do not print installation messages for up-to-date files. + // LLVM and LLD builds can produce a lot of those and hit CI limits on log size. + cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY"); + if builder.config.ninja { cfg.generator("Ninja"); } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index a3d96836aad5..be0af8be7b27 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -683,7 +683,7 @@ impl Step for RustdocUi { target: self.target, mode: "ui", suite: "rustdoc-ui", - path: None, + path: Some("src/test/rustdoc-ui"), compare_mode: None, }) } @@ -1184,8 +1184,19 @@ impl Step for Compiletest { Err(_) => p, } }) - .filter(|p| p.starts_with(suite_path) && p.is_file()) - .map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap()) + .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file())) + .filter_map(|p| { + // Since test suite paths are themselves directories, if we don't + // specify a directory or file, we'll get an empty string here + // (the result of the test suite directory without its suite prefix). + // Therefore, we need to filter these out, as only the first --test-args + // flag is respected, so providing an empty --test-args conflicts with + // any following it. + match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) { + Some(s) if s != "" => Some(s), + _ => None, + } + }) .collect(); test_args.append(&mut builder.config.cmd.test_args()); @@ -1870,6 +1881,10 @@ impl Step for CrateRustdoc { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); + if self.host.contains("musl") { + cargo.arg("'-Ctarget-feature=-crt-static'"); + } + if !builder.config.verbose_tests { cargo.arg("--quiet"); } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index bd99dc118e66..60911d917899 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -113,7 +113,7 @@ pub fn gnu_target(target: &str) -> &str { } pub fn make(host: &str) -> PathBuf { - if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd") + if host.contains("dragonfly") || host.contains("freebsd") || host.contains("netbsd") || host.contains("openbsd") { PathBuf::from("gmake") diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index 04db5e9c0572..d19862d9c583 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -75,7 +75,7 @@ ENV CARGO_TARGET_AARCH64_FUCHSIA_RUSTFLAGS \ ENV TARGETS=x86_64-fuchsia ENV TARGETS=$TARGETS,aarch64-fuchsia ENV TARGETS=$TARGETS,wasm32-unknown-unknown -ENV TARGETS=$TARGETS,wasm32-unknown-wasi +ENV TARGETS=$TARGETS,wasm32-wasi # FIXME(#61022) - reenable solaris # ENV TARGETS=$TARGETS,sparcv9-sun-solaris # ENV TARGETS=$TARGETS,x86_64-sun-solaris @@ -87,5 +87,5 @@ ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda ENV X86_FORTANIX_SGX_LIBS="/x86_64-fortanix-unknown-sgx/lib/" ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \ - --set target.wasm32-unknown-wasi.wasi-root=/wasm32-unknown-wasi + --set target.wasm32-wasi.wasi-root=/wasm32-wasi ENV SCRIPT python2.7 ../x.py dist --target $TARGETS diff --git a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh index 965286e5bcf6..98d6df043bac 100755 --- a/src/ci/docker/dist-various-2/build-wasi-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-wasi-toolchain.sh @@ -13,7 +13,7 @@ git clone https://github.com/CraneStation/wasi-sysroot cd wasi-sysroot git reset --hard e5f14be38362f1ab83302895a6e74b2ffd0e2302 -make -j$(nproc) INSTALL_DIR=/wasm32-unknown-wasi install +make -j$(nproc) INSTALL_DIR=/wasm32-wasi install cd .. rm -rf reference-sysroot-wasi diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile index 39ad785b41ac..385eefde846c 100644 --- a/src/ci/docker/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/dist-x86_64-musl/Dockerfile @@ -23,7 +23,7 @@ COPY scripts/musl-toolchain.sh /build/ # We need to mitigate rust-lang/rust#34978 when compiling musl itself as well RUN CFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ CXXFLAGS="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ - bash musl-toolchain.sh x86_64 && rm -rf build + REPLACE_CC=1 bash musl-toolchain.sh x86_64 && rm -rf build COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -35,10 +35,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-extended \ --disable-docs \ --set target.x86_64-unknown-linux-musl.crt-static=false \ - --build $HOSTS \ - --set target.x86_64-unknown-linux-musl.cc=x86_64-linux-musl-gcc \ - --set target.x86_64-unknown-linux-musl.cxx=x86_64-linux-musl-g++ \ - --set target.x86_64-unknown-linux-musl.linker=x86_64-linux-musl-gcc + --build $HOSTS # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our @@ -49,4 +46,5 @@ ENV RUST_CONFIGURE_ARGS \ ENV CFLAGS_x86_64_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wa,--compress-debug-sections=none \ -Wl,--compress-debug-sections=none" +# To run native tests replace `dist` below with `test` ENV SCRIPT python2.7 ../x.py dist --build $HOSTS diff --git a/src/ci/docker/scripts/musl-toolchain.sh b/src/ci/docker/scripts/musl-toolchain.sh index 8cdbfebea4dd..d5988a25671a 100644 --- a/src/ci/docker/scripts/musl-toolchain.sh +++ b/src/ci/docker/scripts/musl-toolchain.sh @@ -45,6 +45,15 @@ cd - ln -s $OUTPUT/$TARGET/lib/libc.so /lib/ld-musl-$ARCH.so.1 echo $OUTPUT/$TARGET/lib >> /etc/ld-musl-$ARCH.path +# Now when musl bootstraps itself create proper toolchain symlinks to make build and tests easier +if [ "$REPLACE_CC" = "1" ]; then + for exec in cc gcc; do + ln -s $TARGET-gcc /usr/local/bin/$exec + done + for exec in cpp c++ g++; do + ln -s $TARGET-g++ /usr/local/bin/$exec + done +fi export CC=$TARGET-gcc export CXX=$TARGET-g++ diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index af0198705a2f..a0fe307cffcd 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -74,7 +74,9 @@ status_check() { check_dispatch $1 beta nomicon src/doc/nomicon check_dispatch $1 beta reference src/doc/reference check_dispatch $1 beta rust-by-example src/doc/rust-by-example - check_dispatch $1 beta edition-guide src/doc/edition-guide + # Temporarily disabled until + # https://github.com/rust-lang/rust/issues/60459 is fixed. + # check_dispatch $1 beta edition-guide src/doc/edition-guide check_dispatch $1 beta rls src/tools/rls check_dispatch $1 beta rustfmt src/tools/rustfmt check_dispatch $1 beta clippy-driver src/tools/clippy diff --git a/src/doc/book b/src/doc/book index db919bc6bb90..29fe982990e4 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit db919bc6bb9071566e9c4f05053672133eaac33e +Subproject commit 29fe982990e43b9367be0ff47abc82fb2123fd03 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index c413d42a207b..581c6cccfaf9 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit c413d42a207bd082f801ec0137c31b71e4bfed4c +Subproject commit 581c6cccfaf995394ea9dcac362dc8e731c18558 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index de3d55f521e6..9858872bd1b7 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit de3d55f521e657863df45260ebbca1b10527f662 +Subproject commit 9858872bd1b7dbba5ec27dc30d34eba00acd7ef9 diff --git a/src/doc/nomicon b/src/doc/nomicon index fb29b147be4d..c656171b749b 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit fb29b147be4d9a1f8e24aba753a7e1de537abf61 +Subproject commit c656171b749b7307f21371dd0d3278efee5573b8 diff --git a/src/doc/reference b/src/doc/reference index 2a2de9ce0959..862b669c3958 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 2a2de9ce095979978ad7b582daecf94e4070b916 +Subproject commit 862b669c395822bb0938781d74f860e5762ad4fb diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 1ff0f8e01883..811c697b232c 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 1ff0f8e018838a710ebc0cc1a7bf74ebe73ad9f1 +Subproject commit 811c697b232c611ed754d279ed20643a0c4096f6 diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide index 99e1b1d53656..3cb727b62b95 160000 --- a/src/doc/rustc-guide +++ b/src/doc/rustc-guide @@ -1 +1 @@ -Subproject commit 99e1b1d53656be08654df399fc200584aebb50e4 +Subproject commit 3cb727b62b953d59b4360d39aa68b6dc8f157655 diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index dfb40284ef6c..bd7f6630ea2a 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -17,28 +17,147 @@ to `#[cfg(verbose)]` and `#[cfg(feature = "serde")]` respectively. ## `-L`: add a directory to the library search path -When looking for external crates, a directory passed to this flag will be searched. +When looking for external crates or libraries, a directory passed to this flag +will be searched. + +The kind of search path can optionally be specified with the form `-L +KIND=PATH` where `KIND` may be one of: + +- `dependency` — Only search for transitive dependencies in this directory. +- `crate` — Only search for this crate's direct dependencies in this + directory. +- `native` — Only search for native libraries in this directory. +- `framework` — Only search for macOS frameworks in this directory. +- `all` — Search for all library kinds in this directory. This is the default + if `KIND` is not specified. ## `-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. +The kind of library can optionally be specified with the form `-l KIND=lib` +where `KIND` may be one of: + +- `dylib` — A native dynamic library. +- `static` — A native static library (such as a `.a` archive). +- `framework` — A macOS framework. + +The kind of library can be specified in a [`#[link]` +attribute][link-attribute]. If the kind is not specified in the `link` +attribute or on the command-line, it will link a dynamic library if available, +otherwise it will use a static library. If the kind is specified on the +command-line, it will override the kind specified in a `link` attribute. + +The name used in a `link` attribute may be overridden using the form `-l +ATTR_NAME:LINK_NAME` where `ATTR_NAME` is the name in the `link` attribute, +and `LINK_NAME` is the name of the actual library that will be linked. + +[link-attribute]: ../reference/items/external-blocks.html#the-link-attribute + ## `--crate-type`: a list of types of crates for the compiler to emit -This instructs `rustc` on which crate type to build. +This instructs `rustc` on which crate type to build. This flag accepts a +comma-separated list of values, and may be specified multiple times. The valid +crate types are: + +- `lib` — Generates a library kind preferred by the compiler, currently + defaults to `rlib`. +- `rlib` — A Rust static library. +- `staticlib` — A native static library. +- `dylib` — A Rust dynamic library. +- `cdylib` — A native dynamic library. +- `bin` — A runnable executable program. +- `proc-macro` — Generates a format suitable for a procedural macro library + that may be loaded by the compiler. + +The crate type may be specified with the [`crate_type` attribute][crate_type]. +The `--crate-type` command-line value will override the `crate_type` +attribute. + +More details may be found in the [linkage chapter] of the reference. + +[linkage chapter]: ../reference/linkage.html +[crate_type]: ../reference/linkage.html ## `--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 +## `--edition`: specify the edition to use -Instead of producing a crate, this flag can print out things like the assembly or LLVM-IR. +This flag takes a value of `2015` or `2018`. The default is `2015`. More +information about editions may be found in the [edition guide]. + +[edition guide]: ../edition-guide/introduction.html + +## `--emit`: specifies the types of output files to generate + +This flag controls the types of output files generated by the compiler. It +accepts a comma-separated list of values, and may be specified multiple times. +The valid emit kinds are: + +- `asm` — Generates a file with the crate's assembly code. The default output + filename is `CRATE_NAME.s`. +- `dep-info` — Generates a file with Makefile syntax that indicates all the + source files that were loaded to generate the crate. The default output + filename is `CRATE_NAME.d`. +- `link` — Generates the crates specified by `--crate-type`. The default + output filenames depend on the crate type and platform. This is the default + if `--emit` is not specified. +- `llvm-bc` — Generates a binary file containing the [LLVM bitcode]. The + default output filename is `CRATE_NAME.bc`. +- `llvm-ir` — Generates a file containing [LLVM IR]. The default output + filename is `CRATE_NAME.ll`. +- `metadata` — Generates a file containing metadata about the crate. The + default output filename is `CRATE_NAME.rmeta`. +- `mir` — Generates a file containing rustc's mid-level intermediate + representation. The default output filename is `CRATE_NAME.mir`. +- `obj` — Generates a native object file. The default output filename is + `CRATE_NAME.o`. + +The output filename can be set with the `-o` flag. A suffix may be added to +the filename with the `-C extra-filename` flag. The files are written to the +current directory unless the `--out-dir` flag is used. Each emission type may +also specify the output filename with the form `KIND=PATH`, which takes +precedence over the `-o` flag. + +[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html +[LLVM IR]: https://llvm.org/docs/LangRef.html ## `--print`: print compiler information -This flag prints out various information about the compiler. +This flag prints out various information about the compiler. This flag may be +specified multiple times, and the information is printed in the order the +flags are specified. Specifying a `--print` flag will usually disable the +`--emit` step and will only print the requested information. The valid types +of print values are: + +- `crate-name` — The name of the crate. +- `file-names` — The names of the files created by the `link` emit kind. +- `sysroot` — Path to the sysroot. +- `cfg` — List of cfg values. See [conditional compilation] for more + information about cfg values. +- `target-list` — List of known targets. The target may be selected with the + `--target` flag. +- `target-cpus` — List of available CPU values for the current target. The + target CPU may be selected with the `-C target-cpu=val` flag. +- `target-features` — List of available target features for the current + target. Target features may be enabled with the `-C target-feature=val` + flag. +- `relocation-models` — List of relocation models. Relocation models may be + selected with the `-C relocation-model=val` flag. +- `code-models` — List of code models. Code models may be selected with the + `-C code-model=val` flag. +- `tls-models` — List of Thread Local Storage models supported. The model may + be selected with the `-Z tls-model=val` flag. +- `native-static-libs` — This may be used when creating a `staticlib` crate + type. If this is the only flag, it will perform a full compilation and + include a diagnostic note that indicates the linker flags to use when + linking the resulting static library. The note starts with the text + `native-static-libs:` to make it easier to fetch the output. + +[conditional compilation]: ../reference/conditional-compilation.html ## `-g`: include debug information @@ -54,7 +173,8 @@ This flag controls the output filename. ## `--out-dir`: directory to write the output in -The outputted crate will be written to this directory. +The outputted crate will be written to this directory. This flag is ignored if +the `-o` flag is used. ## `--explain`: provide a detailed explanation of an error message @@ -111,8 +231,9 @@ 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. +This flag allows you to pass the name and location of an external crate that +will be linked into the crate you are building. This flag may be specified +multiple times. The format of the value should be `CRATENAME=PATH`. ## `--sysroot`: Override the system root @@ -121,8 +242,32 @@ distribution; this flag allows that to be overridden. ## `--error-format`: control how errors are produced -This flag lets you control the format of errors. +This flag lets you control the format of messages. Messages are printed to +stderr. The valid options are: + +- `human` — Human-readable output. This is the default. +- `json` — Structured JSON output. +- `short` — Short, one-line messages. ## `--color`: configure coloring of output -This flag lets you control color settings of the output. +This flag lets you control color settings of the output. The valid options +are: + +- `auto` — Use colors if output goes to a tty. This is the default. +- `always` — Always use colors. +- `never` — Never colorize output. + +## `--remap-path-prefix`: remap source names in output + +Remap source path prefixes in all output, including compiler diagnostics, +debug information, macro expansions, etc. It takes a value of the form +`FROM=TO` where a path prefix equal to `FROM` is rewritten to the value `TO`. +The `FROM` may itself contain an `=` symbol, but the `TO` value may not. This +flag may be specified multiple times. + +This is useful for normalizing build products, for example by removing the +current directory out of pathnames emitted into the object files. The +replacement is purely textual, with no consideration of the current system's +pathname syntax. For example `--remap-path-prefix foo=bar` will match +`foo/lib.rs` but not `./foo/lib.rs`. diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md index 46b717f3387d..049e59b65172 100644 --- a/src/doc/rustc/src/lints/groups.md +++ b/src/doc/rustc/src/lints/groups.md @@ -21,9 +21,9 @@ Here's a list of each lint group, and the lints that they are made up of: | 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 | +| 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, 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 +compiler you have installed. diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index fa62d1a03f53..c1740f272ed2 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -222,44 +222,3 @@ error: invalid `crate_type` value | ^^^^^^^^^^^^^^^^^^^^ | ``` - -## incoherent-fundamental-impls - -This lint detects potentially-conflicting impls that were erroneously allowed. Some -example code that triggers this lint: - -```rust,ignore -pub trait Trait1 { - type Output; -} - -pub trait Trait2 {} - -pub struct A; - -impl Trait1 for T where T: Trait2 { - type Output = (); -} - -impl Trait1> for A { - type Output = i32; -} -``` - -This will produce: - -```text -error: conflicting implementations of trait `Trait1>` for type `A`: (E0119) - --> src/main.rs:13:1 - | -9 | impl Trait1 for T where T: Trait2 { - | --------------------------------------------- first implementation here -... -13 | impl Trait1> for A { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` - | - = note: #[deny(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 - = note: downstream crates may implement trait `Trait2>` for type `A` -``` diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 61e5b3d0133f..b165c5a6b3b9 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -92,6 +92,21 @@ the tracking issue. #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] ``` +### `html_root_url` + +The `#[doc(html_root_url = "…")]` attribute value indicates the URL for +generating links to external crates. When rustdoc needs to generate a link to +an item in an external crate, it will first check if the extern crate has been +documented locally on-disk, and if so link directly to it. Failing that, it +will use the URL given by the `--extern-html-root-url` command-line flag if +available. If that is not available, then it will use the `html_root_url` +value in the extern crate if it is available. If that is not available, then +the extern items will not be linked. + +```rust,ignore +#![doc(html_root_url = "https://docs.rs/serde/1.0")] +``` + ### `html_no_source` By default, `rustdoc` will include the source code of your program, with links diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index 54472e35b1b2..bbcacb7f3d5d 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -98,21 +98,21 @@ documentation for them as well! `rustdoc` can also generate HTML from standalone Markdown files. Let's give it a try: create a `README.md` file with these contents: -```text - # Docs +````text +# Docs - This is a project to test out `rustdoc`. +This is a project to test out `rustdoc`. - [Here is a link!](https://www.rust-lang.org) +[Here is a link!](https://www.rust-lang.org) - ## Subheading +## Subheading - ```rust - fn foo() -> i32 { - 1 + 1 - } - ``` +```rust +fn foo() -> i32 { + 1 + 1 +} ``` +```` And call `rustdoc` on it: diff --git a/src/etc/natvis/liballoc.natvis b/src/etc/natvis/liballoc.natvis index e3d99e34b357..de30b58526a1 100644 --- a/src/etc/natvis/liballoc.natvis +++ b/src/etc/natvis/liballoc.natvis @@ -7,11 +7,11 @@ buf.cap len - buf.ptr.pointer.__0 + buf.ptr.pointer - + {{ size={tail <= head ? head - tail : buf.cap - tail + head} }} tail <= head ? head - tail : buf.cap - tail + head @@ -24,19 +24,19 @@ - buf.ptr.pointer.__0 + i + buf.ptr.pointer[i] i = (i + 1 == buf.cap ? 0 : i + 1) - + {{ size={len} }} len - *(alloc::linked_list::Node<$T1> **)&head - *(alloc::linked_list::Node<$T1> **)&next + *(alloc::collections::linked_list::Node<$T1> **)&head + *(alloc::collections::linked_list::Node<$T1> **)&next element diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 37d64be1ce96..0e703b3b9502 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -1,15 +1,15 @@ - {{ Unique {*pointer.__0} }} + {{ Unique {pointer} }} - pointer.__0 + pointer - {{ Shared {*pointer.__0} }} + {{ Shared {pointer} }} - pointer.__0 + pointer diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index ddf0044c506f..bcb27bb5161e 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -33,3 +33,4 @@ harness = false [features] compiler-builtins-mem = ['compiler_builtins/mem'] +compiler-builtins-c = ["compiler_builtins/c"] diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index ddc6481eec78..41ff06d70ff0 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -37,6 +37,8 @@ extern "Rust" { /// /// Note: while this type is unstable, the functionality it provides can be /// accessed through the [free functions in `alloc`](index.html#functions). +/// +/// [`Alloc`]: trait.Alloc.html #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; @@ -54,6 +56,10 @@ pub struct Global; /// /// See [`GlobalAlloc::alloc`]. /// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc +/// /// # Examples /// /// ``` @@ -87,6 +93,10 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { /// # Safety /// /// See [`GlobalAlloc::dealloc`]. +/// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { @@ -105,6 +115,10 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { /// # Safety /// /// See [`GlobalAlloc::realloc`]. +/// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc #[stable(feature = "global_alloc", since = "1.28.0")] #[inline] pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { @@ -124,6 +138,10 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 /// /// See [`GlobalAlloc::alloc_zeroed`]. /// +/// [`Global`]: struct.Global.html +/// [`Alloc`]: trait.Alloc.html +/// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed +/// /// # Examples /// /// ``` diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index c355361b53c4..c5a0b6e877b6 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -231,6 +231,20 @@ use super::SpecExtend; /// assert_eq!(heap.pop(), Some(Reverse(5))); /// assert_eq!(heap.pop(), None); /// ``` +/// +/// # Time complexity +/// +/// | [push] | [pop] | [peek]/[peek\_mut] | +/// |--------|----------|--------------------| +/// | O(1)~ | O(log n) | O(1) | +/// +/// The value for `push` is an expected cost; the method documentation gives a +/// more detailed analysis. +/// +/// [push]: #method.push +/// [pop]: #method.pop +/// [peek]: #method.peek +/// [peek\_mut]: #method.peek_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct BinaryHeap { data: Vec, @@ -384,6 +398,10 @@ impl BinaryHeap { /// } /// assert_eq!(heap.peek(), Some(&2)); /// ``` + /// + /// # Time complexity + /// + /// Cost is O(1) in the worst case. #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { if self.is_empty() { @@ -411,6 +429,11 @@ impl BinaryHeap { /// assert_eq!(heap.pop(), Some(1)); /// assert_eq!(heap.pop(), None); /// ``` + /// + /// # Time complexity + /// + /// The worst case cost of `pop` on a heap containing *n* elements is O(log + /// n). #[stable(feature = "rust1", since = "1.0.0")] pub fn pop(&mut self) -> Option { self.data.pop().map(|mut item| { @@ -438,6 +461,22 @@ impl BinaryHeap { /// assert_eq!(heap.len(), 3); /// assert_eq!(heap.peek(), Some(&5)); /// ``` + /// + /// # Time complexity + /// + /// The expected cost of `push`, averaged over every possible ordering of + /// the elements being pushed, and over a sufficiently large number of + /// pushes, is O(1). This is the most meaningful cost metric when pushing + /// elements that are *not* already in any sorted pattern. + /// + /// The time complexity degrades if elements are pushed in predominantly + /// ascending order. In the worst case, elements are pushed in ascending + /// sorted order and the amortized cost per push is O(log n) against a heap + /// containing *n* elements. + /// + /// The worst case cost of a *single* call to `push` is O(n). The worst case + /// occurs when capacity is exhausted and needs a resize. The resize cost + /// has been amortized in the previous figures. #[stable(feature = "rust1", since = "1.0.0")] pub fn push(&mut self, item: T) { let old_len = self.len(); @@ -650,6 +689,10 @@ impl BinaryHeap { /// assert_eq!(heap.peek(), Some(&5)); /// /// ``` + /// + /// # Time complexity + /// + /// Cost is O(1) in the worst case. #[stable(feature = "rust1", since = "1.0.0")] pub fn peek(&self) -> Option<&T> { self.data.get(0) @@ -992,6 +1035,11 @@ impl<'a, T> Iterator for Iter<'a, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1047,6 +1095,11 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1093,6 +1146,11 @@ impl Iterator for Drain<'_, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "drain", since = "1.6.0")] diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index 6b079fc87cc7..414abb00ef1f 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -1193,6 +1193,11 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { fn size_hint(&self) -> (usize, Option) { (self.length, Some(self.length)) } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a V)> { + self.next_back() + } } #[stable(feature = "fused", since = "1.26.0")] @@ -1253,6 +1258,11 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { (self.length, Some(self.length)) } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a mut V)> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1359,6 +1369,11 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { (self.length, Some(self.length)) } + + #[inline] + fn last(mut self) -> Option<(K, V)> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1421,6 +1436,11 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a K> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1458,6 +1478,11 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a V> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1495,6 +1520,11 @@ impl<'a, K, V> Iterator for Range<'a, K, V> { unsafe { Some(self.next_unchecked()) } } } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a V)> { + self.next_back() + } } #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1508,6 +1538,11 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a mut V> { + self.next_back() + } } #[stable(feature = "map_values_mut", since = "1.10.0")] @@ -1626,6 +1661,11 @@ impl<'a, K, V> Iterator for RangeMut<'a, K, V> { unsafe { Some(self.next_unchecked()) } } } + + #[inline] + fn last(mut self) -> Option<(&'a K, &'a mut V)> { + self.next_back() + } } impl<'a, K, V> RangeMut<'a, K, V> { diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 16a96ca19b82..6f2467dfd6b5 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -1019,6 +1019,11 @@ impl<'a, T> Iterator for Iter<'a, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> DoubleEndedIterator for Iter<'a, T> { @@ -1044,6 +1049,11 @@ impl Iterator for IntoIter { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for IntoIter { @@ -1073,6 +1083,11 @@ impl<'a, T> Iterator for Range<'a, T> { fn next(&mut self) -> Option<&'a T> { self.iter.next().map(|(k, _)| k) } + + #[inline] + fn last(mut self) -> Option<&'a T> { + self.next_back() + } } #[stable(feature = "btree_range", since = "1.17.0")] diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index d65c24f7350a..31e49d06a7b5 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1835,8 +1835,8 @@ impl VecDeque { /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns false. - /// This method operates in place and preserves the order of the retained - /// elements. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. /// /// # Examples /// @@ -1848,6 +1848,20 @@ impl VecDeque { /// buf.retain(|&x| x%2 == 0); /// assert_eq!(buf, [2, 4]); /// ``` + /// + /// The exact order may be useful for tracking external state, like an index. + /// + /// ``` + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.extend(1..6); + /// + /// let keep = [false, true, true, false, true]; + /// let mut i = 0; + /// buf.retain(|_| (keep[i], i += 1).0); + /// assert_eq!(buf, [2, 3, 5]); + /// ``` #[stable(feature = "vec_deque_retain", since = "1.4.0")] pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool @@ -1934,8 +1948,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vecdeque_rotate)] - /// /// use std::collections::VecDeque; /// /// let mut buf: VecDeque<_> = (0..10).collect(); @@ -1949,7 +1961,7 @@ impl VecDeque { /// } /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// ``` - #[unstable(feature = "vecdeque_rotate", issue = "56686")] + #[stable(feature = "vecdeque_rotate", since = "1.36.0")] pub fn rotate_left(&mut self, mid: usize) { assert!(mid <= self.len()); let k = self.len() - mid; @@ -1979,8 +1991,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// #![feature(vecdeque_rotate)] - /// /// use std::collections::VecDeque; /// /// let mut buf: VecDeque<_> = (0..10).collect(); @@ -1994,7 +2004,7 @@ impl VecDeque { /// } /// assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); /// ``` - #[unstable(feature = "vecdeque_rotate", issue = "56686")] + #[stable(feature = "vecdeque_rotate", since = "1.36.0")] pub fn rotate_right(&mut self, k: usize) { assert!(k <= self.len()); let mid = self.len() - k; diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 2edd946ff11c..d90036eaf49b 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -109,7 +109,7 @@ #![feature(rustc_const_unstable)] #![feature(const_vec_new)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_array)] #![feature(alloc_layout_extra)] #![feature(try_trait)] #![feature(iter_nth_back)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 68eecd97ea11..0dffb19476f3 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -932,6 +932,11 @@ impl RcEqIdent for Rc { } } +/// We're doing this specialization here, and not as a more general optimization on `&T`, because it +/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to +/// store large values, that are slow to clone, but also heavy to check for equality, causing this +/// cost to pay off more easily. It's also more likely to have two `Rc` clones, that point to +/// the same value, than two `&T`s. #[stable(feature = "rust1", since = "1.0.0")] impl RcEqIdent for Rc { #[inline] diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index a3e2098695f7..e74d37c1c2ba 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -1200,8 +1200,8 @@ impl String { /// Retains only the characters specified by the predicate. /// /// In other words, remove all characters `c` such that `f(c)` returns `false`. - /// This method operates in place and preserves the order of the retained - /// characters. + /// This method operates in place, visiting each character exactly once in the + /// original order, and preserves the order of the retained characters. /// /// # Examples /// @@ -1212,6 +1212,16 @@ impl String { /// /// assert_eq!(s, "foobar"); /// ``` + /// + /// The exact order may be useful for tracking external state, like an index. + /// + /// ``` + /// let mut s = String::from("abcde"); + /// let keep = [false, true, true, false, true]; + /// let mut i = 0; + /// s.retain(|_| (keep[i], i += 1).0); + /// assert_eq!(s, "bce"); + /// ``` #[inline] #[stable(feature = "string_retain", since = "1.26.0")] pub fn retain(&mut self, mut f: F) @@ -2179,6 +2189,14 @@ impl From<&str> for String { } } +#[stable(feature = "from_ref_string", since = "1.35.0")] +impl From<&String> for String { + #[inline] + fn from(s: &String) -> String { + s.clone() + } +} + // note: test pulls in libstd, which causes errors here #[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] @@ -2367,6 +2385,10 @@ impl Iterator for Drain<'_> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "drain", since = "1.6.0")] diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 466e806663c7..90c7859b3db9 100644 --- a/src/liballoc/sync.rs +++ b/src/liballoc/sync.rs @@ -1377,6 +1377,11 @@ impl ArcEqIdent for Arc { } } +/// We're doing this specialization here, and not as a more general optimization on `&T`, because it +/// would otherwise add a cost to all equality checks on refs. We assume that `Arc`s are used to +/// store large values, that are slow to clone, but also heavy to check for equality, causing this +/// cost to pay off more easily. It's also more likely to have two `Arc` clones, that point to +/// the same value, than two `&T`s. #[stable(feature = "rust1", since = "1.0.0")] impl ArcEqIdent for Arc { #[inline] diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index d52814118b3c..989beb3b1bfd 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -143,8 +143,8 @@ fn test_union() { #[test] // Only tests the simple function definition with respect to intersection fn test_is_disjoint() { - let one = [1].into_iter().collect::>(); - let two = [2].into_iter().collect::>(); + let one = [1].iter().collect::>(); + let two = [2].iter().collect::>(); assert!(one.is_disjoint(&two)); } diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index b736750c5760..ddb3120e89d7 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -6,7 +6,6 @@ #![feature(repeat_generic_slice)] #![feature(try_reserve)] #![feature(unboxed_closures)] -#![feature(vecdeque_rotate)] #![deny(rust_2018_idioms)] use std::hash::{Hash, Hasher}; diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index cd62c3e05244..c0cdffe596ba 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -937,8 +937,8 @@ impl Vec { /// Retains only the elements specified by the predicate. /// /// In other words, remove all elements `e` such that `f(&e)` returns `false`. - /// This method operates in place and preserves the order of the retained - /// elements. + /// This method operates in place, visiting each element exactly once in the + /// original order, and preserves the order of the retained elements. /// /// # Examples /// @@ -947,6 +947,16 @@ impl Vec { /// vec.retain(|&x| x%2 == 0); /// assert_eq!(vec, [2, 4]); /// ``` + /// + /// The exact order may be useful for tracking external state, like an index. + /// + /// ``` + /// let mut vec = vec![1, 2, 3, 4, 5]; + /// let keep = [false, true, true, false, true]; + /// let mut i = 0; + /// vec.retain(|_| (keep[i], i += 1).0); + /// assert_eq!(vec, [2, 3, 5]); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn retain(&mut self, mut f: F) where F: FnMut(&T) -> bool @@ -2385,6 +2395,11 @@ impl Iterator for IntoIter { fn count(self) -> usize { self.len() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2504,6 +2519,11 @@ impl Iterator for Drain<'_, T> { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "drain", since = "1.6.0")] @@ -2573,6 +2593,10 @@ impl Iterator for Splice<'_, I> { fn size_hint(&self) -> (usize, Option) { self.drain.size_hint() } + + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "vec_splice", since = "1.21.0")] diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index c124457118cb..f25631e028ee 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -99,7 +99,7 @@ impl Layout { /// [`Layout::from_size_align`](#method.from_size_align). #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] - pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { + pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } } @@ -480,7 +480,7 @@ pub unsafe trait GlobalAlloc { /// this allocator, /// /// * `layout` must be the same layout that was used - /// to allocated that block of memory, + /// to allocate that block of memory, #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); @@ -535,7 +535,7 @@ pub unsafe trait GlobalAlloc { /// * `ptr` must be currently allocated via this allocator, /// /// * `layout` must be the same layout that was used - /// to allocated that block of memory, + /// to allocate that block of memory, /// /// * `new_size` must be greater than zero. /// diff --git a/src/libcore/array.rs b/src/libcore/array.rs index e4cadcbf75b9..03094bfd3337 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -8,7 +8,7 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; -use crate::convert::TryFrom; +use crate::convert::{Infallible, TryFrom}; use crate::fmt; use crate::hash::{Hash, self}; use crate::marker::Unsize; @@ -74,6 +74,13 @@ impl TryFromSliceError { } } +#[stable(feature = "try_from_slice_error", since = "1.36.0")] +impl From for TryFromSliceError { + fn from(x: Infallible) -> TryFromSliceError { + match x {} + } +} + macro_rules! __impl_slice_eq1 { ($Lhs: ty, $Rhs: ty) => { __impl_slice_eq1! { $Lhs, $Rhs, Sized } diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index c0ab364380fb..ddee02ea232d 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -117,6 +117,8 @@ impl Iterator for EscapeDefault { type Item = u8; fn next(&mut self) -> Option { self.range.next().map(|i| self.data[i]) } fn size_hint(&self) -> (usize, Option) { self.range.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for EscapeDefault { diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index cf92babcb400..b3ff447be5ee 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -104,7 +104,6 @@ pub const fn identity(x: T) -> T { x } /// If you need to do a costly conversion it is better to implement [`From`] with type /// `&T` or write a custom function. /// -/// /// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects: /// /// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either @@ -133,7 +132,7 @@ pub const fn identity(x: T) -> T { x } /// converted a the specified type `T`. /// /// For example: By creating a generic function that takes an `AsRef` we express that we -/// want to accept all references that can be converted to &str as an argument. +/// want to accept all references that can be converted to `&str` as an argument. /// Since both [`String`] and `&str` implement `AsRef` we can accept both as input argument. /// /// [`String`]: ../../std/string/struct.String.html @@ -149,7 +148,6 @@ pub const fn identity(x: T) -> T { x } /// let s = "hello".to_string(); /// is_hello(s); /// ``` -/// #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRef { /// Performs the conversion. @@ -182,6 +180,7 @@ pub trait AsRef { /// write a function `add_one`that takes all arguments that can be converted to `&mut u64`. /// Because [`Box`] implements `AsMut` `add_one` accepts arguments of type /// `&mut Box` as well: +/// /// ``` /// fn add_one>(num: &mut T) { /// *num.as_mut() += 1; @@ -191,8 +190,8 @@ pub trait AsRef { /// add_one(&mut boxed_num); /// assert_eq!(*boxed_num, 1); /// ``` -/// [`Box`]: ../../std/boxed/struct.Box.html /// +/// [`Box`]: ../../std/boxed/struct.Box.html #[stable(feature = "rust1", since = "1.0.0")] pub trait AsMut { /// Performs the conversion. @@ -203,9 +202,9 @@ pub trait AsMut { /// A value-to-value conversion that consumes the input value. The /// opposite of [`From`]. /// -/// One should only implement [`Into`] if a conversion to a type outside the current crate is -/// required. Otherwise one should always prefer implementing [`From`] over [`Into`] because -/// implementing [`From`] automatically provides one with a implementation of [`Into`] thanks to +/// One should only implement `Into` if a conversion to a type outside the current crate is +/// required. Otherwise one should always prefer implementing [`From`] over `Into` because +/// implementing [`From`] automatically provides one with a implementation of `Into` thanks to /// the blanket implementation in the standard library. [`From`] cannot do these type of /// conversions because of Rust's orphaning rules. /// @@ -213,8 +212,8 @@ pub trait AsMut { /// /// # Generic Implementations /// -/// - [`From`]` for U` implies `Into for T` -/// - [`Into`]` is reflexive, which means that `Into for T` is implemented +/// - [`From`]` for U` implies `Into for T` +/// - `Into` is reflexive, which means that `Into for T` is implemented /// /// # Implementing `Into` for conversions to external types /// @@ -273,7 +272,7 @@ pub trait AsMut { /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// [`String`]: ../../std/string/struct.String.html -/// [From]: trait.From.html +/// [`From`]: trait.From.html /// [`into`]: trait.Into.html#tymethod.into #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { @@ -285,18 +284,18 @@ pub trait Into: Sized { /// Used to do value-to-value conversions while consuming the input value. It is the reciprocal of /// [`Into`]. /// -/// One should always prefer implementing [`From`] over [`Into`] -/// because implementing [`From`] automatically provides one with a implementation of [`Into`] +/// One should always prefer implementing `From` over [`Into`] +/// because implementing `From` automatically provides one with a implementation of [`Into`] /// thanks to the blanket implementation in the standard library. /// /// Only implement [`Into`] if a conversion to a type outside the current crate is required. -/// [`From`] cannot do these type of conversions because of Rust's orphaning rules. +/// `From` cannot do these type of conversions because of Rust's orphaning rules. /// See [`Into`] for more details. /// -/// Prefer using [`Into`] over using [`From`] when specifying trait bounds on a generic function. +/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function. /// This way, types that directly implement [`Into`] can be used as arguments as well. /// -/// The [`From`] is also very useful when performing error handling. When constructing a function +/// The `From` is also very useful when performing error handling. When constructing a function /// that is capable of failing, the return type will generally be of the form `Result`. /// The `From` trait simplifies error handling by allowing a function to return a single error type /// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more @@ -306,14 +305,15 @@ pub trait Into: Sized { /// /// # Generic Implementations /// -/// - [`From`]` for U` implies [`Into`]` for T` -/// - [`From`] is reflexive, which means that `From for T` is implemented +/// - `From for U` implies [`Into`]` for T` +/// - `From` is reflexive, which means that `From for T` is implemented /// /// # Examples /// /// [`String`] implements `From<&str>`: /// -/// An explicit conversion from a &str to a String is done as follows: +/// An explicit conversion from a `&str` to a String is done as follows: +/// /// ``` /// let string = "hello".to_string(); /// let other_string = String::from("hello"); @@ -361,7 +361,7 @@ pub trait Into: Sized { /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// [`String`]: ../../std/string/struct.String.html -/// [`Into`]: trait.Into.html +/// [`Into`]: trait.Into.html /// [`from`]: trait.From.html#tymethod.from /// [book]: ../../book/ch09-00-error-handling.html #[stable(feature = "rust1", since = "1.0.0")] @@ -422,7 +422,7 @@ pub trait TryInto: Sized { /// /// # Generic Implementations /// -/// - `TryFrom for U` implies [`TryInto`]` for T` +/// - `TryFrom for U` implies [`TryInto`]` for T` /// - [`try_from`] is reflexive, which means that `TryFrom for T` /// is implemented and cannot fail -- the associated `Error` type for /// calling `T::try_from()` on a value of type `T` is `Infallible`. diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 43c1a3b7767a..2f6d745d146d 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -886,7 +886,7 @@ pub trait Pointer { /// /// # Examples /// -/// Basic usage with `i32`: +/// Basic usage with `f64`: /// /// ``` /// let x = 42.0; // 42.0 is '4.2e1' in scientific notation @@ -929,7 +929,7 @@ pub trait LowerExp { /// /// # Examples /// -/// Basic usage with `f32`: +/// Basic usage with `f64`: /// /// ``` /// let x = 42.0; // 42.0 is '4.2E1' in scientific notation diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index 504330a023b3..3f76ac20192b 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -23,7 +23,7 @@ use crate::task::{Context, Poll}; /// When using a future, you generally won't call `poll` directly, but instead /// `await!` the value. #[doc(spotlight)] -#[must_use = "futures do nothing unless polled"] +#[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] pub trait Future { /// The type of value produced on completion. diff --git a/src/libcore/iter/adapters/mod.rs b/src/libcore/iter/adapters/mod.rs index 518442efe741..64e588f65b46 100644 --- a/src/libcore/iter/adapters/mod.rs +++ b/src/libcore/iter/adapters/mod.rs @@ -73,6 +73,11 @@ impl Iterator for Rev where I: DoubleEndedIterator { { self.iter.position(predicate) } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index 403f33581053..38c7c9bc4d08 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -356,7 +356,7 @@ pub trait Iterator { /// /// ``` /// let a = [0, 1, 2, 3, 4, 5]; - /// let mut iter = a.into_iter().step_by(2); + /// let mut iter = a.iter().step_by(2); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&2)); @@ -531,7 +531,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.into_iter().map(|x| 2 * x); + /// let mut iter = a.iter().map(|x| 2 * x); /// /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), Some(4)); @@ -620,7 +620,7 @@ pub trait Iterator { /// ``` /// let a = [0i32, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|x| x.is_positive()); + /// let mut iter = a.iter().filter(|x| x.is_positive()); /// /// assert_eq!(iter.next(), Some(&1)); /// assert_eq!(iter.next(), Some(&2)); @@ -634,7 +634,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|x| **x > 1); // need two *s! + /// let mut iter = a.iter().filter(|x| **x > 1); // need two *s! /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -646,7 +646,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|&x| *x > 1); // both & and * + /// let mut iter = a.iter().filter(|&x| *x > 1); // both & and * /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -657,7 +657,7 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2]; /// - /// let mut iter = a.into_iter().filter(|&&x| x > 1); // two &s + /// let mut iter = a.iter().filter(|&&x| x > 1); // two &s /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -837,7 +837,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.into_iter().skip_while(|x| x.is_negative()); + /// let mut iter = a.iter().skip_while(|x| x.is_negative()); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -851,7 +851,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1]; /// - /// let mut iter = a.into_iter().skip_while(|x| **x < 0); // need two *s! + /// let mut iter = a.iter().skip_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -863,7 +863,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.into_iter().skip_while(|x| **x < 0); + /// let mut iter = a.iter().skip_while(|x| **x < 0); /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -898,7 +898,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.into_iter().take_while(|x| x.is_negative()); + /// let mut iter = a.iter().take_while(|x| x.is_negative()); /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -911,7 +911,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1]; /// - /// let mut iter = a.into_iter().take_while(|x| **x < 0); // need two *s! + /// let mut iter = a.iter().take_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -922,7 +922,7 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.into_iter().take_while(|x| **x < 0); + /// let mut iter = a.iter().take_while(|x| **x < 0); /// /// assert_eq!(iter.next(), Some(&-1)); /// @@ -937,7 +937,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4]; - /// let mut iter = a.into_iter(); + /// let mut iter = a.iter(); /// /// let result: Vec = iter.by_ref() /// .take_while(|n| **n != 3) @@ -1321,7 +1321,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let iter = a.into_iter(); + /// let iter = a.iter(); /// /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i ); /// @@ -1334,7 +1334,7 @@ pub trait Iterator { /// // let's try that again /// let a = [1, 2, 3]; /// - /// let mut iter = a.into_iter(); + /// let mut iter = a.iter(); /// /// // instead, we add in a .by_ref() /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i ); @@ -1479,7 +1479,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// let (even, odd): (Vec, Vec) = a - /// .into_iter() + /// .iter() /// .partition(|&n| n % 2 == 0); /// /// assert_eq!(even, vec![2]); diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 28db55578c3d..4a70329b64bc 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -125,7 +125,7 @@ #![feature(structural_match)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] -#![feature(maybe_uninit, maybe_uninit_slice, maybe_uninit_array)] +#![feature(maybe_uninit_slice, maybe_uninit_array)] #![feature(external_doc)] #[prelude_import] diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 9fb071d29524..24bee6355a7c 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -63,62 +63,6 @@ pub use crate::intrinsics::transmute; /// The practical use cases for `forget` are rather specialized and mainly come /// up in unsafe or FFI code. /// -/// ## Use case 1 -/// -/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. -/// You must either initialize or `forget` it on every computation path before -/// Rust drops it automatically, like at the end of a scope or after a panic. -/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// # let some_condition = false; -/// unsafe { -/// let mut uninit_vec: Vec = mem::uninitialized(); -/// -/// if some_condition { -/// // Initialize the variable. -/// ptr::write(&mut uninit_vec, Vec::new()); -/// } else { -/// // Forget the uninitialized value so its destructor doesn't run. -/// mem::forget(uninit_vec); -/// } -/// } -/// ``` -/// -/// ## Use case 2 -/// -/// You have duplicated the bytes making up a value, without doing a proper -/// [`Clone`][clone]. You need the value's destructor to run only once, -/// because a double `free` is undefined behavior. -/// -/// An example is a possible implementation of [`mem::swap`][swap]: -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// # #[allow(dead_code)] -/// fn swap(x: &mut T, y: &mut T) { -/// unsafe { -/// // Give ourselves some scratch space to work with -/// let mut t: T = mem::uninitialized(); -/// -/// // Perform the swap, `&mut` pointers never alias -/// ptr::copy_nonoverlapping(&*x, &mut t, 1); -/// ptr::copy_nonoverlapping(&*y, x, 1); -/// ptr::copy_nonoverlapping(&t, y, 1); -/// -/// // y and t now point to the same thing, but we need to completely -/// // forget `t` because we do not want to run the destructor for `T` -/// // on its value, which is still owned somewhere outside this function. -/// mem::forget(t); -/// } -/// } -/// ``` -/// /// [drop]: fn.drop.html /// [uninit]: fn.uninitialized.html /// [clone]: ../clone/trait.Clone.html @@ -465,29 +409,37 @@ pub const fn needs_drop() -> bool { /// Creates a value whose bytes are all zero. /// -/// This has the same effect as allocating space with -/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for -/// FFI sometimes, but should generally be avoided. +/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. +/// It is useful for FFI sometimes, but should generally be avoided. /// /// There is no guarantee that an all-zero byte-pattern represents a valid value of -/// some type `T`. If `T` has a destructor and the value is destroyed (due to -/// a panic or the end of a scope) before being initialized, then the destructor -/// will run on zeroed data, likely leading to [undefined behavior][ub]. +/// some type `T`. For example, the all-zero byte-pattern is not a valid value +/// for reference types (`&T` and `&mut T`). Using `zeroed` on such types +/// causes immediate [undefined behavior][ub] because [the Rust compiler assumes][inv] +/// that there always is a valid value in a variable it considers initialized. /// -/// See also the documentation for [`mem::uninitialized`][uninit], which has -/// many of the same caveats. -/// -/// [uninit]: fn.uninitialized.html +/// [zeroed]: union.MaybeUninit.html#method.zeroed /// [ub]: ../../reference/behavior-considered-undefined.html +/// [inv]: union.MaybeUninit.html#initialization-invariant /// /// # Examples /// +/// Correct usage of this function: initializing an integer with zero. +/// /// ``` /// use std::mem; /// /// let x: i32 = unsafe { mem::zeroed() }; /// assert_eq!(0, x); /// ``` +/// +/// *Incorrect* usage of this function: initializing a reference with zero. +/// +/// ```no_run +/// use std::mem; +/// +/// let _x: &i32 = unsafe { mem::zeroed() }; // Undefined behavior! +/// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn zeroed() -> T { @@ -498,130 +450,23 @@ pub unsafe fn zeroed() -> T { /// Bypasses Rust's normal memory-initialization checks by pretending to /// produce a value of type `T`, while doing nothing at all. /// -/// **This is incredibly dangerous and should not be done lightly. Deeply -/// consider initializing your memory with a default value instead.** +/// **This functon is deprecated.** Use [`MaybeUninit`] instead. /// -/// This is useful for FFI functions and initializing arrays sometimes, -/// but should generally be avoided. +/// The reason for deprecation is that the function basically cannot be used +/// correctly: [the Rust compiler assumes][inv] that values are properly initialized. +/// As a consequence, calling e.g. `mem::uninitialized::()` causes immediate +/// undefined behavior for returning a `bool` that is not definitely either `true` +/// or `false`. Worse, truly uninitialized memory like what gets returned here +/// is special in that the compiler knows that it does not have a fixed value. +/// This makes it undefined behavior to have uninitialized data in a variable even +/// if that variable has an integer type. +/// (Notice that the rules around uninitialized integers are not finalized yet, but +/// until they are, it is advisable to avoid them.) /// -/// # Undefined behavior -/// -/// It is [undefined behavior][ub] to read uninitialized memory, even just an -/// uninitialized boolean. For instance, if you branch on the value of such -/// a boolean, your program may take one, both, or neither of the branches. -/// -/// Writing to the uninitialized value is similarly dangerous. Rust believes the -/// value is initialized, and will therefore try to [`Drop`] the uninitialized -/// value and its fields if you try to overwrite it in a normal manner. The only way -/// to safely initialize an uninitialized value is with [`ptr::write`][write], -/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no]. -/// -/// If the value does implement [`Drop`], it must be initialized before -/// it goes out of scope (and therefore would be dropped). Note that this -/// includes a `panic` occurring and unwinding the stack suddenly. -/// -/// If you partially initialize an array, you may need to use -/// [`ptr::drop_in_place`][drop_in_place] to remove the elements you have fully -/// initialized followed by [`mem::forget`][mem_forget] to prevent drop running -/// on the array. If a partially allocated array is dropped this will lead to -/// undefined behaviour. -/// -/// # Examples -/// -/// Here's how to safely initialize an array of [`Vec`]s. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// // Only declare the array. This safely leaves it -/// // uninitialized in a way that Rust will track for us. -/// // However we can't initialize it element-by-element -/// // safely, and we can't use the `[value; 1000]` -/// // constructor because it only works with `Copy` data. -/// let mut data: [Vec; 1000]; -/// -/// unsafe { -/// // So we need to do this to initialize it. -/// data = mem::uninitialized(); -/// -/// // DANGER ZONE: if anything panics or otherwise -/// // incorrectly reads the array here, we will have -/// // Undefined Behavior. -/// -/// // It's ok to mutably iterate the data, since this -/// // doesn't involve reading it at all. -/// // (ptr and len are statically known for arrays) -/// for elem in &mut data[..] { -/// // *elem = Vec::new() would try to drop the -/// // uninitialized memory at `elem` -- bad! -/// // -/// // Vec::new doesn't allocate or do really -/// // anything. It's only safe to call here -/// // because we know it won't panic. -/// ptr::write(elem, Vec::new()); -/// } -/// -/// // SAFE ZONE: everything is initialized. -/// } -/// -/// println!("{:?}", &data[0]); -/// ``` -/// -/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized` -/// can be. Note that the [`vec!`] macro *does* let you initialize every element with a -/// value that is only [`Clone`], so the following is semantically equivalent and -/// vastly less dangerous, as long as you can live with an extra heap -/// allocation: -/// -/// ``` -/// let data: Vec> = vec![Vec::new(); 1000]; -/// println!("{:?}", &data[0]); -/// ``` -/// -/// This example shows how to handle partially initialized arrays, which could -/// be found in low-level datastructures. -/// -/// ``` -/// use std::mem; -/// use std::ptr; -/// -/// // Count the number of elements we have assigned. -/// let mut data_len: usize = 0; -/// let mut data: [String; 1000]; -/// -/// unsafe { -/// data = mem::uninitialized(); -/// -/// for elem in &mut data[0..500] { -/// ptr::write(elem, String::from("hello")); -/// data_len += 1; -/// } -/// -/// // For each item in the array, drop if we allocated it. -/// for i in &mut data[0..data_len] { -/// ptr::drop_in_place(i); -/// } -/// } -/// // Forget the data. If this is allowed to drop, you may see a crash such as: -/// // 'mem_uninit_test(2457,0x7fffb55dd380) malloc: *** error for object -/// // 0x7ff3b8402920: pointer being freed was not allocated' -/// mem::forget(data); -/// ``` -/// -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// [`vec!`]: ../../std/macro.vec.html -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [ub]: ../../reference/behavior-considered-undefined.html -/// [write]: ../ptr/fn.write.html -/// [drop_in_place]: ../ptr/fn.drop_in_place.html -/// [mem_zeroed]: fn.zeroed.html -/// [mem_forget]: fn.forget.html -/// [copy]: ../intrinsics/fn.copy.html -/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html -/// [`Drop`]: ../ops/trait.Drop.html +/// [`MaybeUninit`]: union.MaybeUninit.html +/// [inv]: union.MaybeUninit.html#initialization-invariant #[inline] -#[rustc_deprecated(since = "2.0.0", reason = "use `mem::MaybeUninit::uninit` instead")] +#[rustc_deprecated(since = "1.40.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn uninitialized() -> T { intrinsics::panic_if_uninhabited::(); @@ -899,7 +744,6 @@ pub fn discriminant(v: &T) -> Discriminant { } } -// FIXME: Reference `MaybeUninit` from these docs, once that is stable. /// A wrapper to inhibit compiler from automatically calling `T`’s destructor. /// /// This wrapper is 0-cost. @@ -908,6 +752,7 @@ pub fn discriminant(v: &T) -> Discriminant { /// As a consequence, it has *no effect* on the assumptions that the compiler makes /// about all values being initialized at their type. In particular, initializing /// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior. +/// If you need to handle uninitialized data, use [`MaybeUninit`] instead. /// /// # Examples /// @@ -942,6 +787,7 @@ pub fn discriminant(v: &T) -> Discriminant { /// ``` /// /// [`mem::zeroed`]: fn.zeroed.html +/// [`MaybeUninit`]: union.MaybeUninit.html #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1042,17 +888,18 @@ impl DerefMut for ManuallyDrop { } } -/// A wrapper to construct uninitialized instances of `T`. +/// A wrapper type to construct uninitialized instances of `T`. +/// +/// # Initialization invariant /// /// The compiler, in general, assumes that variables are properly initialized /// at their respective type. For example, a variable of reference type must /// be aligned and non-NULL. This is an invariant that must *always* be upheld, /// even in unsafe code. As a consequence, zero-initializing a variable of reference -/// type causes instantaneous undefined behavior, no matter whether that reference +/// type causes instantaneous [undefined behavior][ub], no matter whether that reference /// ever gets used to access memory: /// /// ```rust,no_run -/// #![feature(maybe_uninit)] /// use std::mem::{self, MaybeUninit}; /// /// let x: &i32 = unsafe { mem::zeroed() }; // undefined behavior! @@ -1067,7 +914,6 @@ impl DerefMut for ManuallyDrop { /// always be `true` or `false`. Hence, creating an uninitialized `bool` is undefined behavior: /// /// ```rust,no_run -/// #![feature(maybe_uninit)] /// use std::mem::{self, MaybeUninit}; /// /// let b: bool = unsafe { mem::uninitialized() }; // undefined behavior! @@ -1078,10 +924,9 @@ impl DerefMut for ManuallyDrop { /// Moreover, uninitialized memory is special in that the compiler knows that /// it does not have a fixed value. This makes it undefined behavior to have /// uninitialized data in a variable even if that variable has an integer type, -/// which otherwise can hold any bit pattern: +/// which otherwise can hold any *fixed* bit pattern: /// /// ```rust,no_run -/// #![feature(maybe_uninit)] /// use std::mem::{self, MaybeUninit}; /// /// let x: i32 = unsafe { mem::uninitialized() }; // undefined behavior! @@ -1091,37 +936,154 @@ impl DerefMut for ManuallyDrop { /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) /// +/// On top of that, remember that most types have additional invariants beyond merely +/// being considered initialized at the type level. For example, a `1`-initialized [`Vec`] +/// is considered initialized because the only requirement the compiler knows about it +/// is that the data pointer must be non-null. Creating such a `Vec` does not cause +/// *immediate* undefined behavior, but will cause undefined behavior with most +/// safe operations (including dropping it). +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// +/// # Examples +/// /// `MaybeUninit` serves to enable unsafe code to deal with uninitialized data. /// It is a signal to the compiler indicating that the data here might *not* /// be initialized: /// /// ```rust -/// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// // Create an explicitly uninitialized reference. The compiler knows that data inside /// // a `MaybeUninit` may be invalid, and hence this is not UB: /// let mut x = MaybeUninit::<&i32>::uninit(); /// // Set it to a valid value. -/// x.write(&0); +/// unsafe { x.as_mut_ptr().write(&0); } /// // Extract the initialized data -- this is only allowed *after* properly /// // initializing `x`! /// let x = unsafe { x.assume_init() }; /// ``` /// /// The compiler then knows to not make any incorrect assumptions or optimizations on this code. -// -// FIXME before stabilizing, explain how to initialize a struct field-by-field. +/// +/// ## out-pointers +/// +/// You can use `MaybeUninit` to implement "out-pointers": instead of returning data +/// from a function, pass it a pointer to some (uninitialized) memory to put the +/// result into. This can be useful when it is important for the caller to control +/// how the memory the result is stored in gets allocated, and you want to avoid +/// unnecessary moves. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// +/// unsafe fn make_vec(out: *mut Vec) { +/// // `write` does not drop the old contents, which is important. +/// out.write(vec![1, 2, 3]); +/// } +/// +/// let mut v: MaybeUninit> = MaybeUninit::uninit(); +/// unsafe { make_vec(v.as_mut_ptr()); } +/// // Now we know `v` is initialized! This also makes sure the vector gets +/// // properly dropped. +/// let v = unsafe { v.assume_init() }; +/// assert_eq!(&v, &[1, 2, 3]); +/// ``` +/// +/// ## Initializing an array element-by-element +/// +/// `MaybeUninit` can be used to initialize a large array element-by-element: +/// +/// ``` +/// use std::mem::{self, MaybeUninit}; +/// use std::ptr; +/// +/// let data = { +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit>; 1000] = unsafe { +/// MaybeUninit::uninit().assume_init() +/// }; +/// +/// // Dropping a `MaybeUninit` does nothing, so if there is a panic during this loop, +/// // we have a memory leak, but there is no memory safety issue. +/// for elem in &mut data[..] { +/// unsafe { ptr::write(elem.as_mut_ptr(), vec![42]); } +/// } +/// +/// // Everything is initialized. Transmute the array to the +/// // initialized type. +/// unsafe { mem::transmute::<_, [Vec; 1000]>(data) } +/// }; +/// +/// assert_eq!(&data[0], &[42]); +/// ``` +/// +/// You can also work with partially initialized arrays, which could +/// be found in low-level datastructures. +/// +/// ``` +/// use std::mem::MaybeUninit; +/// use std::ptr; +/// +/// // Create an uninitialized array of `MaybeUninit`. The `assume_init` is +/// // safe because the type we are claiming to have initialized here is a +/// // bunch of `MaybeUninit`s, which do not require initialization. +/// let mut data: [MaybeUninit; 1000] = unsafe { MaybeUninit::uninit().assume_init() }; +/// // Count the number of elements we have assigned. +/// let mut data_len: usize = 0; +/// +/// for elem in &mut data[0..500] { +/// unsafe { ptr::write(elem.as_mut_ptr(), String::from("hello")); } +/// data_len += 1; +/// } +/// +/// // For each item in the array, drop if we allocated it. +/// for elem in &mut data[0..data_len] { +/// unsafe { ptr::drop_in_place(elem.as_mut_ptr()); } +/// } +/// ``` +/// +/// ## Initializing a struct field-by-field +/// +/// There is currently no supported way to create a raw pointer or reference +/// to a field of a struct inside `MaybeUninit`. That means it is not possible +/// to create a struct by calling `MaybeUninit::uninit::()` and then writing +/// to its fields. +/// +/// [ub]: ../../reference/behavior-considered-undefined.html +/// +/// # Layout +/// +/// `MaybeUninit` is guaranteed to have the same size and alignment as `T`: +/// +/// ```rust +/// use std::mem::{MaybeUninit, size_of, align_of}; +/// assert_eq!(size_of::>(), size_of::()); +/// assert_eq!(align_of::>(), align_of::()); +/// ``` +/// +/// However remember that a type *containing* a `MaybeUninit` is not necessarily the same +/// layout; Rust does not in general guarantee that the fields of a `Foo` have the same order as +/// a `Foo` even if `T` and `U` have the same size and alignment. Furthermore because any bit +/// value is valid for a `MaybeUninit` the compiler can't apply non-zero/niche-filling +/// optimizations, potentially resulting in a larger size: +/// +/// ```rust +/// # use std::mem::{MaybeUninit, size_of, align_of}; +/// assert_eq!(size_of::>(), 1); +/// assert_eq!(size_of::>>(), 2); +/// ``` #[allow(missing_debug_implementations)] -#[unstable(feature = "maybe_uninit", issue = "53491")] +#[stable(feature = "maybe_uninit", since = "1.36.0")] #[derive(Copy)] -// NOTE: after stabilizing `MaybeUninit`, proceed to deprecate `mem::uninitialized`. pub union MaybeUninit { uninit: (), value: ManuallyDrop, } -#[unstable(feature = "maybe_uninit", issue = "53491")] +#[stable(feature = "maybe_uninit", since = "1.36.0")] impl Clone for MaybeUninit { #[inline(always)] fn clone(&self) -> Self { @@ -1132,10 +1094,13 @@ impl Clone for MaybeUninit { impl MaybeUninit { /// Creates a new `MaybeUninit` initialized with the given value. + /// It is safe to call [`assume_init`] on the return value of this function. /// /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. /// It is your responsibility to make sure `T` gets dropped if it got initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] + /// + /// [`assume_init`]: #method.assume_init + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub const fn new(val: T) -> MaybeUninit { MaybeUninit { value: ManuallyDrop::new(val) } @@ -1145,7 +1110,11 @@ impl MaybeUninit { /// /// Note that dropping a `MaybeUninit` will never call `T`'s drop code. /// It is your responsibility to make sure `T` gets dropped if it got initialized. - #[unstable(feature = "maybe_uninit", issue = "53491")] + /// + /// See the [type-level documentation][type] for some examples. + /// + /// [type]: union.MaybeUninit.html + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub const fn uninit() -> MaybeUninit { MaybeUninit { uninit: () } @@ -1166,7 +1135,6 @@ impl MaybeUninit { /// fields of the struct can hold the bit-pattern 0 as a valid value. /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::<(u8, bool)>::zeroed(); @@ -1178,7 +1146,6 @@ impl MaybeUninit { /// cannot hold 0 as a valid value. /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// enum NotZero { One = 1, Two = 2 }; @@ -1188,7 +1155,7 @@ impl MaybeUninit { /// // Inside a pair, we create a `NotZero` that does not have a valid discriminant. /// // This is undefined behavior. /// ``` - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline] pub fn zeroed() -> MaybeUninit { let mut u = MaybeUninit::::uninit(); @@ -1202,7 +1169,7 @@ impl MaybeUninit { /// without dropping it, so be careful not to use this twice unless you want to /// skip running the destructor. For your convenience, this also returns a mutable /// reference to the (now safely initialized) contents of `self`. - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] #[inline(always)] pub fn write(&mut self, val: T) -> &mut T { unsafe { @@ -1213,13 +1180,14 @@ impl MaybeUninit { /// Gets a pointer to the contained value. Reading from this pointer or turning it /// into a reference is undefined behavior unless the `MaybeUninit` is initialized. + /// Writing to memory that this pointer (non-transitively) points to is undefined behavior + /// (except inside an `UnsafeCell`). /// /// # Examples /// /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); @@ -1232,7 +1200,6 @@ impl MaybeUninit { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::>::uninit(); @@ -1242,7 +1209,7 @@ impl MaybeUninit { /// /// (Notice that the rules around references to uninitialized data are not finalized yet, but /// until they are, it is advisable to avoid them.) - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub fn as_ptr(&self) -> *const T { unsafe { &*self.value as *const T } @@ -1256,7 +1223,6 @@ impl MaybeUninit { /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); @@ -1271,7 +1237,6 @@ impl MaybeUninit { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>::uninit(); @@ -1281,7 +1246,7 @@ impl MaybeUninit { /// /// (Notice that the rules around references to uninitialized data are not finalized yet, but /// until they are, it is advisable to avoid them.) - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub fn as_mut_ptr(&mut self) -> *mut T { unsafe { &mut *self.value as *mut T } @@ -1294,15 +1259,17 @@ impl MaybeUninit { /// # Safety /// /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized - /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// state. Calling this when the content is not yet fully initialized causes immediate undefined + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. + /// + /// [inv]: #initialization-invariant /// /// # Examples /// /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::::uninit(); @@ -1314,14 +1281,13 @@ impl MaybeUninit { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::>::uninit(); /// let x_init = unsafe { x.assume_init() }; /// // `x` had not been initialized yet, so this last line caused undefined behavior. /// ``` - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[stable(feature = "maybe_uninit", since = "1.36.0")] #[inline(always)] pub unsafe fn assume_init(self) -> T { intrinsics::panic_if_uninhabited::(); @@ -1338,13 +1304,15 @@ impl MaybeUninit { /// /// It is up to the caller to guarantee that the `MaybeUninit` really is in an initialized /// state. Calling this when the content is not yet fully initialized causes undefined - /// behavior. + /// behavior. The [type-level documentation][inv] contains more information about + /// this initialization invariant. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using /// multiple copies of the data (by calling `read` multiple times, or first /// calling `read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// + /// [inv]: #initialization-invariant /// [`assume_init`]: #method.assume_init /// /// # Examples @@ -1352,7 +1320,7 @@ impl MaybeUninit { /// Correct usage of this method: /// /// ```rust - /// #![feature(maybe_uninit)] + /// #![feature(maybe_uninit_extra)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::::uninit(); @@ -1373,7 +1341,7 @@ impl MaybeUninit { /// *Incorrect* usage of this method: /// /// ```rust,no_run - /// #![feature(maybe_uninit)] + /// #![feature(maybe_uninit_extra)] /// use std::mem::MaybeUninit; /// /// let mut x = MaybeUninit::>>::uninit(); @@ -1383,7 +1351,7 @@ impl MaybeUninit { /// // We now created two copies of the same vector, leading to a double-free when /// // they both get dropped! /// ``` - #[unstable(feature = "maybe_uninit", issue = "53491")] + #[unstable(feature = "maybe_uninit_extra", issue = "53491")] #[inline(always)] pub unsafe fn read(&self) -> T { intrinsics::panic_if_uninhabited::(); diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 6355bcdcab2f..006b1e143eee 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -155,12 +155,12 @@ pub use crate::intrinsics::write_bytes; /// location first: /// ``` /// use std::ptr; -/// use std::mem; +/// use std::mem::{self, MaybeUninit}; /// /// unsafe fn drop_after_copy(to_drop: *mut T) { -/// let mut copy: T = mem::uninitialized(); -/// ptr::copy(to_drop, &mut copy, 1); -/// drop(copy); +/// let mut copy: MaybeUninit = MaybeUninit::uninit(); +/// ptr::copy(to_drop, copy.as_mut_ptr(), 1); +/// drop(copy.assume_init()); /// } /// /// #[repr(packed, C)] @@ -374,10 +374,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { // #[repr(simd)], even if we don't actually use this struct directly. // // FIXME repr(simd) broken on emscripten and redox - // It's also broken on big-endian powerpc64 and s390x. #42778 - #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox", - target_endian = "big")), - repr(simd))] + #[cfg_attr(not(any(target_os = "emscripten", target_os = "redox")), repr(simd))] struct Block(u64, u64, u64, u64); struct UnalignedBlock(u64, u64, u64, u64); @@ -813,9 +810,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// -/// Memory accessed with `read_volatile` or [`write_volatile`] should not be -/// accessed with non-volatile operations. -/// /// [`write_volatile`]: ./fn.write_volatile.html /// /// # Notes @@ -840,7 +834,7 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// * `src` must be properly aligned. /// -/// Like [`read`], `read_unaligned` creates a bitwise copy of `T`, regardless of +/// Like [`read`], `read_volatile` creates a bitwise copy of `T`, regardless of /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the returned /// value and the value at `*src` can [violate memory safety][read-ownership]. /// However, storing non-[`Copy`] types in volatile memory is almost certainly @@ -884,9 +878,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// to not be elided or reordered by the compiler across other volatile /// operations. /// -/// Memory accessed with [`read_volatile`] or `write_volatile` should not be -/// accessed with non-volatile operations. -/// /// `write_volatile` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care should be taken not to overwrite /// an object that should be dropped. @@ -2973,7 +2964,6 @@ impl NonNull { /// some other means. #[stable(feature = "nonnull", since = "1.25.0")] #[inline] - #[rustc_const_unstable(feature = "const_ptr_nonnull")] pub const fn dangling() -> Self { unsafe { let ptr = mem::align_of::() as *mut T; @@ -3037,7 +3027,6 @@ impl NonNull { /// Cast to a pointer of another type #[stable(feature = "nonnull_cast", since = "1.27.0")] #[inline] - #[rustc_const_unstable(feature = "const_ptr_nonnull")] pub const fn cast(self) -> NonNull { 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 8731f4867535..d06d107d32a4 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -359,6 +359,10 @@ impl [T] { /// The caller must ensure that the slice outlives the pointer this /// function returns, or else it will end up pointing to garbage. /// + /// The caller must also ensure that the memory the pointer (non-transitively) points to + /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer + /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`]. + /// /// Modifying the container referenced by this slice may cause its buffer /// to be reallocated, which would also make any pointers to it invalid. /// @@ -374,6 +378,8 @@ impl [T] { /// } /// } /// ``` + /// + /// [`as_mut_ptr`]: #method.as_mut_ptr #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub const fn as_ptr(&self) -> *const T { @@ -3541,6 +3547,11 @@ impl<'a, T, P> Iterator for Split<'a, T, P> where P: FnMut(&T) -> bool { (1, Some(self.v.len() + 1)) } } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3639,6 +3650,11 @@ impl<'a, T, P> Iterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool { (1, Some(self.v.len() + 1)) } } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -3704,6 +3720,11 @@ impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "slice_rsplit", since = "1.27.0")] @@ -3768,6 +3789,11 @@ impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "slice_rsplit", since = "1.27.0")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 45421848cec5..0e8a2da3c110 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1333,6 +1333,11 @@ impl<'a> Iterator for Lines<'a> { fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1379,6 +1384,11 @@ impl<'a> Iterator for LinesAny<'a> { fn size_hint(&self) -> (usize, Option) { self.0.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -2188,7 +2198,11 @@ impl str { /// [`u8`]. This pointer will be pointing to the first byte of the string /// slice. /// + /// The caller must ensure that the returned pointer is never written to. + /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`]. + /// /// [`u8`]: primitive.u8.html + /// [`as_mut_ptr`]: #method.as_mut_ptr /// /// # Examples /// @@ -4217,6 +4231,11 @@ impl<'a> Iterator for SplitWhitespace<'a> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "split_whitespace", since = "1.1.0")] @@ -4243,6 +4262,11 @@ impl<'a> Iterator for SplitAsciiWhitespace<'a> { fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs index b4e912498320..a6d611d2e93c 100644 --- a/src/libcore/task/wake.rs +++ b/src/libcore/task/wake.rs @@ -10,6 +10,8 @@ use crate::marker::{PhantomData, Unpin}; /// /// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that /// customizes the behavior of the `RawWaker`. +/// +/// [`Waker`]: struct.Waker.html #[derive(PartialEq, Debug)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct RawWaker { @@ -55,6 +57,8 @@ impl RawWaker { /// pointer of a properly constructed [`RawWaker`] object from inside the /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. +/// +/// [`RawWaker`]: struct.RawWaker.html #[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { @@ -65,6 +69,9 @@ pub struct RawWakerVTable { /// required for this additional instance of a [`RawWaker`] and associated /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup /// of the same task that would have been awoken by the original [`RawWaker`]. + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html clone: unsafe fn(*const ()) -> RawWaker, /// This function will be called when `wake` is called on the [`Waker`]. @@ -73,6 +80,9 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html wake: unsafe fn(*const ()), /// This function will be called when `wake_by_ref` is called on the [`Waker`]. @@ -80,6 +90,9 @@ pub struct RawWakerVTable { /// /// This function is similar to `wake`, but must not consume the provided data /// pointer. + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html wake_by_ref: unsafe fn(*const ()), /// This function gets called when a [`RawWaker`] gets dropped. @@ -87,6 +100,8 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. + /// + /// [`RawWaker`]: struct.RawWaker.html drop: unsafe fn(*const ()), } @@ -128,6 +143,9 @@ impl RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. + /// + /// [`Waker`]: struct.Waker.html + /// [`RawWaker`]: struct.RawWaker.html #[rustc_promotable] #[cfg_attr(stage0, unstable(feature = "futures_api_const_fn_ptr", issue = "50547"))] #[cfg_attr(not(stage0), stable(feature = "futures_api", since = "1.36.0"))] @@ -201,6 +219,8 @@ impl fmt::Debug for Context<'_> { /// executor-specific wakeup behavior. /// /// Implements [`Clone`], [`Send`], and [`Sync`]. +/// +/// [`RawWaker`]: struct.RawWaker.html #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { @@ -266,6 +286,9 @@ impl Waker { /// The behavior of the returned `Waker` is undefined if the contract defined /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. + /// + /// [`RawWaker`]: struct.RawWaker.html + /// [`RawWakerVTable`]: struct.RawWakerVTable.html #[inline] #[stable(feature = "futures_api", since = "1.36.0")] pub unsafe fn from_raw(waker: RawWaker) -> Waker { diff --git a/src/libcore/tests/alloc.rs b/src/libcore/tests/alloc.rs new file mode 100644 index 000000000000..63537ba23d84 --- /dev/null +++ b/src/libcore/tests/alloc.rs @@ -0,0 +1,10 @@ +use core::alloc::Layout; + +#[test] +fn const_unchecked_layout() { + const SIZE: usize = 0x2000; + const ALIGN: usize = 0x1000; + const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) }; + assert_eq!(LAYOUT.size(), SIZE); + assert_eq!(LAYOUT.align(), ALIGN); +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 025f7fb5cc6c..c617596aba80 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -31,10 +31,12 @@ #![feature(slice_partition_dedup)] #![feature(copy_within)] #![feature(int_error_matching)] -#![deny(rust_2018_idioms)] +#![feature(const_fn)] +#![warn(rust_2018_idioms)] extern crate test; +mod alloc; mod any; mod array; mod ascii; diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 2468de99d60a..4d50e80d4cf6 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -36,7 +36,7 @@ byteorder = { version = "1.1", features = ["i128"]} chalk-engine = { version = "0.9.0", default-features=false } rustc_fs_util = { path = "../librustc_fs_util" } smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } -measureme = "0.2.1" +measureme = "0.3" # Note that these dependencies are a lie, they're just here to get linkage to # work. diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 2592af7d4ad5..2e54165be1f1 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -166,47 +166,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(expr.hir_id.local_id, &[blk_exit]) } - hir::ExprKind::If(ref cond, ref then, None) => { - // - // [pred] - // | - // v 1 - // [cond] - // | - // / \ - // / \ - // v 2 * - // [then] | - // | | - // v 3 v 4 - // [..expr..] - // - let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.expr(&then, cond_exit); // 2 - self.add_ast_node(expr.hir_id.local_id, &[cond_exit, then_exit]) // 3,4 - } - - hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => { - // - // [pred] - // | - // v 1 - // [cond] - // | - // / \ - // / \ - // v 2 v 3 - // [then][otherwise] - // | | - // v 4 v 5 - // [..expr..] - // - let cond_exit = self.expr(&cond, pred); // 1 - let then_exit = self.expr(&then, cond_exit); // 2 - let else_exit = self.expr(&otherwise, cond_exit); // 3 - self.add_ast_node(expr.hir_id.local_id, &[then_exit, else_exit]) // 4, 5 - } - hir::ExprKind::While(ref cond, ref body, _) => { // // [pred] diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 4c527f80d0f5..b199eee6dad8 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -12,6 +12,7 @@ use crate::hir; use crate::hir::def_id::DefId; use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; use std::fmt::{self, Display}; +use syntax::symbol::sym; use syntax_pos::Span; #[derive(Copy, Clone, PartialEq)] @@ -95,18 +96,18 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { fn check_attributes(&self, item: &hir::Item, target: Target) { if target == Target::Fn || target == Target::Const { self.tcx.codegen_fn_attrs(self.tcx.hir().local_def_id_from_hir_id(item.hir_id)); - } else if let Some(a) = item.attrs.iter().find(|a| a.check_name("target_feature")) { + } else if let Some(a) = item.attrs.iter().find(|a| a.check_name(sym::target_feature)) { self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function") .span_label(item.span, "not a function") .emit(); } for attr in &item.attrs { - if attr.check_name("inline") { + if attr.check_name(sym::inline) { self.check_inline(attr, &item.span, target) - } else if attr.check_name("non_exhaustive") { + } else if attr.check_name(sym::non_exhaustive) { self.check_non_exhaustive(attr, item, target) - } else if attr.check_name("marker") { + } else if attr.check_name(sym::marker) { self.check_marker(attr, item, target) } } @@ -166,7 +167,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { // ``` let hints: Vec<_> = item.attrs .iter() - .filter(|attr| attr.check_name("repr")) + .filter(|attr| attr.check_name(sym::repr)) .filter_map(|attr| attr.meta_item_list()) .flatten() .collect(); @@ -177,9 +178,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { let mut is_transparent = false; for hint in &hints { - let (article, allowed_targets) = match hint.name_or_empty().get() { - name @ "C" | name @ "align" => { - is_c |= name == "C"; + let (article, allowed_targets) = match hint.name_or_empty() { + name @ sym::C | name @ sym::align => { + is_c |= name == sym::C; if target != Target::Struct && target != Target::Union && target != Target::Enum { @@ -188,7 +189,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { continue } } - "packed" => { + sym::packed => { if target != Target::Struct && target != Target::Union { ("a", "struct or union") @@ -196,7 +197,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { continue } } - "simd" => { + sym::simd => { is_simd = true; if target != Target::Struct { ("a", "struct") @@ -204,7 +205,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { continue } } - "transparent" => { + sym::transparent => { is_transparent = true; if target != Target::Struct { ("a", "struct") @@ -212,9 +213,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { continue } } - "i8" | "u8" | "i16" | "u16" | - "i32" | "u32" | "i64" | "u64" | - "isize" | "usize" => { + sym::i8 | sym::u8 | sym::i16 | sym::u16 | + sym::i32 | sym::u32 | sym::i64 | sym::u64 | + sym::isize | sym::usize => { int_reprs += 1; if target != Target::Enum { ("an", "enum") @@ -268,10 +269,10 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { // When checking statements ignore expressions, they will be checked later if let hir::StmtKind::Local(ref l) = stmt.node { for attr in l.attrs.iter() { - if attr.check_name("inline") { + if attr.check_name(sym::inline) { self.check_inline(attr, &stmt.span, Target::Statement); } - if attr.check_name("repr") { + if attr.check_name(sym::repr) { self.emit_repr_error( attr.span, stmt.span, @@ -289,10 +290,10 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { _ => Target::Expression, }; for attr in expr.attrs.iter() { - if attr.check_name("inline") { + if attr.check_name(sym::inline) { self.check_inline(attr, &expr.span, target); } - if attr.check_name("repr") { + if attr.check_name(sym::repr) { self.emit_repr_error( attr.span, expr.span, @@ -305,7 +306,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { fn check_used(&self, item: &hir::Item, target: Target) { for attr in &item.attrs { - if attr.check_name("used") && target != Target::Static { + if attr.check_name(sym::used) && target != Target::Static { self.tcx.sess .span_err(attr.span, "attribute must be applied to a `static` variable"); } diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index b268a1a494d1..0c4f5fb3fc16 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -96,34 +96,20 @@ impl fmt::Display for CrateNum { impl serialize::UseSpecializedEncodable for CrateNum {} impl serialize::UseSpecializedDecodable for CrateNum {} -/// A DefIndex is an index into the hir-map for a crate, identifying a -/// particular definition. It should really be considered an interned -/// shorthand for a particular DefPath. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -pub struct DefIndex(u32); +newtype_index! { + /// A DefIndex is an index into the hir-map for a crate, identifying a + /// particular definition. It should really be considered an interned + /// shorthand for a particular DefPath. + pub struct DefIndex { + DEBUG_FORMAT = "DefIndex({})", -/// The crate root is always assigned index 0 by the AST Map code, -/// thanks to `NodeCollector::new`. -pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0); - -impl fmt::Debug for DefIndex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DefIndex({})", self.as_array_index()) + /// The crate root is always assigned index 0 by the AST Map code, + /// thanks to `NodeCollector::new`. + const CRATE_DEF_INDEX = 0, } } impl DefIndex { - /// Converts this DefIndex into a zero-based array index. - #[inline] - pub fn as_array_index(&self) -> usize { - self.0 as usize - } - - #[inline] - pub fn from_array_index(i: usize) -> DefIndex { - DefIndex(i as u32) - } - // Proc macros from a proc-macro crate have a kind of virtual DefIndex. This // function maps the index of the macro within the crate (which is also the // index of the macro in the CrateMetadata::proc_macros array) to the @@ -132,7 +118,7 @@ impl DefIndex { // DefIndex for proc macros start from FIRST_FREE_DEF_INDEX, // because the first FIRST_FREE_DEF_INDEX indexes are reserved // for internal use. - let def_index = DefIndex::from_array_index( + let def_index = DefIndex::from( proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX) .expect("integer overflow adding `proc_macro_index`")); assert!(def_index != CRATE_DEF_INDEX); @@ -141,19 +127,11 @@ impl DefIndex { // This function is the reverse of from_proc_macro_index() above. pub fn to_proc_macro_index(self: DefIndex) -> usize { - self.as_array_index().checked_sub(FIRST_FREE_DEF_INDEX) + self.index().checked_sub(FIRST_FREE_DEF_INDEX) .unwrap_or_else(|| { bug!("using local index {:?} as proc-macro index", self) }) } - - pub fn from_raw_u32(x: u32) -> DefIndex { - DefIndex(x) - } - - pub fn as_raw_u32(&self) -> u32 { - self.0 - } } impl serialize::UseSpecializedEncodable for DefIndex {} @@ -169,7 +147,7 @@ pub struct DefId { impl fmt::Debug for DefId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "DefId({}:{}", self.krate, self.index.as_array_index())?; + write!(f, "DefId({}:{}", self.krate, self.index.index())?; ty::tls::with_opt(|opt_tcx| { if let Some(tcx) = opt_tcx { diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 0c73d97394fd..38d6d710868c 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1032,11 +1032,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprKind::DropTemps(ref subexpression) => { visitor.visit_expr(subexpression); } - ExprKind::If(ref head_expression, ref if_block, ref optional_else) => { - visitor.visit_expr(head_expression); - visitor.visit_expr(if_block); - walk_list!(visitor, visit_expr, optional_else); - } ExprKind::While(ref subexpression, ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_expr(subexpression); diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4d5707560b04..3ec4d4e8cc8f 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -62,8 +62,9 @@ use syntax::ext::hygiene::Mark; use syntax::print::pprust; use syntax::ptr::P; use syntax::source_map::{respan, CompilerDesugaringKind, Spanned}; +use syntax::source_map::CompilerDesugaringKind::IfTemporary; use syntax::std_inject; -use syntax::symbol::{keywords, Symbol}; +use syntax::symbol::{keywords, Symbol, sym}; use syntax::tokenstream::{TokenStream, TokenTree}; use syntax::parse::token::Token; use syntax::visit::{self, Visitor}; @@ -72,7 +73,7 @@ use syntax_pos::Span; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; pub struct LoweringContext<'a> { - crate_root: Option<&'static str>, + crate_root: Option, /// Used to assign ids to HIR nodes that do not directly correspond to an AST node. sess: &'a Session, @@ -96,6 +97,10 @@ pub struct LoweringContext<'a> { is_generator: bool, is_async_body: bool, + /// Used to get the current `fn`'s def span to point to when using `await` + /// outside of an `async fn`. + current_item: Option, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -163,8 +168,8 @@ pub trait Resolver { fn resolve_str_path( &mut self, span: Span, - crate_root: Option<&str>, - components: &[&str], + crate_root: Option, + components: &[Symbol], is_value: bool, ) -> hir::Path; } @@ -227,7 +232,7 @@ pub fn lower_crate( dep_graph.assert_ignored(); LoweringContext { - crate_root: std_inject::injected_crate_name(), + crate_root: std_inject::injected_crate_name().map(Symbol::intern), sess, cstore, resolver, @@ -249,6 +254,7 @@ pub fn lower_crate( node_id_to_hir_id: IndexVec::new(), is_generator: false, is_async_body: false, + current_item: None, is_in_trait_impl: false, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, @@ -849,10 +855,6 @@ impl<'a> LoweringContext<'a> { self.sess.diagnostic() } - fn str_to_ident(&self, s: &'static str) -> Ident { - Ident::with_empty_ctxt(Symbol::gensym(s)) - } - fn with_anonymous_lifetime_mode( &mut self, anonymous_lifetime_mode: AnonymousLifetimeMode, @@ -1148,7 +1150,7 @@ impl<'a> LoweringContext<'a> { ].into()), ); let gen_future = self.expr_std_path( - unstable_span, &["future", "from_generator"], None, ThinVec::new()); + unstable_span, &[sym::future, sym::from_generator], None, ThinVec::new()); hir::ExprKind::Call(P(gen_future), hir_vec![generator]) } @@ -2212,7 +2214,7 @@ impl<'a> LoweringContext<'a> { bindings: hir_vec![ hir::TypeBinding { hir_id: this.next_id(), - ident: Ident::from_str(FN_OUTPUT_NAME), + ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME), ty: output .as_ref() .map(|ty| this.lower_ty(&ty, ImplTraitContext::disallowed())) @@ -2537,7 +2539,7 @@ impl<'a> LoweringContext<'a> { let future_params = P(hir::GenericArgs { args: hir_vec![], bindings: hir_vec![hir::TypeBinding { - ident: Ident::from_str(FN_OUTPUT_NAME), + ident: Ident::with_empty_ctxt(FN_OUTPUT_NAME), ty: output_ty, hir_id: self.next_id(), span, @@ -2547,7 +2549,7 @@ impl<'a> LoweringContext<'a> { // ::std::future::Future let future_path = - self.std_path(span, &["future", "Future"], Some(future_params), false); + self.std_path(span, &[sym::future, sym::Future], Some(future_params), false); hir::GenericBound::Trait( hir::PolyTraitRef { @@ -2726,7 +2728,7 @@ impl<'a> LoweringContext<'a> { self.lower_ty(x, ImplTraitContext::disallowed()) }), synthetic: param.attrs.iter() - .filter(|attr| attr.check_name("rustc_synthetic")) + .filter(|attr| attr.check_name(sym::rustc_synthetic)) .map(|_| hir::SyntheticTyParamKind::ImplTrait) .next(), }; @@ -2744,7 +2746,7 @@ impl<'a> LoweringContext<'a> { hir_id: self.lower_node_id(param.id), name, span: param.ident.span, - pure_wrt_drop: attr::contains_name(¶m.attrs, "may_dangle"), + pure_wrt_drop: attr::contains_name(¶m.attrs, sym::may_dangle), attrs: self.lower_attrs(¶m.attrs), bounds, kind, @@ -3115,6 +3117,7 @@ impl<'a> LoweringContext<'a> { ItemKind::Fn(ref decl, ref header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); self.with_new_scopes(|this| { + this.current_item = Some(ident.span); let mut lower_fn = |decl: &FnDecl| { // Note: we don't need to change the return type from `T` to // `impl Future` here because lower_body @@ -3653,6 +3656,7 @@ impl<'a> LoweringContext<'a> { } else { lower_method(sig) }; + self.current_item = Some(i.span); (generics, hir::ImplItemKind::Method(sig, body_id)) } @@ -3772,8 +3776,8 @@ impl<'a> LoweringContext<'a> { let mut vis = self.lower_visibility(&i.vis, None); let attrs = self.lower_attrs(&i.attrs); if let ItemKind::MacroDef(ref def) = i.node { - if !def.legacy || attr::contains_name(&i.attrs, "macro_export") || - attr::contains_name(&i.attrs, "rustc_doc_only_macro") { + if !def.legacy || attr::contains_name(&i.attrs, sym::macro_export) || + attr::contains_name(&i.attrs, sym::rustc_doc_only_macro) { let body = self.lower_token_stream(def.stream()); let hir_id = self.lower_node_id(i.id); self.exported_macros.push(hir::MacroDef { @@ -4099,7 +4103,7 @@ impl<'a> LoweringContext<'a> { let ohs = P(self.lower_expr(ohs)); hir::ExprKind::Unary(op, ohs) } - ExprKind::Lit(ref l) => hir::ExprKind::Lit((*l).clone()), + ExprKind::Lit(ref l) => hir::ExprKind::Lit(respan(l.span, l.node.clone())), ExprKind::Cast(ref expr, ref ty) => { let expr = P(self.lower_expr(expr)); hir::ExprKind::Cast(expr, self.lower_ty(ty, ImplTraitContext::disallowed())) @@ -4115,31 +4119,46 @@ impl<'a> LoweringContext<'a> { } // More complicated than you might expect because the else branch // might be `if let`. - ExprKind::If(ref cond, ref blk, ref else_opt) => { - let else_opt = else_opt.as_ref().map(|els| { - match els.node { + ExprKind::If(ref cond, ref then, ref else_opt) => { + // `true => then`: + let then_pat = self.pat_bool(e.span, true); + let then_blk = self.lower_block(then, false); + let then_expr = self.expr_block(then_blk, ThinVec::new()); + let then_arm = self.arm(hir_vec![then_pat], P(then_expr)); + + // `_ => else_block` where `else_block` is `{}` if there's `None`: + let else_pat = self.pat_wild(e.span); + let else_expr = match else_opt { + None => self.expr_block_empty(e.span), + Some(els) => match els.node { ExprKind::IfLet(..) => { // Wrap the `if let` expr in a block. - let span = els.span; - let els = P(self.lower_expr(els)); - let blk = P(hir::Block { - stmts: hir_vec![], - expr: Some(els), - hir_id: self.next_id(), - rules: hir::DefaultBlock, - span, - targeted_by_break: false, - }); - P(self.expr_block(blk, ThinVec::new())) + let els = self.lower_expr(els); + let blk = self.block_all(els.span, hir_vec![], Some(P(els))); + self.expr_block(P(blk), ThinVec::new()) } - _ => P(self.lower_expr(els)), + _ => self.lower_expr(els), } - }); + }; + let else_arm = self.arm(hir_vec![else_pat], P(else_expr)); - let then_blk = self.lower_block(blk, false); - let then_expr = self.expr_block(then_blk, ThinVec::new()); + // Lower condition: + let span_block = self + .sess + .source_map() + .mark_span_with_reason(IfTemporary, cond.span, None); + let cond = self.lower_expr(cond); + // Wrap in a construct equivalent to `{ let _t = $cond; _t }` to preserve drop + // semantics since `if cond { ... }` don't let temporaries live outside of `cond`. + let cond = self.expr_drop_temps(span_block, P(cond), ThinVec::new()); - hir::ExprKind::If(P(self.lower_expr(cond)), P(then_expr), else_opt) + hir::ExprKind::Match( + P(cond), + vec![then_arm, else_arm].into(), + hir::MatchSource::IfDesugar { + contains_else_clause: else_opt.is_some() + }, + ) } ExprKind::While(ref cond, ref body, opt_label) => self.with_loop_scope(e.id, |this| { hir::ExprKind::While( @@ -4178,7 +4197,7 @@ impl<'a> LoweringContext<'a> { |x: P| x.into_inner(), ); block.expr = Some(this.wrap_in_try_constructor( - "from_ok", tail, unstable_span)); + sym::from_ok, tail, unstable_span)); hir::ExprKind::Block(P(block), None) }) } @@ -4254,6 +4273,7 @@ impl<'a> LoweringContext<'a> { let fn_decl = self.lower_fn_decl(decl, None, false, None); self.with_new_scopes(|this| { + this.current_item = Some(fn_decl_span); let mut is_generator = false; let body_id = this.lower_body(Some(decl), |this| { let e = this.lower_expr(body); @@ -4320,7 +4340,7 @@ impl<'a> LoweringContext<'a> { self.expr_call_std_assoc_fn( id, e.span, - &["ops", "RangeInclusive"], + &[sym::ops, sym::RangeInclusive], "new", hir_vec![e1, e2], ) @@ -4329,11 +4349,11 @@ impl<'a> LoweringContext<'a> { use syntax::ast::RangeLimits::*; let path = match (e1, e2, lims) { - (&None, &None, HalfOpen) => "RangeFull", - (&Some(..), &None, HalfOpen) => "RangeFrom", - (&None, &Some(..), HalfOpen) => "RangeTo", - (&Some(..), &Some(..), HalfOpen) => "Range", - (&None, &Some(..), Closed) => "RangeToInclusive", + (&None, &None, HalfOpen) => sym::RangeFull, + (&Some(..), &None, HalfOpen) => sym::RangeFrom, + (&None, &Some(..), HalfOpen) => sym::RangeTo, + (&Some(..), &Some(..), HalfOpen) => sym::Range, + (&None, &Some(..), Closed) => sym::RangeToInclusive, (&Some(..), &Some(..), Closed) => unreachable!(), (_, &None, Closed) => self.diagnostic() .span_fatal(e.span, "inclusive range with no end") @@ -4351,7 +4371,7 @@ impl<'a> LoweringContext<'a> { .collect::>(); let is_unit = fields.is_empty(); - let struct_path = ["ops", path]; + let struct_path = [sym::ops, path]; let struct_path = self.std_path(e.span, &struct_path, None, is_unit); let struct_path = hir::QPath::Resolved(None, P(struct_path)); @@ -4486,16 +4506,16 @@ impl<'a> LoweringContext<'a> { arms.push(self.arm(pats, body_expr)); } - // _ => [|()] + // _ => [|{}] { let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p); let wildcard_pattern = self.pat_wild(e.span); let body = if let Some(else_expr) = wildcard_arm { - P(self.lower_expr(else_expr)) + self.lower_expr(else_expr) } else { - P(self.expr_tuple(e.span, hir_vec![])) + self.expr_block_empty(e.span) }; - arms.push(self.arm(hir_vec![wildcard_pattern], body)); + arms.push(self.arm(hir_vec![wildcard_pattern], P(body))); } let contains_else_clause = else_opt.is_some(); @@ -4597,18 +4617,18 @@ impl<'a> LoweringContext<'a> { ); head.span = desugared_span; - let iter = self.str_to_ident("iter"); + let iter = Ident::with_empty_ctxt(sym::iter); - let next_ident = self.str_to_ident("__next"); + let next_ident = Ident::with_empty_ctxt(sym::__next); let (next_pat, next_pat_hid) = self.pat_ident_binding_mode( desugared_span, next_ident, hir::BindingAnnotation::Mutable, ); - // `::std::option::Option::Some(val) => next = val` + // `::std::option::Option::Some(val) => __next = val` let pat_arm = { - let val_ident = self.str_to_ident("val"); + let val_ident = Ident::with_empty_ctxt(sym::val); let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident); let val_expr = P(self.expr_ident(pat.span, val_ident, val_pat_hid)); let next_expr = P(self.expr_ident(pat.span, next_ident, next_pat_hid)); @@ -4640,7 +4660,7 @@ impl<'a> LoweringContext<'a> { let match_expr = { let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid)); let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter); - let next_path = &["iter", "Iterator", "next"]; + let next_path = &[sym::iter, sym::Iterator, sym::next]; let next_expr = P(self.expr_call_std_path( head_sp, next_path, @@ -4658,11 +4678,7 @@ impl<'a> LoweringContext<'a> { ThinVec::new(), )) }; - let match_stmt = hir::Stmt { - hir_id: self.next_id(), - node: hir::StmtKind::Expr(match_expr), - span: head_sp, - }; + let match_stmt = self.stmt(head_sp, hir::StmtKind::Expr(match_expr)); let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat_hid)); @@ -4685,11 +4701,7 @@ impl<'a> LoweringContext<'a> { let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false)); let body_expr = P(self.expr_block(body_block, ThinVec::new())); - let body_stmt = hir::Stmt { - hir_id: self.next_id(), - node: hir::StmtKind::Expr(body_expr), - span: body.span, - }; + let body_stmt = self.stmt(body.span, hir::StmtKind::Expr(body_expr)); let loop_block = P(self.block_all( e.span, @@ -4715,7 +4727,8 @@ impl<'a> LoweringContext<'a> { // `match ::std::iter::IntoIterator::into_iter() { ... }` let into_iter_expr = { - let into_iter_path = &["iter", "IntoIterator", "into_iter"]; + let into_iter_path = + &[sym::iter, sym::IntoIterator, sym::into_iter]; P(self.expr_call_std_path( head_sp, into_iter_path, @@ -4754,17 +4767,13 @@ impl<'a> LoweringContext<'a> { let unstable_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::QuestionMark, e.span, - Some(vec![ - Symbol::intern("try_trait") - ].into()), + Some(vec![sym::try_trait].into()), ); let try_span = self.sess.source_map().end_point(e.span); let try_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::QuestionMark, try_span, - Some(vec![ - Symbol::intern("try_trait") - ].into()), + Some(vec![sym::try_trait].into()), ); // `Try::into_result()` @@ -4772,7 +4781,7 @@ impl<'a> LoweringContext<'a> { // expand let sub_expr = self.lower_expr(sub_expr); - let path = &["ops", "Try", "into_result"]; + let path = &[sym::ops, sym::Try, sym::into_result]; P(self.expr_call_std_path( unstable_span, path, @@ -4784,8 +4793,9 @@ impl<'a> LoweringContext<'a> { let attr = { // `allow(unreachable_code)` let allow = { - let allow_ident = Ident::from_str("allow").with_span_pos(e.span); - let uc_ident = Ident::from_str("unreachable_code").with_span_pos(e.span); + let allow_ident = Ident::with_empty_ctxt(sym::allow).with_span_pos(e.span); + let uc_ident = Ident::with_empty_ctxt(sym::unreachable_code) + .with_span_pos(e.span); let uc_nested = attr::mk_nested_word_item(uc_ident); attr::mk_list_item(e.span, allow_ident, vec![uc_nested]) }; @@ -4795,7 +4805,7 @@ impl<'a> LoweringContext<'a> { // `Ok(val) => #[allow(unreachable_code)] val,` let ok_arm = { - let val_ident = self.str_to_ident("val"); + let val_ident = Ident::with_empty_ctxt(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(e.span, val_ident); let val_expr = P(self.expr_ident_with_attrs( e.span, @@ -4811,15 +4821,15 @@ impl<'a> LoweringContext<'a> { // `Err(err) => #[allow(unreachable_code)] // return Try::from_error(From::from(err)),` let err_arm = { - let err_ident = self.str_to_ident("err"); + let err_ident = Ident::with_empty_ctxt(sym::err); let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); let from_expr = { - let from_path = &["convert", "From", "from"]; + let from_path = &[sym::convert, sym::From, sym::from]; let err_expr = self.expr_ident(try_span, err_ident, err_local_nid); self.expr_call_std_path(try_span, from_path, hir_vec![err_expr]) }; let from_err_expr = - self.wrap_in_try_constructor("from_error", from_expr, unstable_span); + self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span); let thin_attrs = ThinVec::from(attrs); let catch_scope = self.catch_scopes.last().map(|x| *x); let ret_expr = if let Some(catch_node) = catch_scope { @@ -4869,12 +4879,7 @@ impl<'a> LoweringContext<'a> { .into_iter() .map(|item_id| { let item_id = hir::ItemId { id: self.lower_node_id(item_id) }; - - hir::Stmt { - hir_id: self.next_id(), - node: hir::StmtKind::Item(item_id), - span: s.span, - } + self.stmt(s.span, hir::StmtKind::Item(item_id)) }) .collect(); ids.push({ @@ -5054,7 +5059,7 @@ impl<'a> LoweringContext<'a> { fn expr_call_std_path( &mut self, span: Span, - path_components: &[&str], + path_components: &[Symbol], args: hir::HirVec, ) -> hir::Expr { let path = P(self.expr_std_path(span, path_components, None, ThinVec::new())); @@ -5074,7 +5079,7 @@ impl<'a> LoweringContext<'a> { &mut self, ty_path_id: hir::HirId, span: Span, - ty_path_components: &[&str], + ty_path_components: &[Symbol], assoc_fn_name: &str, args: hir::HirVec, ) -> hir::ExprKind { @@ -5116,7 +5121,7 @@ impl<'a> LoweringContext<'a> { fn expr_std_path( &mut self, span: Span, - components: &[&str], + components: &[Symbol], params: Option>, attrs: ThinVec, ) -> hir::Expr { @@ -5174,28 +5179,32 @@ impl<'a> LoweringContext<'a> { } } + fn stmt(&mut self, span: Span, node: hir::StmtKind) -> hir::Stmt { + hir::Stmt { span, node, hir_id: self.next_id() } + } + fn stmt_let_pat( &mut self, - sp: Span, - ex: Option>, + span: Span, + init: Option>, pat: P, source: hir::LocalSource, ) -> hir::Stmt { let local = hir::Local { pat, ty: None, - init: ex, + init, hir_id: self.next_id(), - span: sp, - attrs: ThinVec::new(), + span, source, + attrs: ThinVec::new() }; + self.stmt(span, hir::StmtKind::Local(P(local))) + } - hir::Stmt { - hir_id: self.next_id(), - node: hir::StmtKind::Local(P(local)), - span: sp - } + fn expr_block_empty(&mut self, span: Span) -> hir::Expr { + let blk = self.block_all(span, hir_vec![], None); + self.expr_block(P(blk), ThinVec::new()) } fn block_expr(&mut self, expr: P) -> hir::Block { @@ -5235,26 +5244,33 @@ impl<'a> LoweringContext<'a> { ) } + /// Constructs a `true` or `false` literal pattern. + fn pat_bool(&mut self, span: Span, val: bool) -> P { + let lit = Spanned { span, node: LitKind::Bool(val) }; + let expr = self.expr(span, hir::ExprKind::Lit(lit), ThinVec::new()); + self.pat(span, hir::PatKind::Lit(P(expr))) + } + fn pat_ok(&mut self, span: Span, pat: P) -> P { - self.pat_std_enum(span, &["result", "Result", "Ok"], hir_vec![pat]) + self.pat_std_enum(span, &[sym::result, sym::Result, sym::Ok], hir_vec![pat]) } fn pat_err(&mut self, span: Span, pat: P) -> P { - self.pat_std_enum(span, &["result", "Result", "Err"], hir_vec![pat]) + self.pat_std_enum(span, &[sym::result, sym::Result, sym::Err], hir_vec![pat]) } fn pat_some(&mut self, span: Span, pat: P) -> P { - self.pat_std_enum(span, &["option", "Option", "Some"], hir_vec![pat]) + self.pat_std_enum(span, &[sym::option, sym::Option, sym::Some], hir_vec![pat]) } fn pat_none(&mut self, span: Span) -> P { - self.pat_std_enum(span, &["option", "Option", "None"], hir_vec![]) + self.pat_std_enum(span, &[sym::option, sym::Option, sym::None], hir_vec![]) } fn pat_std_enum( &mut self, span: Span, - components: &[&str], + components: &[Symbol], subpats: hir::HirVec>, ) -> P { let path = self.std_path(span, components, None, true); @@ -5307,7 +5323,7 @@ impl<'a> LoweringContext<'a> { fn std_path( &mut self, span: Span, - components: &[&str], + components: &[Symbol], params: Option>, is_value: bool, ) -> hir::Path { @@ -5506,11 +5522,11 @@ impl<'a> LoweringContext<'a> { fn wrap_in_try_constructor( &mut self, - method: &'static str, + method: Symbol, e: hir::Expr, unstable_span: Span, ) -> P { - let path = &["ops", "Try", method]; + let path = &[sym::ops, sym::Try, method]; let from_err = P(self.expr_std_path(unstable_span, path, None, ThinVec::new())); P(self.expr_call(e.span, from_err, hir_vec![e])) @@ -5529,20 +5545,25 @@ impl<'a> LoweringContext<'a> { // match ::std::future::poll_with_tls_context(unsafe { // ::std::pin::Pin::new_unchecked(&mut pinned) // }) { - // ::std::task::Poll::Ready(x) => break x, + // ::std::task::Poll::Ready(result) => break result, // ::std::task::Poll::Pending => {}, // } // yield (); // } // } if !self.is_async_body { - span_err!( + let mut err = struct_span_err!( self.sess, await_span, E0728, "`await` is only allowed inside `async` functions and blocks" ); - self.sess.abort_if_errors(); + err.span_label(await_span, "only allowed inside `async` functions and blocks"); + if let Some(item_sp) = self.current_item { + err.span_label(item_sp, "this is not `async`"); + } + err.emit(); + return hir::ExprKind::Err; } let span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::Await, @@ -5552,12 +5573,12 @@ impl<'a> LoweringContext<'a> { let gen_future_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::Await, await_span, - Some(vec![Symbol::intern("gen_future")].into()), + Some(vec![sym::gen_future].into()), ); // let mut pinned = ; let expr = P(self.lower_expr(expr)); - let pinned_ident = self.str_to_ident("pinned"); + let pinned_ident = Ident::with_empty_ctxt(sym::pinned); let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode( span, pinned_ident, @@ -5580,7 +5601,7 @@ impl<'a> LoweringContext<'a> { let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( pin_ty_id, span, - &["pin", "Pin"], + &[sym::pin, sym::Pin], "new_unchecked", hir_vec![ref_mut_pinned], ); @@ -5588,21 +5609,21 @@ impl<'a> LoweringContext<'a> { let unsafe_expr = self.expr_unsafe(new_unchecked); P(self.expr_call_std_path( gen_future_span, - &["future", "poll_with_tls_context"], + &[sym::future, sym::poll_with_tls_context], hir_vec![unsafe_expr], )) }; - // `::std::task::Poll::Ready(x) => break x` + // `::std::task::Poll::Ready(result) => break result` let loop_node_id = self.sess.next_node_id(); let loop_hir_id = self.lower_node_id(loop_node_id); let ready_arm = { - let x_ident = self.str_to_ident("x"); + let x_ident = Ident::with_empty_ctxt(sym::result); let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident); let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid)); let ready_pat = self.pat_std_enum( span, - &["task", "Poll", "Ready"], + &[sym::task, sym::Poll, sym::Ready], hir_vec![x_pat], ); let break_x = self.with_loop_scope(loop_node_id, |this| { @@ -5619,18 +5640,10 @@ impl<'a> LoweringContext<'a> { let pending_arm = { let pending_pat = self.pat_std_enum( span, - &["task", "Poll", "Pending"], + &[sym::task, sym::Poll, sym::Pending], hir_vec![], ); - let empty_block = P(hir::Block { - stmts: hir_vec![], - expr: None, - hir_id: self.next_id(), - rules: hir::DefaultBlock, - span, - targeted_by_break: false, - }); - let empty_block = P(self.expr_block(empty_block, ThinVec::new())); + let empty_block = P(self.expr_block_empty(span)); self.arm(hir_vec![pending_pat], empty_block) }; @@ -5641,11 +5654,7 @@ impl<'a> LoweringContext<'a> { hir_vec![ready_arm, pending_arm], hir::MatchSource::AwaitDesugar, )); - hir::Stmt { - hir_id: self.next_id(), - node: hir::StmtKind::Expr(match_expr), - span, - } + self.stmt(span, hir::StmtKind::Expr(match_expr)) }; let yield_stmt = { @@ -5655,11 +5664,7 @@ impl<'a> LoweringContext<'a> { hir::ExprKind::Yield(P(unit)), ThinVec::new(), )); - hir::Stmt { - hir_id: self.next_id(), - node: hir::StmtKind::Expr(yield_expr), - span, - } + self.stmt(span, hir::StmtKind::Expr(yield_expr)) }; let loop_block = P(self.block_all( diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index a1cf338bf12e..eeba628b3bf2 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -226,7 +226,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>) { debug!("hir_map: {:?} => {:?}", id, entry); - let local_map = &mut self.map[id.owner.as_array_index()]; + let local_map = &mut self.map[id.owner.index()]; let i = id.local_id.as_u32() as usize; if local_map.is_none() { *local_map = Some(IndexVec::with_capacity(i + 1)); diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index dc6cddc89f91..1cc9a2c0e8a1 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -17,7 +17,7 @@ use std::fmt::Write; use std::hash::Hash; use syntax::ast; use syntax::ext::hygiene::Mark; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::{Symbol, sym, InternedString}; use syntax_pos::{Span, DUMMY_SP}; use crate::util::nodemap::NodeMap; @@ -38,7 +38,7 @@ impl DefPathTable { def_path_hash: DefPathHash) -> DefIndex { let index = { - let index = DefIndex::from_array_index(self.index_to_key.len()); + let index = DefIndex::from(self.index_to_key.len()); debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index); self.index_to_key.push(key); index @@ -49,17 +49,17 @@ impl DefPathTable { } pub fn next_id(&self) -> DefIndex { - DefIndex::from_array_index(self.index_to_key.len()) + DefIndex::from(self.index_to_key.len()) } #[inline(always)] pub fn def_key(&self, index: DefIndex) -> DefKey { - self.index_to_key[index.as_array_index()].clone() + self.index_to_key[index.index()].clone() } #[inline(always)] pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash { - let ret = self.def_path_hashes[index.as_array_index()]; + let ret = self.def_path_hashes[index.index()]; debug!("def_path_hash({:?}) = {:?}", index, ret); return ret } @@ -74,7 +74,7 @@ impl DefPathTable { .map(|(index, &hash)| { let def_id = DefId { krate: cnum, - index: DefIndex::from_array_index(index), + index: DefIndex::from(index), }; (hash, def_id) }) @@ -387,7 +387,7 @@ impl Definitions { #[inline] pub fn as_local_node_id(&self, def_id: DefId) -> Option { if def_id.krate == LOCAL_CRATE { - let node_id = self.def_index_to_node[def_id.index.as_array_index()]; + let node_id = self.def_index_to_node[def_id.index.index()]; if node_id != ast::DUMMY_NODE_ID { return Some(node_id); } @@ -417,7 +417,7 @@ impl Definitions { #[inline] pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId { - let node_id = self.def_index_to_node[def_index.as_array_index()]; + let node_id = self.def_index_to_node[def_index.index()]; self.node_to_hir_id[node_id] } @@ -508,7 +508,7 @@ impl Definitions { // Create the definition. let index = self.table.allocate(key, def_path_hash); - assert_eq!(index.as_array_index(), self.def_index_to_node.len()); + assert_eq!(index.index(), self.def_index_to_node.len()); self.def_index_to_node.push(node_id); // Some things for which we allocate DefIndices don't correspond to @@ -584,16 +584,16 @@ impl DefPathData { return name } // note that this does not show up in user printouts - CrateRoot => "{{crate}}", - Impl => "{{impl}}", - Misc => "{{misc}}", - ClosureExpr => "{{closure}}", - Ctor => "{{constructor}}", - AnonConst => "{{constant}}", - ImplTrait => "{{opaque}}", + CrateRoot => sym::double_braced_crate, + Impl => sym::double_braced_impl, + Misc => sym::double_braced_misc, + ClosureExpr => sym::double_braced_closure, + Ctor => sym::double_braced_constructor, + AnonConst => sym::double_braced_constant, + ImplTrait => sym::double_braced_opaque, }; - Symbol::intern(s).as_interned_str() + s.as_interned_str() } pub fn to_string(&self) -> String { @@ -653,7 +653,7 @@ macro_rules! define_global_metadata_kind { .position(|k| *k == def_key) .unwrap(); - DefIndex::from_array_index(index) + DefIndex::from(index) } fn name(&self) -> Symbol { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 1a48dff213b5..4b94f772554e 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -189,7 +189,7 @@ pub struct Map<'hir> { impl<'hir> Map<'hir> { #[inline] fn lookup(&self, id: HirId) -> Option<&Entry<'hir>> { - let local_map = self.map.get(id.owner.as_array_index())?; + let local_map = self.map.get(id.owner.index())?; local_map.as_ref()?.get(id.local_id)?.as_ref() } @@ -1023,7 +1023,7 @@ impl<'hir> Map<'hir> { local_map.iter_enumerated().filter_map(move |(i, entry)| entry.map(move |_| { // Reconstruct the HirId based on the 3 indices we used to find it HirId { - owner: DefIndex::from_array_index(array_index), + owner: DefIndex::from(array_index), local_id: i, } })) @@ -1146,7 +1146,7 @@ impl<'a> NodesMatchingSuffix<'a> { None => return false, Some((node_id, name)) => (node_id, name), }; - if mod_name != &**part { + if mod_name.as_str() != *part { return false; } cursor = self.map.get_parent_item(mod_id); @@ -1183,7 +1183,7 @@ impl<'a> NodesMatchingSuffix<'a> { // We are looking at some node `n` with a given name and parent // id; do their names match what I am seeking? fn matches_names(&self, parent_of_n: HirId, name: Name) -> bool { - name == &**self.item_name && self.suffix_matches(parent_of_n) + name.as_str() == *self.item_name && self.suffix_matches(parent_of_n) } fn matches_suffix(&self, hir: HirId) -> bool { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 01de7917e6e2..57304c5ed37a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -20,7 +20,7 @@ use syntax_pos::{Span, DUMMY_SP, symbol::InternedString}; use syntax::source_map::Spanned; use rustc_target::spec::abi::Abi; use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, AsmDialect}; -use syntax::ast::{Attribute, Label, Lit, StrStyle, FloatTy, IntTy, UintTy}; +use syntax::ast::{Attribute, Label, LitKind, StrStyle, FloatTy, IntTy, UintTy}; use syntax::attr::{InlineAttr, OptimizeAttr}; use syntax::ext::hygiene::SyntaxContext; use syntax::ptr::P; @@ -126,12 +126,12 @@ mod item_local_id_inner { use rustc_macros::HashStable; newtype_index! { /// An `ItemLocalId` uniquely identifies something within a given "item-like", - /// that is within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no + /// that is, within a hir::Item, hir::TraitItem, or hir::ImplItem. There is no /// guarantee that the numerical value of a given `ItemLocalId` corresponds to /// the node's position within the owning item in any way, but there is a /// guarantee that the `LocalItemId`s within an owner occupy a dense range of /// integers starting at zero, so a mapping that maps all or most nodes within - /// an "item-like" to something else can be implement by a `Vec` instead of a + /// an "item-like" to something else can be implemented by a `Vec` instead of a /// tree or hash map. pub struct ItemLocalId { derive [HashStable] @@ -609,9 +609,9 @@ impl Generics { own_counts } - pub fn get_named(&self, name: &InternedString) -> Option<&GenericParam> { + pub fn get_named(&self, name: InternedString) -> Option<&GenericParam> { for param in &self.params { - if *name == param.name.ident().as_interned_str() { + if name == param.name.ident().as_interned_str() { return Some(param); } } @@ -1331,6 +1331,9 @@ impl BodyOwnerKind { } } +/// A literal. +pub type Lit = Spanned; + /// A constant (expression) that's not an item or associated item, /// but needs its own `DefId` for type-checking, const-eval, etc. /// These are usually found nested inside types (e.g., array lengths) @@ -1353,7 +1356,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::() == 72); +static_assert_size!(Expr, 72); impl Expr { pub fn precedence(&self) -> ExprPrecedence { @@ -1368,7 +1371,6 @@ impl Expr { ExprKind::Lit(_) => ExprPrecedence::Lit, ExprKind::Type(..) | ExprKind::Cast(..) => ExprPrecedence::Cast, ExprKind::DropTemps(ref expr, ..) => expr.precedence(), - ExprKind::If(..) => ExprPrecedence::If, ExprKind::While(..) => ExprPrecedence::While, ExprKind::Loop(..) => ExprPrecedence::Loop, ExprKind::Match(..) => ExprPrecedence::Match, @@ -1421,7 +1423,6 @@ impl Expr { ExprKind::MethodCall(..) | ExprKind::Struct(..) | ExprKind::Tup(..) | - ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Closure(..) | ExprKind::Block(..) | @@ -1498,10 +1499,6 @@ pub enum ExprKind { /// This construct only exists to tweak the drop order in HIR lowering. /// An example of that is the desugaring of `for` loops. DropTemps(P), - /// An `if` block, with an optional else block. - /// - /// I.e., `if { } else { }`. - If(P, P, Option>), /// A while loop, with an optional label /// /// I.e., `'label: while expr { }`. @@ -1615,6 +1612,10 @@ pub enum LocalSource { pub enum MatchSource { /// A `match _ { .. }`. Normal, + /// An `if _ { .. }` (optionally with `else { .. }`). + IfDesugar { + contains_else_clause: bool, + }, /// An `if let _ = _ { .. }` (optionally with `else { .. }`). IfLetDesugar { contains_else_clause: bool, diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 54816316f0bf..8a9028e54439 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -5,7 +5,7 @@ use syntax::parse::ParseSess; use syntax::parse::lexer::comments; use syntax::print::pp::{self, Breaks}; use syntax::print::pp::Breaks::{Consistent, Inconsistent}; -use syntax::print::pprust::PrintState; +use syntax::print::pprust::{self, PrintState}; use syntax::ptr::P; use syntax::symbol::keywords; use syntax::util::parser::{self, AssocOp, Fixity}; @@ -18,7 +18,6 @@ use crate::hir::{GenericParam, GenericParamKind, GenericArg}; use std::borrow::Cow; use std::cell::Cell; use std::io::{self, Write, Read}; -use std::iter::Peekable; use std::vec; pub enum AnnNode<'a> { @@ -76,7 +75,6 @@ pub struct State<'a> { pub s: pp::Printer<'a>, cm: Option<&'a SourceMap>, comments: Option>, - literals: Peekable>, cur_cmnt: usize, boxes: Vec, ann: &'a (dyn PpAnn + 'a), @@ -98,14 +96,6 @@ impl<'a> PrintState<'a> for State<'a> { fn cur_cmnt(&mut self) -> &mut usize { &mut self.cur_cmnt } - - fn cur_lit(&mut self) -> Option<&comments::Literal> { - self.literals.peek() - } - - fn bump_lit(&mut self) -> Option { - self.literals.next() - } } #[allow(non_upper_case_globals)] @@ -116,18 +106,16 @@ pub const default_columns: usize = 78; /// Requires you to pass an input filename and reader so that -/// it can scan the input text for comments and literals to -/// copy forward. +/// it can scan the input text for comments to copy forward. pub fn print_crate<'a>(cm: &'a SourceMap, sess: &ParseSess, krate: &hir::Crate, filename: FileName, input: &mut dyn Read, out: Box, - ann: &'a dyn PpAnn, - is_expanded: bool) + ann: &'a dyn PpAnn) -> io::Result<()> { - let mut s = State::new_from_input(cm, sess, filename, input, out, ann, is_expanded); + let mut s = State::new_from_input(cm, sess, filename, input, out, ann); // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. @@ -143,36 +131,21 @@ impl<'a> State<'a> { filename: FileName, input: &mut dyn Read, out: Box, - ann: &'a dyn PpAnn, - is_expanded: bool) + ann: &'a dyn PpAnn) -> State<'a> { - let (cmnts, lits) = comments::gather_comments_and_literals(sess, filename, input); - - State::new(cm, - out, - ann, - Some(cmnts), - // If the code is post expansion, don't use the table of - // literals, since it doesn't correspond with the literals - // in the AST anymore. - if is_expanded { - None - } else { - Some(lits) - }) + let comments = comments::gather_comments(sess, filename, input); + State::new(cm, out, ann, Some(comments)) } pub fn new(cm: &'a SourceMap, out: Box, ann: &'a dyn PpAnn, - comments: Option>, - literals: Option>) + comments: Option>) -> State<'a> { State { s: pp::mk_printer(out, default_columns), cm: Some(cm), comments, - literals: literals.unwrap_or_default().into_iter().peekable(), cur_cmnt: 0, boxes: Vec::new(), ann, @@ -189,7 +162,6 @@ pub fn to_string(ann: &dyn PpAnn, f: F) -> String s: pp::mk_printer(Box::new(&mut wr), default_columns), cm: None, comments: None, - literals: vec![].into_iter().peekable(), cur_cmnt: 0, boxes: Vec::new(), ann, @@ -646,7 +618,6 @@ impl<'a> State<'a> { self.print_where_clause(&exist.generics.where_clause)?; self.s.space()?; - self.word_space(":")?; let mut real_bounds = Vec::with_capacity(exist.bounds.len()); for b in exist.bounds.iter() { if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b { @@ -1093,65 +1064,6 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Block(blk)) } - fn print_else(&mut self, els: Option<&hir::Expr>) -> io::Result<()> { - match els { - Some(_else) => { - match _else.node { - // "another else-if" - hir::ExprKind::If(ref i, ref then, ref e) => { - self.cbox(indent_unit - 1)?; - self.ibox(0)?; - self.s.word(" else if ")?; - self.print_expr_as_cond(&i)?; - self.s.space()?; - self.print_expr(&then)?; - self.print_else(e.as_ref().map(|e| &**e)) - } - // "final else" - hir::ExprKind::Block(ref b, _) => { - self.cbox(indent_unit - 1)?; - self.ibox(0)?; - self.s.word(" else ")?; - self.print_block(&b) - } - // BLEAH, constraints would be great here - _ => { - panic!("print_if saw if with weird alternative"); - } - } - } - _ => Ok(()), - } - } - - pub fn print_if(&mut self, - test: &hir::Expr, - blk: &hir::Expr, - elseopt: Option<&hir::Expr>) - -> io::Result<()> { - self.head("if")?; - self.print_expr_as_cond(test)?; - self.s.space()?; - self.print_expr(blk)?; - self.print_else(elseopt) - } - - pub fn print_if_let(&mut self, - pat: &hir::Pat, - expr: &hir::Expr, - blk: &hir::Block, - elseopt: Option<&hir::Expr>) - -> io::Result<()> { - self.head("if let")?; - self.print_pat(pat)?; - self.s.space()?; - self.word_space("=")?; - self.print_expr_as_cond(expr)?; - self.s.space()?; - self.print_block(blk)?; - self.print_else(elseopt) - } - pub fn print_anon_const(&mut self, constant: &hir::AnonConst) -> io::Result<()> { self.ann.nested(self, Nested::Body(constant.body)) } @@ -1335,6 +1247,12 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(expr, parser::PREC_PREFIX) } + fn print_literal(&mut self, lit: &hir::Lit) -> io::Result<()> { + self.maybe_print_comment(lit.span.lo())?; + let (token, suffix) = lit.node.to_lit_token(); + self.writer().word(pprust::literal_to_string(token, suffix)) + } + pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> { self.maybe_print_comment(expr.span.lo())?; self.print_outer_attributes(&expr.attrs)?; @@ -1406,9 +1324,6 @@ impl<'a> State<'a> { // Print `}`: self.bclose_maybe_open(expr.span, indent_unit, true)?; } - hir::ExprKind::If(ref test, ref blk, ref elseopt) => { - self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; - } hir::ExprKind::While(ref test, ref blk, opt_label) => { if let Some(label) = opt_label { self.print_ident(label.ident)?; @@ -2414,7 +2329,6 @@ impl<'a> State<'a> { /// isn't parsed as (if true {...} else {...} | x) | 5 fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool { match e.node { - hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::Block(..) | hir::ExprKind::While(..) | diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 6da2cb9ab57e..8be610e8bf7a 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -28,7 +28,7 @@ use smallvec::SmallVec; fn compute_ignored_attr_names() -> FxHashSet { debug_assert!(ich::IGNORED_ATTRIBUTES.len() > 0); - ich::IGNORED_ATTRIBUTES.iter().map(|&s| Symbol::intern(s)).collect() + ich::IGNORED_ATTRIBUTES.iter().map(|&s| s).collect() } /// This is the context state available during incr. comp. hashing. It contains diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 90dd5099cbfd..4e5718cc5ef2 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -162,7 +162,13 @@ impl_stable_hash_for!(enum ::syntax::ast::LitIntType { Unsuffixed }); -impl_stable_hash_for_spanned!(::syntax::ast::LitKind); +impl_stable_hash_for!(struct ::syntax::ast::Lit { + node, + token, + suffix, + span +}); + impl_stable_hash_for!(enum ::syntax::ast::LitKind { Str(value, style), Err(value), @@ -175,6 +181,8 @@ impl_stable_hash_for!(enum ::syntax::ast::LitKind { Bool(value) }); +impl_stable_hash_for_spanned!(::syntax::ast::LitKind); + impl_stable_hash_for!(enum ::syntax::ast::IntTy { Isize, I8, I16, I32, I64, I128 }); impl_stable_hash_for!(enum ::syntax::ast::UintTy { Usize, U8, U16, U32, U64, U128 }); impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 }); @@ -280,6 +288,19 @@ for tokenstream::TokenStream { } } +impl_stable_hash_for!(enum token::Lit { + Bool(val), + Byte(val), + Char(val), + Err(val), + Integer(val), + Float(val), + Str_(val), + ByteStr(val), + StrRaw(val, n), + ByteStrRaw(val, n) +}); + fn hash_token<'a, 'gcx, W: StableHasherResult>( token: &token::Token, hcx: &mut StableHashingContext<'a>, @@ -327,22 +348,8 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>( token::Token::CloseDelim(delim_token) => { std_hash::Hash::hash(&delim_token, hasher); } - token::Token::Literal(ref lit, ref opt_name) => { - mem::discriminant(lit).hash_stable(hcx, hasher); - match *lit { - token::Lit::Byte(val) | - token::Lit::Char(val) | - token::Lit::Err(val) | - token::Lit::Integer(val) | - token::Lit::Float(val) | - token::Lit::Str_(val) | - token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher), - token::Lit::StrRaw(val, n) | - token::Lit::ByteStrRaw(val, n) => { - val.hash_stable(hcx, hasher); - n.hash_stable(hcx, hasher); - } - }; + token::Token::Literal(lit, opt_name) => { + lit.hash_stable(hcx, hasher); opt_name.hash_stable(hcx, hasher); } @@ -395,6 +402,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { + IfTemporary, Async, Await, QuestionMark, diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index b407b75e68c9..f3fc7ec8fda1 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -4,6 +4,8 @@ crate use rustc_data_structures::fingerprint::Fingerprint; pub use self::caching_source_map_view::CachingSourceMapView; pub use self::hcx::{StableHashingContextProvider, StableHashingContext, NodeIdHashingMode, hash_stable_trait_impls}; +use syntax::symbol::{Symbol, sym}; + mod caching_source_map_view; mod hcx; @@ -12,16 +14,16 @@ mod impls_misc; mod impls_ty; mod impls_syntax; -pub const ATTR_DIRTY: &str = "rustc_dirty"; -pub const ATTR_CLEAN: &str = "rustc_clean"; -pub const ATTR_IF_THIS_CHANGED: &str = "rustc_if_this_changed"; -pub const ATTR_THEN_THIS_WOULD_NEED: &str = "rustc_then_this_would_need"; -pub const ATTR_PARTITION_REUSED: &str = "rustc_partition_reused"; -pub const ATTR_PARTITION_CODEGENED: &str = "rustc_partition_codegened"; -pub const ATTR_EXPECTED_CGU_REUSE: &str = "rustc_expected_cgu_reuse"; +pub const ATTR_DIRTY: Symbol = sym::rustc_dirty; +pub const ATTR_CLEAN: Symbol = sym::rustc_clean; +pub const ATTR_IF_THIS_CHANGED: Symbol = sym::rustc_if_this_changed; +pub const ATTR_THEN_THIS_WOULD_NEED: Symbol = sym::rustc_then_this_would_need; +pub const ATTR_PARTITION_REUSED: Symbol = sym::rustc_partition_reused; +pub const ATTR_PARTITION_CODEGENED: Symbol = sym::rustc_partition_codegened; +pub const ATTR_EXPECTED_CGU_REUSE: Symbol = sym::rustc_expected_cgu_reuse; -pub const IGNORED_ATTRIBUTES: &[&str] = &[ - "cfg", +pub const IGNORED_ATTRIBUTES: &[Symbol] = &[ + sym::cfg, ATTR_IF_THIS_CHANGED, ATTR_THEN_THIS_WOULD_NEED, ATTR_DIRTY, diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 4b6e7da33308..e4505a240379 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -194,20 +194,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut sp = cm.def_span(self.hir().span_by_hir_id(node)); if let Some(param) = self.hir() .get_generics(scope) - .and_then(|generics| generics.get_named(&br.name)) + .and_then(|generics| generics.get_named(br.name)) { sp = param.span; } (format!("the lifetime {} as defined on", br.name), sp) } ty::ReFree(ty::FreeRegion { - bound_region: ty::BoundRegion::BrNamed(_, ref name), + bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => { let mut sp = cm.def_span(self.hir().span_by_hir_id(node)); if let Some(param) = self.hir() .get_generics(scope) - .and_then(|generics| generics.get_named(&name)) + .and_then(|generics| generics.get_named(name)) { sp = param.span; } diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs index 3ed28a1f9882..feade7a8f56f 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs @@ -43,7 +43,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { ) -> Option> { let (id, bound_region) = match *anon_region { ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), - ty::ReEarlyBound(ref ebr) => ( + ty::ReEarlyBound(ebr) => ( self.tcx().parent(ebr.def_id).unwrap(), ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), ), diff --git a/src/librustc/infer/lexical_region_resolve/graphviz.rs b/src/librustc/infer/lexical_region_resolve/graphviz.rs index 073a3f74422c..1878afd581dd 100644 --- a/src/librustc/infer/lexical_region_resolve/graphviz.rs +++ b/src/librustc/infer/lexical_region_resolve/graphviz.rs @@ -56,7 +56,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( } let requested_node = env::var("RUST_REGION_GRAPH_NODE") - .ok().and_then(|s| s.parse().map(DefIndex::from_raw_u32).ok()); + .ok().and_then(|s| s.parse().map(DefIndex::from_u32).ok()); if requested_node.is_some() && requested_node != Some(context.index) { return; @@ -90,7 +90,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( let mut new_str = String::new(); for c in output_template.chars() { if c == '%' { - new_str.push_str(&context.index.as_raw_u32().to_string()); + new_str.push_str(&context.index.as_u32().to_string()); } else { new_str.push(c); } diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index f85fd524a5d9..4351f94df2f1 100644 --- a/src/librustc/infer/opaque_types/mod.rs +++ b/src/librustc/infer/opaque_types/mod.rs @@ -284,18 +284,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("constrain_opaque_type: def_id={:?}", def_id); debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn); + let tcx = self.tcx; + let concrete_ty = self.resolve_type_vars_if_possible(&opaque_defn.concrete_ty); debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); - let abstract_type_generics = self.tcx.generics_of(def_id); + let abstract_type_generics = tcx.generics_of(def_id); - let span = self.tcx.def_span(def_id); + let span = tcx.def_span(def_id); - // If there are required region bounds, we can just skip - // ahead. There will already be a registered region - // obligation related `concrete_ty` to those regions. + // If there are required region bounds, we can use them. if opaque_defn.has_required_region_bounds { + let predicates_of = tcx.predicates_of(def_id); + debug!( + "constrain_opaque_type: predicates: {:#?}", + predicates_of, + ); + let bounds = predicates_of.instantiate(tcx, opaque_defn.substs); + debug!("constrain_opaque_type: bounds={:#?}", bounds); + let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs); + + let required_region_bounds = tcx.required_region_bounds( + opaque_type, + bounds.predicates.clone(), + ); + debug_assert!(!required_region_bounds.is_empty()); + + for region in required_region_bounds { + concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor { + infcx: self, + least_region: region, + span, + }); + } return; } @@ -371,7 +393,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - let least_region = least_region.unwrap_or(self.tcx.lifetimes.re_static); + let least_region = least_region.unwrap_or(tcx.lifetimes.re_static); debug!("constrain_opaque_types: least_region={:?}", least_region); concrete_ty.visit_with(&mut OpaqueTypeOutlivesVisitor { @@ -589,10 +611,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> ty::ReLateBound(..) | // ignore `'static`, as that can appear anywhere - ty::ReStatic | - - // ignore `ReScope`, which may appear in impl Trait in bindings. - ty::ReScope(..) => return r, + ty::ReStatic => return r, _ => { } } @@ -683,6 +702,23 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> self.tcx.mk_closure(def_id, ty::ClosureSubsts { substs }) } + ty::Generator(def_id, substs, movability) => { + let generics = self.tcx.generics_of(def_id); + let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map( + |(index, &kind)| { + if index < generics.parent_count { + // Accommodate missing regions in the parent kinds... + self.fold_kind_mapping_missing_regions_to_empty(kind) + } else { + // ...but not elsewhere. + self.fold_kind_normally(kind) + } + }, + )); + + self.tcx.mk_generator(def_id, ty::GeneratorSubsts { substs }, movability) + } + _ => ty.super_fold_with(self), } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 993e1aacb4e4..69d865f53d46 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -198,12 +198,6 @@ declare_lint! { "detects generic lifetime arguments in path segments with late bound lifetime parameters" } -declare_lint! { - pub INCOHERENT_FUNDAMENTAL_IMPLS, - Deny, - "potentially-conflicting impls were erroneously allowed" -} - declare_lint! { pub ORDER_DEPENDENT_TRAIT_OBJECTS, Deny, @@ -428,7 +422,6 @@ declare_lint_pass! { MISSING_FRAGMENT_SPECIFIER, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, LATE_BOUND_LIFETIME_ARGUMENTS, - INCOHERENT_FUNDAMENTAL_IMPLS, ORDER_DEPENDENT_TRAIT_OBJECTS, DEPRECATED, UNUSED_UNSAFE, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index e713cf8d8055..7e1e751e8564 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -828,8 +828,8 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { // This shouldn't ever be needed, but just in case: Ok(vec![match trait_ref { - Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)).as_str(), - None => Symbol::intern(&format!("<{}>", self_ty)).as_str(), + Some(trait_ref) => LocalInternedString::intern(&format!("{:?}", trait_ref)), + None => LocalInternedString::intern(&format!("<{}>", self_ty)), }]) } @@ -845,9 +845,10 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { // This shouldn't ever be needed, but just in case: path.push(match trait_ref { Some(trait_ref) => { - Symbol::intern(&format!("", trait_ref, self_ty)).as_str() + LocalInternedString::intern(&format!("", trait_ref, + self_ty)) }, - None => Symbol::intern(&format!("", self_ty)).as_str(), + None => LocalInternedString::intern(&format!("", self_ty)), }); Ok(path) diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index 2e5bd8add0cd..9c926dff325b 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -14,7 +14,7 @@ use syntax::ast; use syntax::attr; use syntax::feature_gate; use syntax::source_map::MultiSpan; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; pub struct LintLevelSets { list: Vec, @@ -194,7 +194,7 @@ impl<'a> LintLevelsBuilder<'a> { struct_span_err!(sess, span, E0452, "malformed lint attribute") }; for attr in attrs { - let level = match Level::from_str(&attr.name_or_empty()) { + let level = match Level::from_symbol(attr.name_or_empty()) { None => continue, Some(lvl) => lvl, }; @@ -221,7 +221,7 @@ impl<'a> LintLevelsBuilder<'a> { match item.node { ast::MetaItemKind::Word => {} // actual lint names handled later ast::MetaItemKind::NameValue(ref name_value) => { - if item.path == "reason" { + if item.path == sym::reason { // found reason, reslice meta list to exclude it metas = &metas[0..metas.len()-1]; // FIXME (#55112): issue unused-attributes lint if we thereby @@ -230,7 +230,7 @@ impl<'a> LintLevelsBuilder<'a> { if !self.sess.features_untracked().lint_reasons { feature_gate::emit_feature_err( &self.sess.parse_sess, - "lint_reasons", + sym::lint_reasons, item.span, feature_gate::GateIssue::Language, "lint reasons are experimental" @@ -261,7 +261,7 @@ impl<'a> LintLevelsBuilder<'a> { let mut err = bad_attr(li.span()); if let Some(item) = li.meta_item() { if let ast::MetaItemKind::NameValue(_) = item.node { - if item.path == "reason" { + if item.path == sym::reason { err.help("reason in lint attribute must come last"); } } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 6613440ee7c9..9c4683e09463 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -38,7 +38,7 @@ use syntax::ast; use syntax::source_map::{MultiSpan, ExpnFormat}; use syntax::early_buffered_lints::BufferedEarlyLintId; use syntax::edition::Edition; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; pub use crate::lint::context::{LateContext, EarlyContext, LintContext, LintStore, @@ -570,6 +570,17 @@ impl Level { _ => None, } } + + /// Converts a symbol to a level. + pub fn from_symbol(x: Symbol) -> Option { + match x { + sym::allow => Some(Allow), + sym::warn => Some(Warn), + sym::deny => Some(Deny), + sym::forbid => Some(Forbid), + _ => None, + } + } } /// How a lint level was set. @@ -752,7 +763,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session, pub fn maybe_lint_level_root(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId) -> bool { let attrs = tcx.hir().attrs_by_hir_id(id); - attrs.iter().any(|attr| Level::from_str(&attr.name_or_empty()).is_some()) + attrs.iter().any(|attr| Level::from_symbol(attr.name_or_empty()).is_some()) } fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) @@ -767,6 +778,9 @@ fn lint_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) let push = builder.levels.push(&krate.attrs); builder.levels.register_id(hir::CRATE_HIR_ID); + for macro_def in &krate.exported_macros { + builder.levels.register_id(macro_def.hir_id); + } intravisit::walk_crate(&mut builder, krate); builder.levels.pop(push); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a0107ed0546d..2a9928567f4d 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -19,6 +19,7 @@ use rustc_data_structures::fx::FxHashMap; use syntax::{ast, source_map}; use syntax::attr; +use syntax::symbol::sym; use syntax_pos; // Any local node that may call something in its body block should be @@ -304,22 +305,22 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_, '_, '_>, id: hir::HirId, attrs: &[ast::Attribute]) -> bool { - if attr::contains_name(attrs, "lang") { + if attr::contains_name(attrs, sym::lang) { return true; } // Stable attribute for #[lang = "panic_impl"] - if attr::contains_name(attrs, "panic_handler") { + if attr::contains_name(attrs, sym::panic_handler) { return true; } // (To be) stable attribute for #[lang = "oom"] - if attr::contains_name(attrs, "alloc_error_handler") { + if attr::contains_name(attrs, sym::alloc_error_handler) { return true; } // Don't lint about global allocators - if attr::contains_name(attrs, "global_allocator") { + if attr::contains_name(attrs, sym::global_allocator) { return true; } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index df77033ebef3..67db2ec24815 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -4,6 +4,7 @@ use crate::session::{config, Session}; use crate::session::config::EntryFnType; use syntax::attr; use syntax::entry::EntryPointType; +use syntax::symbol::sym; use syntax_pos::Span; use crate::hir::{HirId, Item, ItemKind, ImplItem, TraitItem}; use crate::hir::itemlikevisit::ItemLikeVisitor; @@ -58,7 +59,7 @@ fn entry_fn(tcx: TyCtxt<'_, '_, '_>, cnum: CrateNum) -> Option<(DefId, EntryFnTy } // If the user wants no main function at all, then stop here. - if attr::contains_name(&tcx.hir().krate().attrs, "no_main") { + if attr::contains_name(&tcx.hir().krate().attrs, sym::no_main) { return None; } @@ -81,11 +82,11 @@ fn entry_fn(tcx: TyCtxt<'_, '_, '_>, cnum: CrateNum) -> Option<(DefId, EntryFnTy fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType { match item.node { ItemKind::Fn(..) => { - if attr::contains_name(&item.attrs, "start") { + if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start - } else if attr::contains_name(&item.attrs, "main") { + } else if attr::contains_name(&item.attrs, sym::main) { EntryPointType::MainAttr - } else if item.ident.name == "main" { + } else if item.ident.name == sym::main { if at_root { // This is a top-level function so can be 'main'. EntryPointType::MainNamed diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 93ba4241c472..d46bba92f3fc 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -424,14 +424,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_exprs(exprs); } - hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => { - self.consume_expr(&cond_expr); - self.walk_expr(&then_expr); - if let Some(ref else_expr) = *opt_else_expr { - self.consume_expr(&else_expr); - } - } - hir::ExprKind::Match(ref discr, ref arms, _) => { let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr))); let r = self.tcx().lifetimes.re_empty; diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 0e283ca6b1cf..103580a598fc 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -18,7 +18,7 @@ use crate::middle::weak_lang_items; use crate::util::nodemap::FxHashMap; use syntax::ast; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; use rustc_macros::HashStable; use crate::hir::itemlikevisit::ItemLikeVisitor; @@ -209,9 +209,9 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { /// are also extracted out when found. pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { attrs.iter().find_map(|attr| Some(match attr { - _ if attr.check_name("lang") => (attr.value_str()?, attr.span), - _ if attr.check_name("panic_handler") => (Symbol::intern("panic_impl"), attr.span), - _ if attr.check_name("alloc_error_handler") => (Symbol::intern("oom"), attr.span), + _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span), + _ if attr.check_name(sym::panic_handler) => (Symbol::intern("panic_impl"), attr.span), + _ if attr.check_name(sym::alloc_error_handler) => (Symbol::intern("oom"), attr.span), _ => return None, })) } diff --git a/src/librustc/middle/lib_features.rs b/src/librustc/middle/lib_features.rs index e79ef8bfc6fb..76934ddd69b1 100644 --- a/src/librustc/middle/lib_features.rs +++ b/src/librustc/middle/lib_features.rs @@ -8,7 +8,7 @@ use crate::ty::TyCtxt; use crate::hir::intravisit::{self, NestedVisitorMap, Visitor}; use syntax::symbol::Symbol; use syntax::ast::{Attribute, MetaItem, MetaItemKind}; -use syntax_pos::{Span, symbols}; +use syntax_pos::{Span, sym}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_macros::HashStable; use errors::DiagnosticId; @@ -51,7 +51,7 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> { } fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option, Span)> { - let stab_attrs = [symbols::stable, symbols::unstable, symbols::rustc_const_unstable]; + let stab_attrs = [sym::stable, sym::unstable, sym::rustc_const_unstable]; // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`, // `#[rustc_const_unstable (..)]`). @@ -65,9 +65,9 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> { for meta in metas { if let Some(mi) = meta.meta_item() { // Find the `feature = ".."` meta-item. - match (mi.name_or_empty().get(), mi.value_str()) { - ("feature", val) => feature = val, - ("since", val) => since = val, + match (mi.name_or_empty(), mi.value_str()) { + (sym::feature, val) => feature = val, + (sym::since, val) => since = val, _ => {} } } @@ -76,7 +76,7 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> { // This additional check for stability is to make sure we // don't emit additional, irrelevant errors for malformed // attributes. - if *stab_attr != "stable" || since.is_some() { + if *stab_attr != sym::stable || since.is_some() { return Some((feature, since, attr.span)); } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 4b458e474b29..cb333b5b0cba 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -112,7 +112,7 @@ use std::io; use std::rc::Rc; use syntax::ast::{self, NodeId}; use syntax::ptr::P; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax_pos::Span; use crate::hir; @@ -362,7 +362,7 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>, if let FnKind::Method(..) = fk { let parent = ir.tcx.hir().get_parent_item(id); if let Some(Node::Item(i)) = ir.tcx.hir().find_by_hir_id(parent) { - if i.attrs.iter().any(|a| a.check_name("automatically_derived")) { + if i.attrs.iter().any(|a| a.check_name(sym::automatically_derived)) { return; } } @@ -500,7 +500,6 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { } // live nodes required for interesting control flow: - hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) => { @@ -1040,28 +1039,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }) } - hir::ExprKind::If(ref cond, ref then, ref els) => { - // - // (cond) - // | - // v - // (expr) - // / \ - // | | - // v v - // (then)(els) - // | | - // v v - // ( succ ) - // - let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ); - let then_ln = self.propagate_through_expr(&then, succ); - let ln = self.live_node(expr.hir_id, expr.span); - self.init_from_succ(ln, else_ln); - self.merge_from_succ(ln, then_ln, false); - self.propagate_through_expr(&cond, ln) - } - hir::ExprKind::While(ref cond, ref blk, _) => { self.propagate_through_loop(expr, WhileLoop(&cond), &blk, succ) } @@ -1523,7 +1500,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { } // no correctness conditions related to liveness - hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) | hir::ExprKind::If(..) | + hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) | hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Index(..) | hir::ExprKind::Field(..) | hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7edd5c5a9de1..c7f8cf684e6b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -72,6 +72,7 @@ use crate::hir::{MutImmutable, MutMutable, PatKind}; use crate::hir::pat_util::EnumerateAndAdjustIterator; use crate::hir; use syntax::ast::{self, Name}; +use syntax::symbol::sym; use syntax_pos::Span; use std::borrow::Cow; @@ -678,7 +679,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) | hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | hir::ExprKind::DropTemps(..) | - hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) | + hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | hir::ExprKind::While(..) | hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) | @@ -714,7 +715,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // they also cannot be moved out of. let is_thread_local = self.tcx.get_attrs(def_id)[..] .iter() - .any(|attr| attr.check_name("thread_local")); + .any(|attr| attr.check_name(sym::thread_local)); let cat = if is_thread_local { let re = self.temporary_scope(hir_id.local_id); diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index ea077220e0be..5f355d17072b 100644 --- a/src/librustc/middle/recursion_limit.rs +++ b/src/librustc/middle/recursion_limit.rs @@ -7,15 +7,16 @@ use crate::session::Session; use syntax::ast; +use syntax::symbol::{Symbol, sym}; use rustc_data_structures::sync::Once; pub fn update_limits(sess: &Session, krate: &ast::Crate) { - update_limit(krate, &sess.recursion_limit, "recursion_limit", 64); - update_limit(krate, &sess.type_length_limit, "type_length_limit", 1048576); + update_limit(krate, &sess.recursion_limit, sym::recursion_limit, 64); + update_limit(krate, &sess.type_length_limit, sym::type_length_limit, 1048576); } -fn update_limit(krate: &ast::Crate, limit: &Once, name: &str, default: usize) { +fn update_limit(krate: &ast::Crate, limit: &Once, name: Symbol, default: usize) { for attr in &krate.attrs { if !attr.check_name(name) { continue; diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2b88f273adce..37681ad7fcdd 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -158,7 +158,7 @@ newtype_index! { impl_stable_hash_for!(struct crate::middle::region::FirstStatementIndex { private }); // compilation error if size of `ScopeData` is not the same as a `u32` -static_assert!(ASSERT_SCOPE_DATA: mem::size_of::() == 4); +static_assert_size!(ScopeData, 4); impl Scope { /// Returns a item-local ID associated with this scope. @@ -884,17 +884,6 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: terminating(r.hir_id.local_id); } - hir::ExprKind::If(ref expr, ref then, Some(ref otherwise)) => { - terminating(expr.hir_id.local_id); - terminating(then.hir_id.local_id); - terminating(otherwise.hir_id.local_id); - } - - hir::ExprKind::If(ref expr, ref then, None) => { - terminating(expr.hir_id.local_id); - terminating(then.hir_id.local_id); - } - hir::ExprKind::Loop(ref body, _, _) => { terminating(body.hir_id.local_id); } diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index d835d872d76d..2402d0eefde4 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -23,7 +23,7 @@ use std::mem::replace; use syntax::ast; use syntax::attr; use syntax::ptr::P; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax_pos::Span; use crate::hir::intravisit::{self, NestedVisitorMap, Visitor}; @@ -1285,7 +1285,7 @@ fn compute_object_lifetime_defaults( let result = object_lifetime_defaults_for_item(tcx, generics); // Debugging aid. - if attr::contains_name(&item.attrs, "rustc_object_lifetime_default") { + if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) { let object_lifetime_default_reprs: String = result .iter() .map(|set| match *set { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 5078bd7c5942..abcf164cda6d 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -11,7 +11,7 @@ use crate::hir::intravisit::{self, Visitor, NestedVisitorMap}; use crate::ty::query::Providers; use crate::middle::privacy::AccessLevels; use crate::session::{DiagnosticMessageId, Session}; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::{Span, MultiSpan}; use syntax::ast::Attribute; use syntax::errors::Applicability; @@ -195,7 +195,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { // Emit errors for non-staged-api crates. for attr in attrs { let name = attr.name_or_empty(); - if ["unstable", "stable", "rustc_deprecated"].contains(&name.get()) { + if [sym::unstable, sym::stable, sym::rustc_deprecated].contains(&name) { attr::mark_used(attr); self.tcx.sess.span_err(attr.span, "stability attributes may not be used \ outside of the standard library"); @@ -669,7 +669,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match stability { Some(&Stability { level: attr::Unstable { reason, issue }, feature, .. }) => { - if span.allows_unstable(&feature.as_str()) { + if span.allows_unstable(feature) { debug!("stability: skipping span={:?} since it is internal", span); return EvalResult::Allow; } @@ -686,7 +686,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // the `-Z force-unstable-if-unmarked` flag present (we're // compiling a compiler crate), then let this missing feature // annotation slide. - if feature == "rustc_private" && issue == 27812 { + if feature == sym::rustc_private && issue == 27812 { if self.sess.opts.debugging_opts.force_unstable_if_unmarked { return EvalResult::Allow; } @@ -739,7 +739,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone()); let fresh = self.sess.one_time_diagnostics.borrow_mut().insert(error_id); if fresh { - emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, + emit_feature_err(&self.sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg); } } @@ -802,13 +802,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if adt_def.has_dtor(self.tcx) { emit_feature_err(&self.tcx.sess.parse_sess, - "untagged_unions", item.span, GateIssue::Language, + sym::untagged_unions, item.span, GateIssue::Language, "unions with `Drop` implementations are unstable"); } else { let param_env = self.tcx.param_env(def_id); if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() { emit_feature_err(&self.tcx.sess.parse_sess, - "untagged_unions", item.span, GateIssue::Language, + sym::untagged_unions, item.span, GateIssue::Language, "unions with non-`Copy` fields are unstable"); } } diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 312924e5e90f..75c21c738f7a 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -6,7 +6,7 @@ use crate::middle::lang_items; use rustc_data_structures::fx::FxHashSet; use rustc_target::spec::PanicStrategy; use syntax::ast; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; use crate::hir::def_id::DefId; use crate::hir::intravisit::{Visitor, NestedVisitorMap}; @@ -46,8 +46,8 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn link_name(attrs: &[ast::Attribute]) -> Option { lang_items::extract(attrs).and_then(|(name, _)| { - $(if name == stringify!($name) { - Some(Symbol::intern(stringify!($sym))) + $(if name == sym::$name { + Some(sym::$sym) } else)* { None } diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index 75e0f704a585..59b7891b90fd 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -78,7 +78,7 @@ pub struct Pointer { pub tag: Tag, } -static_assert!(POINTER_SIZE: ::std::mem::size_of::() == 16); +static_assert_size!(Pointer, 16); /// Produces a `Pointer` which points to the beginning of the Allocation impl From for Pointer { diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 7e45568725f3..551b86390db4 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -54,7 +54,7 @@ pub enum ConstValue<'tcx> { } #[cfg(target_arch = "x86_64")] -static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 40); +static_assert_size!(ConstValue<'_>, 40); impl<'tcx> ConstValue<'tcx> { #[inline] @@ -111,7 +111,7 @@ pub enum Scalar { } #[cfg(target_arch = "x86_64")] -static_assert!(SCALAR_SIZE: ::std::mem::size_of::() == 24); +static_assert_size!(Scalar, 24); impl fmt::Display for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index bd67aabfe8e5..dd43cb2f18ec 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1738,7 +1738,7 @@ pub struct Statement<'tcx> { // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::>() == 56); +static_assert_size!(Statement<'_>, 56); impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -1997,10 +1997,9 @@ pub type PlaceProjection<'tcx> = Projection, Local, Ty<'tcx>>; /// and the index is a local. pub type PlaceElem<'tcx> = ProjectionElem>; -// at least on 64 bit systems, `PlaceElem` should not be larger than two pointers -static_assert!(PROJECTION_ELEM_IS_2_PTRS_LARGE: - mem::size_of::>() <= 16 -); +// At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. +#[cfg(target_arch = "x86_64")] +static_assert_size!(PlaceElem<'_>, 16); /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index e82e90ede8c1..a26468b0fb6c 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -1,6 +1,6 @@ use crate::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; use crate::hir::HirId; -use syntax::symbol::{Symbol, InternedString}; +use syntax::symbol::InternedString; use crate::ty::{Instance, TyCtxt}; use crate::util::nodemap::FxHashMap; use rustc_data_structures::base_n; @@ -280,7 +280,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> { cgu_name } else { let cgu_name = &cgu_name.as_str()[..]; - Symbol::intern(&CodegenUnit::mangle_name(cgu_name)).as_interned_str() + InternedString::intern(&CodegenUnit::mangle_name(cgu_name)) } } @@ -336,6 +336,6 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> CodegenUnitNameBuilder<'a, 'gcx, 'tcx> { write!(cgu_name, ".{}", special_suffix).unwrap(); } - Symbol::intern(&cgu_name[..]).as_interned_str() + InternedString::intern(&cgu_name[..]) } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index d3fa5e84b6ad..5135aeb2392c 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -17,9 +17,9 @@ pub struct PlaceTy<'tcx> { pub variant_index: Option, } -static_assert!(PLACE_TY_IS_3_PTRS_LARGE: - mem::size_of::>() <= 24 -); +// At least on 64 bit systems, `PlaceTy` should not be larger than two or three pointers. +#[cfg(target_arch = "x86_64")] +static_assert_size!(PlaceTy<'_>, 16); impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index 0e7b66b74449..2fff4c3f109b 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -1052,7 +1052,7 @@ rustc_queries! { } Other { - query target_features_whitelist(_: CrateNum) -> Lrc>> { + query target_features_whitelist(_: CrateNum) -> Lrc>> { eval_always desc { "looking up the whitelist of target features" } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 12427daa3838..b5e3c4cda0a6 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1744,8 +1744,7 @@ pub fn rustc_short_optgroups() -> Vec { opt::multi_s( "", "print", - "Comma separated list of compiler information to \ - print on stdout", + "Compiler information to print on stdout", "[crate-name|file-names|sysroot|cfg|target-list|\ target-cpus|target-features|relocation-models|\ code-models|tls-models|target-spec-json|native-static-libs]", @@ -2753,6 +2752,7 @@ mod tests { // another --cfg test #[test] fn test_switch_implies_cfg_test_unless_cfg_test() { + use syntax::symbol::sym; syntax::with_globals(|| { let matches = &match optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]) { @@ -2763,7 +2763,7 @@ mod tests { let (sessopts, cfg) = build_session_options_and_crate_config(matches); let sess = build_session(sessopts, None, registry); let cfg = build_configuration(&sess, to_crate_config(cfg)); - let mut test_items = cfg.iter().filter(|&&(name, _)| name == "test"); + let mut test_items = cfg.iter().filter(|&&(name, _)| name == sym::test); assert!(test_items.next().is_some()); assert!(test_items.next().is_none()); }); diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index e8c7965ab4f4..4d47491661e8 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -29,6 +29,7 @@ use syntax::feature_gate::{self, AttributeType}; use syntax::json::JsonEmitter; use syntax::source_map; use syntax::parse::{self, ParseSess}; +use syntax::symbol::Symbol; use syntax_pos::{MultiSpan, Span}; use crate::util::profiling::SelfProfiler; @@ -86,7 +87,7 @@ pub struct Session { /// in order to avoid redundantly verbose output (Issue #24690, #44953). pub one_time_diagnostics: Lock, String)>>, pub plugin_llvm_passes: OneThread>>, - pub plugin_attributes: Lock>, + pub plugin_attributes: Lock>, pub crate_types: Once>, pub dependency_formats: Once, /// The crate_disambiguator is constructed out of all the `-C metadata` diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 35d8e2beef55..afbce5a4f0a4 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -4,17 +4,16 @@ //! [trait-resolution]: https://rust-lang.github.io/rustc-guide/traits/resolution.html //! [trait-specialization]: https://rust-lang.github.io/rustc-guide/traits/specialization.html -use crate::infer::CombinedSnapshot; +use crate::infer::{CombinedSnapshot, InferOk}; use crate::hir::def_id::{DefId, LOCAL_CRATE}; -use syntax_pos::DUMMY_SP; use crate::traits::{self, Normalized, SelectionContext, Obligation, ObligationCause}; use crate::traits::IntercrateMode; use crate::traits::select::IntercrateAmbiguityCause; use crate::ty::{self, Ty, TyCtxt}; use crate::ty::fold::TypeFoldable; use crate::ty::subst::Subst; - -use crate::infer::{InferOk}; +use syntax::symbol::sym; +use syntax_pos::DUMMY_SP; /// Whether we do the orphan check relative to this crate or /// to some remote crate. @@ -233,7 +232,7 @@ pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, pub fn trait_ref_is_local_or_fundamental<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, trait_ref: ty::TraitRef<'tcx>) -> bool { - trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, "fundamental") + trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental) } pub enum OrphanCheckErr<'tcx> { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d9ccbba69d5c..9019c4a0575d 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -35,6 +35,7 @@ use crate::util::nodemap::{FxHashMap, FxHashSet}; use errors::{Applicability, DiagnosticBuilder}; use std::fmt; use syntax::ast; +use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnFormat}; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { @@ -329,7 +330,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { return None }; - if tcx.has_attr(impl_def_id, "rustc_on_unimplemented") { + if tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented) { Some(impl_def_id) } else { None @@ -642,13 +643,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .map(|s| &s == "?") .unwrap_or(false); let is_from = format!("{}", trait_ref).starts_with("std::convert::From<"); - let message = if is_try && is_from { - Some(format!( + let (message, note) = if is_try && is_from { + (Some(format!( "`?` couldn't convert the error to `{}`", trait_ref.self_ty(), + )), Some( + "the question mark operation (`?`) implicitly performs a \ + conversion on the error value using the `From` trait".to_owned() )) } else { - message + (message, note) }; let mut err = struct_span_err!( diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 1c8ea5c7b9c5..55216f644a18 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -18,7 +18,8 @@ use crate::ty::{self, Ty, TyCtxt, TypeFoldable, Predicate, ToPredicate}; use crate::ty::subst::{Subst, InternalSubsts}; use std::borrow::Cow; use std::iter::{self}; -use syntax::ast::{self, Name}; +use syntax::ast::{self}; +use syntax::symbol::InternedString; use syntax_pos::Span; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -539,7 +540,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { // are implemented let unsized_self_ty: Ty<'tcx> = self.mk_ty_param( ::std::u32::MAX, - Name::intern("RustaceansAreAwesome").as_interned_str(), + InternedString::intern("RustaceansAreAwesome"), ); // `Receiver[Self => U]` diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 2b286ee1b97f..7ba7429f465a 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -7,6 +7,7 @@ use crate::util::nodemap::FxHashMap; use syntax::ast::{MetaItem, NestedMetaItem}; use syntax::attr; +use syntax::symbol::sym; use syntax_pos::Span; use syntax_pos::symbol::LocalInternedString; @@ -84,25 +85,25 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { let mut note = None; let mut subcommands = vec![]; for item in item_iter { - if item.check_name("message") && message.is_none() { + if item.check_name(sym::message) && message.is_none() { if let Some(message_) = item.value_str() { message = Some(OnUnimplementedFormatString::try_parse( tcx, trait_def_id, message_.as_str(), span)?); continue; } - } else if item.check_name("label") && label.is_none() { + } else if item.check_name(sym::label) && label.is_none() { if let Some(label_) = item.value_str() { label = Some(OnUnimplementedFormatString::try_parse( tcx, trait_def_id, label_.as_str(), span)?); continue; } - } else if item.check_name("note") && note.is_none() { + } else if item.check_name(sym::note) && note.is_none() { if let Some(note_) = item.value_str() { note = Some(OnUnimplementedFormatString::try_parse( tcx, trait_def_id, note_.as_str(), span)?); continue; } - } else if item.check_name("on") && is_root && + } else if item.check_name(sym::on) && is_root && message.is_none() && label.is_none() && note.is_none() { if let Some(items) = item.meta_item_list() { @@ -139,7 +140,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { { let attrs = tcx.get_attrs(impl_def_id); - let attr = if let Some(item) = attr::find_by_name(&attrs, "rustc_on_unimplemented") { + let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) { item } else { return Ok(None); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b5232e828c4c..67e76f7625ce 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -19,6 +19,7 @@ use crate::mir::interpret::{GlobalId, ConstValue}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use rustc_macros::HashStable; use syntax::ast::Ident; +use syntax::symbol::sym; use crate::ty::subst::{Subst, InternalSubsts}; use crate::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use crate::ty::fold::{TypeFoldable, TypeFolder}; @@ -1318,9 +1319,9 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( gen_sig) .map_bound(|(trait_ref, yield_ty, return_ty)| { let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; - let ty = if name == "Return" { + let ty = if name == sym::Return { return_ty - } else if name == "Yield" { + } else if name == sym::Yield { yield_ty } else { bug!() @@ -1420,7 +1421,7 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( projection_ty: ty::ProjectionTy::from_ref_and_name( tcx, trait_ref, - Ident::from_str(FN_OUTPUT_NAME), + Ident::with_empty_ctxt(FN_OUTPUT_NAME), ), ty: ret_type } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index d68e2be9ea08..c4be85050dbc 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -43,6 +43,7 @@ use crate::hir; use rustc_data_structures::bit_set::GrowableBitSet; use rustc_data_structures::sync::Lock; use rustc_target::spec::abi::Abi; +use std::cell::Cell; use std::cmp; use std::fmt::{self, Display}; use std::iter; @@ -153,6 +154,36 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// selection-context's freshener. Used to check for recursion. fresh_trait_ref: ty::PolyTraitRef<'tcx>, + /// Starts out as false -- if, during evaluation, we encounter a + /// cycle, then we will set this flag to true for all participants + /// in the cycle (apart from the "head" node). These participants + /// will then forego caching their results. This is not the most + /// efficient solution, but it addresses #60010. The problem we + /// are trying to prevent: + /// + /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait` + /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok) + /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok) + /// + /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` + /// is `EvaluatedToOk`; this is because they were only considered + /// ok on the premise that if `A: AutoTrait` held, but we indeed + /// encountered a problem (later on) with `A: AutoTrait. So we + /// currently set a flag on the stack node for `B: AutoTrait` (as + /// well as the second instance of `A: AutoTrait`) to supress + /// caching. + /// + /// This is a simple, targeted fix. A more-performant fix requires + /// deeper changes, but would permit more caching: we could + /// basically defer caching until we have fully evaluated the + /// tree, and then cache the entire tree at once. In any case, the + /// performance impact here shouldn't be so horrible: every time + /// this is hit, we do cache at least one trait, so we only + /// evaluate each member of a cycle up to N times, where N is the + /// length of the cycle. This means the performance impact is + /// bounded and we shouldn't have any terrible worst-cases. + in_cycle: Cell, + previous: TraitObligationStackList<'prev, 'tcx>, } @@ -840,8 +871,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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); + if !stack.in_cycle.get() { + debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); + self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); + } else { + debug!( + "evaluate_trait_predicate_recursively: skipping cache because {:?} \ + is a cycle participant", + fresh_trait_ref, + ); + } Ok(result) } @@ -948,6 +987,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { { debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref); + // If we have a stack like `A B C D E A`, where the top of + // the stack is the final `A`, then this will iterate over + // `A, E, D, C, B` -- i.e., all the participants apart + // from the cycle head. We mark them as participating in a + // cycle. This suppresses caching for those nodes. See + // `in_cycle` field for more details. + for item in stack.iter().take(rec_index + 1) { + debug!("evaluate_stack: marking {:?} as cycle participant", item.fresh_trait_ref); + item.in_cycle.set(true); + } + // Subtle: when checking for a coinductive cycle, we do // not compare using the "freshened trait refs" (which // have erased regions) but rather the fully explicit @@ -3690,6 +3740,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { TraitObligationStack { obligation, fresh_trait_ref, + in_cycle: Cell::new(false), previous: previous_stack, } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 2496419640c2..fdd1a821e31b 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -298,7 +298,7 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>( // negated `CrateNum` (so remote definitions are visited first) and then // by a flattened version of the `DefIndex`. trait_impls.sort_unstable_by_key(|def_id| { - (-(def_id.krate.as_u32() as i64), def_id.index.as_array_index()) + (-(def_id.krate.as_u32() as i64), def_id.index.index()) }); for impl_def_id in trait_impls { @@ -319,29 +319,34 @@ pub(super) fn specialization_graph_provider<'a, 'tcx>( String::new(), |ty| { format!(" for type `{}`", ty) }), - if used_to_be_allowed.is_some() { " (E0119)" } else { "" } + match used_to_be_allowed { + Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)", + _ => "", + } ); let impl_span = tcx.sess.source_map().def_span( tcx.span_of_impl(impl_def_id).unwrap() ); - let mut err = if let Some(kind) = used_to_be_allowed { - let lint = match kind { - FutureCompatOverlapErrorKind::Issue43355 => - lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS, - FutureCompatOverlapErrorKind::Issue33140 => - lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS, - }; - tcx.struct_span_lint_hir( - lint, - tcx.hir().as_local_hir_id(impl_def_id).unwrap(), - impl_span, - &msg) - } else { - struct_span_err!(tcx.sess, - impl_span, - E0119, - "{}", - msg) + let mut err = match used_to_be_allowed { + Some(FutureCompatOverlapErrorKind::Issue43355) | None => + struct_span_err!(tcx.sess, + impl_span, + E0119, + "{}", + msg), + Some(kind) => { + let lint = match kind { + FutureCompatOverlapErrorKind::Issue43355 => + unreachable!("converted to hard error above"), + FutureCompatOverlapErrorKind::Issue33140 => + lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS, + }; + tcx.struct_span_lint_hir( + lint, + tcx.hir().as_local_hir_id(impl_def_id).unwrap(), + impl_span, + &msg) + } }; match tcx.span_of_impl(overlap.with_impl) { diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 400a0f526c4e..404fadbc78af 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -312,17 +312,15 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { } fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - use syntax::symbol::Symbol; - match t.sty { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { self.types.insert( bound_ty.var.as_u32(), match bound_ty.kind { ty::BoundTyKind::Param(name) => name, - ty::BoundTyKind::Anon => Symbol::intern( - &format!("^{}", bound_ty.var.as_u32()) - ).as_interned_str(), + ty::BoundTyKind::Anon => + InternedString::intern(&format!("^{}", bound_ty.var.as_u32()), + ), } ); } @@ -334,8 +332,6 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { } fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - use syntax::symbol::Symbol; - match r { ty::ReLateBound(index, br) if *index == self.binder_index => { match br { @@ -344,9 +340,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector { } ty::BoundRegion::BrAnon(var) => { - self.regions.insert(Symbol::intern( - &format!("'^{}", var) - ).as_interned_str()); + self.regions.insert(InternedString::intern(&format!("'^{}", var))); } _ => (), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 15524ca6e930..c9fee02f66bb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -74,7 +74,7 @@ use syntax::ast; use syntax::attr; use syntax::source_map::MultiSpan; use syntax::feature_gate; -use syntax::symbol::{Symbol, keywords, InternedString}; +use syntax::symbol::{Symbol, keywords, InternedString, sym}; use syntax_pos::Span; use crate::hir; @@ -1213,7 +1213,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } span_bug!(attr.span, "no arguments to `rustc_layout_scalar_valid_range` attribute"); }; - (get("rustc_layout_scalar_valid_range_start"), get("rustc_layout_scalar_valid_range_end")) + (get(sym::rustc_layout_scalar_valid_range_start), + get(sym::rustc_layout_scalar_valid_range_end)) } pub fn lift>(self, value: &T) -> Option { @@ -3102,10 +3103,10 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { }; providers.is_panic_runtime = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - attr::contains_name(tcx.hir().krate_attrs(), "panic_runtime") + attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime) }; providers.is_compiler_builtins = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); - attr::contains_name(tcx.hir().krate_attrs(), "compiler_builtins") + attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins) }; } diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 197d3325f51c..be1d973c2cdd 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -113,9 +113,14 @@ impl<'a, 'gcx, 'tcx> AdtDef { tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest { - DefIdForest::intersection(tcx, self.variants.iter().map(|v| { - v.uninhabited_from(tcx, substs, self.adt_kind()) - })) + // Non-exhaustive ADTs from other crates are always considered inhabited. + if self.is_variant_list_non_exhaustive() && !self.did.is_local() { + DefIdForest::empty() + } else { + DefIdForest::intersection(tcx, self.variants.iter().map(|v| { + v.uninhabited_from(tcx, substs, self.adt_kind()) + })) + } } } @@ -134,9 +139,14 @@ impl<'a, 'gcx, 'tcx> VariantDef { AdtKind::Enum => true, AdtKind::Struct => false, }; - DefIdForest::union(tcx, self.fields.iter().map(|f| { - f.uninhabited_from(tcx, substs, is_enum) - })) + // Non-exhaustive variants from other crates are always considered inhabited. + if self.is_field_list_non_exhaustive() && !self.def_id.is_local() { + DefIdForest::empty() + } else { + DefIdForest::union(tcx, self.fields.iter().map(|f| { + f.uninhabited_from(tcx, substs, is_enum) + })) + } } } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index d1a8a9a34e15..6d7b0926c7ae 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -19,6 +19,12 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; pub use rustc_target::abi::*; +use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi}; +use rustc_target::abi::call::{ + ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind +}; + + pub trait IntegerExt { fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx>; @@ -2259,3 +2265,380 @@ impl<'a, 'gcx> HashStable> for LayoutError<'gcx> } } } + +pub trait FnTypeExt<'tcx, C> +where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, +{ + fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self; + fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; + fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; + fn new_internal( + cx: &C, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self; + fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi); +} + +impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>> +where + C: LayoutOf, TyLayout = TyLayout<'tcx>> + + HasDataLayout + + HasTargetSpec + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, +{ + fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self { + let sig = instance.fn_sig(cx.tcx()); + let sig = cx + .tcx() + .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + call::FnType::new(cx, sig, &[]) + } + + fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { + call::FnType::new_internal(cx, sig, extra_args, |ty, _| ArgType::new(cx.layout_of(ty))) + } + + fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { + FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| { + let mut layout = cx.layout_of(ty); + // Don't pass the vtable, it's not an argument of the virtual fn. + // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` + // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen + if arg_idx == Some(0) { + let fat_pointer_ty = if layout.is_unsized() { + // unsized `self` is passed as a pointer to `self` + // FIXME (mikeyhew) change this to use &own if it is ever added to the language + cx.tcx().mk_mut_ptr(layout.ty) + } else { + match layout.abi { + Abi::ScalarPair(..) => (), + _ => bug!("receiver type has unsupported layout: {:?}", layout), + } + + // In the case of Rc, we need to explicitly pass a *mut RcBox + // with a Scalar (not ScalarPair) ABI. This is a hack that is understood + // elsewhere in the compiler as a method on a `dyn Trait`. + // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we + // get a built-in pointer type + let mut fat_pointer_layout = layout; + 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() + && !fat_pointer_layout.ty.is_region_ptr() + { + 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { + let field_layout = fat_pointer_layout.field(cx, i); + + if !field_layout.is_zst() { + fat_pointer_layout = field_layout; + continue 'descend_newtypes; + } + } + + bug!( + "receiver has no non-zero-sized fields {:?}", + fat_pointer_layout + ); + } + + fat_pointer_layout.ty + }; + + // we now have a type like `*mut RcBox` + // change its layout to that of `*mut ()`, a thin pointer, but keep the same type + // this is understood as a special case elsewhere in the compiler + let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit()); + layout = cx.layout_of(unit_pointer_ty); + layout.ty = fat_pointer_ty; + } + ArgType::new(layout) + }) + } + + fn new_internal( + cx: &C, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self { + debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); + + use rustc_target::spec::abi::Abi::*; + let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) { + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C, + + // It's the ABI's job to select this, not ours. + System => bug!("system abi should be selected elsewhere"), + + 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, + AmdGpuKernel => Conv::AmdGpuKernel, + + // These API constants ought to be more specific... + Cdecl => Conv::C, + }; + + let mut inputs = sig.inputs(); + let extra_args = if sig.abi == RustCall { + assert!(!sig.c_variadic && extra_args.is_empty()); + + match sig.inputs().last().unwrap().sty { + ty::Tuple(tupled_arguments) => { + inputs = &sig.inputs()[0..sig.inputs().len() - 1]; + tupled_arguments.iter().map(|k| k.expect_ty()).collect() + } + _ => { + bug!( + "argument to function with \"rust-call\" ABI \ + is not a tuple" + ); + } + } + } else { + assert!(sig.c_variadic || extra_args.is_empty()); + extra_args.to_vec() + }; + + let target = &cx.tcx().sess.target.target; + let win_x64_gnu = + target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; + let linux_s390x = + target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu"; + let linux_sparc64 = + target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu"; + let rust_abi = match sig.abi { + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, + _ => false, + }; + + // Handle safe Rust thin and fat pointers. + let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, + scalar: &Scalar, + layout: TyLayout<'tcx>, + offset: Size, + is_return: bool| { + // Booleans are always an i1 that needs to be zero-extended. + if scalar.is_bool() { + attrs.set(ArgAttribute::ZExt); + return; + } + + // Only pointer types handled below. + if scalar.value != Pointer { + return; + } + + if scalar.valid_range.start() < scalar.valid_range.end() { + if *scalar.valid_range.start() > 0 { + attrs.set(ArgAttribute::NonNull); + } + } + + if let Some(pointee) = layout.pointee_info_at(cx, offset) { + if let Some(kind) = pointee.safe { + attrs.pointee_size = pointee.size; + attrs.pointee_align = Some(pointee.align); + + // `Box` pointer parameters never alias because ownership is transferred + // `&mut` pointer parameters never alias other parameters, + // or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, + // and can be marked as both `readonly` and `noalias`, as + // LLVM's definition of `noalias` is based solely on memory + // dependencies rather than pointer equality + let no_alias = match kind { + PointerKind::Shared => false, + PointerKind::UniqueOwned => true, + PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return, + }; + if no_alias { + attrs.set(ArgAttribute::NoAlias); + } + + if kind == PointerKind::Frozen && !is_return { + attrs.set(ArgAttribute::ReadOnly); + } + } + } + }; + + // Store the index of the last argument. This is useful for working with + // C-compatible variadic arguments. + let last_arg_idx = if sig.inputs().is_empty() { + None + } else { + Some(sig.inputs().len() - 1) + }; + + let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { + let is_return = arg_idx.is_none(); + let mut arg = mk_arg_type(ty, arg_idx); + if arg.layout.is_zst() { + // For some forsaken reason, x86_64-pc-windows-gnu + // doesn't ignore zero-sized struct arguments. + // The same is true for s390x-unknown-linux-gnu + // and sparc64-unknown-linux-gnu. + if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { + arg.mode = PassMode::Ignore(IgnoreMode::Zst); + } + } + + // If this is a C-variadic function, this is not the return value, + // and there is one or more fixed arguments; ensure that the `VaList` + // is ignored as an argument. + if sig.c_variadic { + match (last_arg_idx, arg_idx) { + (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { + let va_list_did = match cx.tcx().lang_items().va_list() { + Some(did) => did, + None => bug!("`va_list` lang item required for C-variadic functions"), + }; + match ty.sty { + ty::Adt(def, _) if def.did == va_list_did => { + // This is the "spoofed" `VaList`. Set the arguments mode + // so that it will be ignored. + arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); + } + _ => (), + } + } + _ => {} + } + } + + // FIXME(eddyb) other ABIs don't have logic for scalar pairs. + if !is_return && rust_abi { + if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi { + let mut a_attrs = ArgAttributes::new(); + let mut b_attrs = ArgAttributes::new(); + adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false); + adjust_for_rust_scalar( + &mut b_attrs, + b, + arg.layout, + a.value.size(cx).align_to(b.value.align(cx).abi), + false, + ); + arg.mode = PassMode::Pair(a_attrs, b_attrs); + return arg; + } + } + + if let Abi::Scalar(ref scalar) = arg.layout.abi { + if let PassMode::Direct(ref mut attrs) = arg.mode { + adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return); + } + } + + arg + }; + + let mut fn_ty = FnType { + ret: arg_of(sig.output(), None), + args: inputs + .iter() + .cloned() + .chain(extra_args) + .enumerate() + .map(|(i, ty)| arg_of(ty, Some(i))) + .collect(), + c_variadic: sig.c_variadic, + conv, + }; + fn_ty.adjust_for_abi(cx, sig.abi); + fn_ty + } + + fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) { + if abi == SpecAbi::Unadjusted { + return; + } + + if abi == SpecAbi::Rust + || abi == SpecAbi::RustCall + || abi == SpecAbi::RustIntrinsic + || abi == SpecAbi::PlatformIntrinsic + { + let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { + if arg.is_ignore() { + return; + } + + match arg.layout.abi { + Abi::Aggregate { .. } => {} + + // This is a fun case! The gist of what this is doing is + // that we want callers and callees to always agree on the + // ABI of how they pass SIMD arguments. If we were to *not* + // make these arguments indirect then they'd be immediates + // in LLVM, which means that they'd used whatever the + // appropriate ABI is for the callee and the caller. That + // means, for example, if the caller doesn't have AVX + // enabled but the callee does, then passing an AVX argument + // across this boundary would cause corrupt data to show up. + // + // This problem is fixed by unconditionally passing SIMD + // arguments through memory between callers and callees + // which should get them all to agree on ABI regardless of + // target feature sets. Some more information about this + // issue can be found in #44367. + // + // Note that the platform intrinsic ABI is exempt here as + // that's how we connect up to LLVM and it's unstable + // anyway, we control all calls to it in libstd. + Abi::Vector { .. } + if abi != SpecAbi::PlatformIntrinsic + && cx.tcx().sess.target.target.options.simd_types_indirect => + { + arg.make_indirect(); + return; + } + + _ => return, + } + + let size = arg.layout.size; + if arg.layout.is_unsized() || size > Pointer.size(cx) { + arg.make_indirect(); + } else { + // We want to pass small aggregates as immediates, but using + // a LLVM aggregate type for this leads to bad optimizations, + // so we pick an appropriately sized integer type instead. + arg.cast_to(Reg { + kind: RegKind::Integer, + size, + }); + } + }; + fixup(&mut self.ret); + for arg in &mut self.args { + fixup(arg); + } + if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { + attrs.set(ArgAttribute::StructRet); + } + return; + } + + if let Err(msg) = self.adjust_for_cabi(cx, abi) { + cx.tcx().sess.fatal(&msg); + } + } +} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 7b749957c3ff..91e996178e7d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -47,7 +47,7 @@ use std::ops::Range; use syntax::ast::{self, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; -use syntax::symbol::{keywords, Symbol, LocalInternedString, InternedString}; +use syntax::symbol::{keywords, sym, Symbol, LocalInternedString, InternedString}; use syntax_pos::Span; use smallvec; @@ -510,7 +510,7 @@ pub struct TyS<'tcx> { // `TyS` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_TY_S: ::std::mem::size_of::>() == 32); +static_assert_size!(TyS<'_>, 32); impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { @@ -1875,11 +1875,11 @@ impl<'a, 'gcx, 'tcx> VariantDef { ); let mut flags = VariantFlags::NO_VARIANT_FLAGS; - if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, "non_exhaustive") { + if adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) { debug!("found non-exhaustive field list for {:?}", parent_did); flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; } else if let Some(variant_did) = variant_did { - if tcx.has_attr(variant_did, "non_exhaustive") { + if tcx.has_attr(variant_did, sym::non_exhaustive) { debug!("found non-exhaustive field list for {:?}", variant_did); flags = flags | VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; } @@ -2156,7 +2156,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { debug!("AdtDef::new({:?}, {:?}, {:?}, {:?})", did, kind, variants, repr); let mut flags = AdtFlags::NO_ADT_FLAGS; - if kind == AdtKind::Enum && tcx.has_attr(did, "non_exhaustive") { + if kind == AdtKind::Enum && tcx.has_attr(did, sym::non_exhaustive) { debug!("found non-exhaustive variant list for {:?}", did); flags = flags | AdtFlags::IS_VARIANT_LIST_NON_EXHAUSTIVE; } @@ -2172,7 +2172,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } let attrs = tcx.get_attrs(did); - if attr::contains_name(&attrs, "fundamental") { + if attr::contains_name(&attrs, sym::fundamental) { flags |= AdtFlags::IS_FUNDAMENTAL; } if Some(did) == tcx.lang_items().phantom_data() { @@ -3030,7 +3030,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Determines whether an item is annotated with an attribute. - pub fn has_attr(self, did: DefId, attr: &str) -> bool { + pub fn has_attr(self, did: DefId, attr: Symbol) -> bool { attr::contains_name(&self.get_attrs(did), attr) } @@ -3405,7 +3405,7 @@ impl_stable_hash_for!(struct self::SymbolName { impl SymbolName { pub fn new(name: &str) -> SymbolName { SymbolName { - name: Symbol::intern(name).as_interned_str() + name: InternedString::intern(name) } } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 8e98d4d85b9c..91b708d7dbe1 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -7,10 +7,8 @@ use crate::middle::region; use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable}; use crate::ty::subst::{Kind, Subst, UnpackedKind}; use crate::mir::interpret::ConstValue; -use syntax::symbol::{keywords, Symbol}; - use rustc_target::spec::abi::Abi; -use syntax::symbol::InternedString; +use syntax::symbol::{keywords, InternedString}; use std::cell::Cell; use std::fmt::{self, Write as _}; @@ -1285,10 +1283,10 @@ impl FmtPrinter<'_, 'gcx, 'tcx, F> { { fn name_by_region_index(index: usize) -> InternedString { match index { - 0 => Symbol::intern("'r"), - 1 => Symbol::intern("'s"), - i => Symbol::intern(&format!("'t{}", i-2)), - }.as_interned_str() + 0 => InternedString::intern("'r"), + 1 => InternedString::intern("'s"), + i => InternedString::intern(&format!("'t{}", i-2)), + } } // Replace any anonymous late-bound regions with named diff --git a/src/librustc/ty/query/values.rs b/src/librustc/ty/query/values.rs index a4b8d365a12e..2fb318a47bef 100644 --- a/src/librustc/ty/query/values.rs +++ b/src/librustc/ty/query/values.rs @@ -1,7 +1,7 @@ use crate::ty::{self, Ty, TyCtxt, AdtSizedConstraint}; use crate::ty::util::NeedsDrop; -use syntax::symbol::Symbol; +use syntax::symbol::InternedString; pub(super) trait Value<'tcx>: Sized { fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self; @@ -28,7 +28,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("").as_interned_str() } + ty::SymbolName { name: InternedString::intern("") } } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 760f3d60d057..e8f3bad4d3ee 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -211,7 +211,7 @@ pub enum TyKind<'tcx> { // `TyKind` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_TY_KIND: ::std::mem::size_of::>() == 24); +static_assert_size!(TyKind<'_>, 24); /// A closure can be modeled as a struct that looks like: /// @@ -1136,7 +1136,7 @@ impl<'a, 'gcx, 'tcx> ParamTy { // FIXME(#50125): Ignoring `Self` with `index != 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`. - self.name == keywords::SelfUpper.name().as_str() && self.index == 0 + self.name.as_symbol() == keywords::SelfUpper.name() && self.index == 0 } } @@ -2207,7 +2207,7 @@ pub struct Const<'tcx> { } #[cfg(target_arch = "x86_64")] -static_assert!(CONST_SIZE: ::std::mem::size_of::>() == 48); +static_assert_size!(Const<'_>, 48); impl<'tcx> Const<'tcx> { #[inline] diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 4c8ed71a57ca..926c0f8b9491 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -22,6 +22,7 @@ use rustc_macros::HashStable; use std::{cmp, fmt}; use syntax::ast; use syntax::attr::{self, SignedInt, UnsignedInt}; +use syntax::symbol::sym; use syntax_pos::{Span, DUMMY_SP}; #[derive(Copy, Clone, Debug)] @@ -447,7 +448,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Such access can be in plain sight (e.g., dereferencing // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden // (e.g., calling `foo.0.clone()` of `Foo`). - if self.has_attr(dtor, "unsafe_destructor_blind_to_params") { + if self.has_attr(dtor, sym::unsafe_destructor_blind_to_params) { debug!("destructor_constraint({:?}) - blind", def.did); return vec![]; } diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 26194176350a..67eaa19c080b 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -11,6 +11,7 @@ use std::time::{Duration, Instant}; use std::sync::mpsc::{Sender}; use syntax_pos::{SpanData}; +use syntax::symbol::{Symbol, sym}; use rustc_macros::HashStable; use crate::ty::TyCtxt; use crate::dep_graph::{DepNode}; @@ -18,7 +19,7 @@ use lazy_static; use crate::session::Session; // The name of the associated type for `Fn` return types -pub const FN_OUTPUT_NAME: &str = "Output"; +pub const FN_OUTPUT_NAME: Symbol = sym::Output; // Useful type to use with `Result<>` indicate that an error has already // been reported to the user, so no need to continue checking. diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 758a0d63886b..6931b3542f76 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -19,7 +19,7 @@ use syntax::{ mut_visit::{self, MutVisitor}, parse::ParseSess, ptr::P, - symbol::Symbol + symbol::{keywords, Symbol, sym} }; use syntax_pos::Span; @@ -58,7 +58,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { debug!("in submodule {}", self.in_submod); - let name = if attr::contains_name(&item.attrs, "global_allocator") { + let name = if attr::contains_name(&item.attrs, sym::global_allocator) { "global_allocator" } else { return mut_visit::noop_flat_map_item(item, self); @@ -110,13 +110,14 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { span, kind: AllocatorKind::Global, global: item.ident, - core: Ident::from_str("core"), + core: Ident::with_empty_ctxt(sym::core), cx: ExtCtxt::new(self.sess, ecfg, self.resolver), }; // We will generate a new submodule. To `use` the static from that module, we need to get // the `super::...` path. - 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::with_empty_ctxt(keywords::Super.name()), f.global]); // Generate the items in the submodule let mut items = vec![ @@ -139,7 +140,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { // Generate the submodule itself let name = f.kind.fn_name("allocator_abi"); - let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name)); + let allocator_abi = Ident::from_str(&name).gensym(); let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); let module = f.cx.monotonic_expander().flat_map_item(module).pop().unwrap(); @@ -236,7 +237,7 @@ impl AllocFnFactory<'_> { ) -> P { match *ty { AllocatorTy::Layout => { - let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); let ty_usize = self.cx.ty_path(usize); let size = ident(); let align = ident(); @@ -298,12 +299,12 @@ impl AllocFnFactory<'_> { } fn usize(&self) -> P { - let usize = self.cx.path_ident(self.span, Ident::from_str("usize")); + let usize = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::usize)); self.cx.ty_path(usize) } fn ptr_u8(&self) -> P { - let u8 = self.cx.path_ident(self.span, Ident::from_str("u8")); + let u8 = self.cx.path_ident(self.span, Ident::with_empty_ctxt(sym::u8)); let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 70d184240fcc..38d4b7e3f9d8 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -11,9 +11,9 @@ use rustc_target::abi::call::ArgType; use rustc_codegen_ssa::traits::*; -use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi}; -use rustc::ty::{self, Ty, Instance}; -use rustc::ty::layout::{self, PointerKind}; +use rustc_target::abi::{HasDataLayout, LayoutOf}; +use rustc::ty::{Ty}; +use rustc::ty::layout::{self}; use libc::c_uint; @@ -294,23 +294,7 @@ impl ArgTypeMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -pub trait FnTypeExt<'tcx> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self; - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self; - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'ll, 'tcx>, - abi: Abi); +pub trait FnTypeLlvmExt<'tcx> { fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type; fn llvm_cconv(&self) -> llvm::CallConv; @@ -318,356 +302,7 @@ pub trait FnTypeExt<'tcx> { fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value); } -impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { - fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self { - let sig = instance.fn_sig(cx.tcx); - let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - FnType::new(cx, sig, &[]) - } - - fn new(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnType::new_internal(cx, sig, extra_args, |ty, _| { - ArgType::new(cx.layout_of(ty)) - }) - } - - fn new_vtable(cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| { - let mut layout = cx.layout_of(ty); - // Don't pass the vtable, it's not an argument of the virtual fn. - // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` - // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen - if arg_idx == Some(0) { - let fat_pointer_ty = if layout.is_unsized() { - // unsized `self` is passed as a pointer to `self` - // FIXME (mikeyhew) change this to use &own if it is ever added to the language - cx.tcx.mk_mut_ptr(layout.ty) - } else { - match layout.abi { - LayoutAbi::ScalarPair(..) => (), - _ => bug!("receiver type has unsupported layout: {:?}", layout) - } - - // In the case of Rc, we need to explicitly pass a *mut RcBox - // with a Scalar (not ScalarPair) ABI. This is a hack that is understood - // elsewhere in the compiler as a method on a `dyn Trait`. - // To get the type `*mut RcBox`, we just keep unwrapping newtypes until we - // get a built-in pointer type - let mut fat_pointer_layout = layout; - 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr() - && !fat_pointer_layout.ty.is_region_ptr() - { - 'iter_fields: for i in 0..fat_pointer_layout.fields.count() { - let field_layout = fat_pointer_layout.field(cx, i); - - if !field_layout.is_zst() { - fat_pointer_layout = field_layout; - continue 'descend_newtypes - } - } - - bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout); - } - - fat_pointer_layout.ty - }; - - // we now have a type like `*mut RcBox` - // change its layout to that of `*mut ()`, a thin pointer, but keep the same type - // this is understood as a special case elsewhere in the compiler - let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit()); - layout = cx.layout_of(unit_pointer_ty); - layout.ty = fat_pointer_ty; - } - ArgType::new(layout) - }) - } - - fn new_internal( - cx: &CodegenCx<'ll, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>], - mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, - ) -> Self { - debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); - - use self::Abi::*; - let conv = match cx.sess().target.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | - Rust | RustCall => Conv::C, - - // It's the ABI's job to select this, not ours. - System => bug!("system abi should be selected elsewhere"), - - 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, - AmdGpuKernel => Conv::AmdGpuKernel, - - // These API constants ought to be more specific... - Cdecl => Conv::C, - }; - - let mut inputs = sig.inputs(); - let extra_args = if sig.abi == RustCall { - assert!(!sig.c_variadic && extra_args.is_empty()); - - match sig.inputs().last().unwrap().sty { - ty::Tuple(tupled_arguments) => { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments.iter().map(|k| k.expect_ty()).collect() - } - _ => { - bug!("argument to function with \"rust-call\" ABI \ - is not a tuple"); - } - } - } else { - assert!(sig.c_variadic || extra_args.is_empty()); - extra_args.to_vec() - }; - - let target = &cx.sess().target.target; - let win_x64_gnu = target.target_os == "windows" - && target.arch == "x86_64" - && target.target_env == "gnu"; - let linux_s390x = target.target_os == "linux" - && target.arch == "s390x" - && target.target_env == "gnu"; - let linux_sparc64 = target.target_os == "linux" - && target.arch == "sparc64" - && target.target_env == "gnu"; - let rust_abi = match sig.abi { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, - _ => false - }; - - // Handle safe Rust thin and fat pointers. - let adjust_for_rust_scalar = |attrs: &mut ArgAttributes, - scalar: &layout::Scalar, - layout: TyLayout<'tcx, Ty<'tcx>>, - offset: Size, - is_return: bool| { - // Booleans are always an i1 that needs to be zero-extended. - if scalar.is_bool() { - attrs.set(ArgAttribute::ZExt); - return; - } - - // Only pointer types handled below. - if scalar.value != layout::Pointer { - return; - } - - if scalar.valid_range.start() < scalar.valid_range.end() { - if *scalar.valid_range.start() > 0 { - attrs.set(ArgAttribute::NonNull); - } - } - - if let Some(pointee) = layout.pointee_info_at(cx, offset) { - if let Some(kind) = pointee.safe { - attrs.pointee_size = pointee.size; - attrs.pointee_align = Some(pointee.align); - - // `Box` pointer parameters never alias because ownership is transferred - // `&mut` pointer parameters never alias other parameters, - // or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, - // and can be marked as both `readonly` and `noalias`, as - // LLVM's definition of `noalias` is based solely on memory - // dependencies rather than pointer equality - let no_alias = match kind { - PointerKind::Shared => false, - PointerKind::UniqueOwned => true, - PointerKind::Frozen | - PointerKind::UniqueBorrowed => !is_return - }; - if no_alias { - attrs.set(ArgAttribute::NoAlias); - } - - if kind == PointerKind::Frozen && !is_return { - attrs.set(ArgAttribute::ReadOnly); - } - } - } - }; - - // Store the index of the last argument. This is useful for working with - // C-compatible variadic arguments. - let last_arg_idx = if sig.inputs().is_empty() { - None - } else { - Some(sig.inputs().len() - 1) - }; - - let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { - let is_return = arg_idx.is_none(); - let mut arg = mk_arg_type(ty, arg_idx); - if arg.layout.is_zst() { - // For some forsaken reason, x86_64-pc-windows-gnu - // doesn't ignore zero-sized struct arguments. - // The same is true for s390x-unknown-linux-gnu - // and sparc64-unknown-linux-gnu. - if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) { - arg.mode = PassMode::Ignore(IgnoreMode::Zst); - } - } - - // If this is a C-variadic function, this is not the return value, - // and there is one or more fixed arguments; ensure that the `VaList` - // is ignored as an argument. - if sig.c_variadic { - match (last_arg_idx, arg_idx) { - (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => { - let va_list_did = match cx.tcx.lang_items().va_list() { - Some(did) => did, - None => bug!("`va_list` lang item required for C-variadic functions"), - }; - match ty.sty { - ty::Adt(def, _) if def.did == va_list_did => { - // This is the "spoofed" `VaList`. Set the arguments mode - // so that it will be ignored. - arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs); - }, - _ => (), - } - } - _ => {} - } - } - - // FIXME(eddyb) other ABIs don't have logic for scalar pairs. - if !is_return && rust_abi { - if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi { - let mut a_attrs = ArgAttributes::new(); - let mut b_attrs = ArgAttributes::new(); - adjust_for_rust_scalar(&mut a_attrs, - a, - arg.layout, - Size::ZERO, - false); - adjust_for_rust_scalar(&mut b_attrs, - b, - arg.layout, - a.value.size(cx).align_to(b.value.align(cx).abi), - false); - arg.mode = PassMode::Pair(a_attrs, b_attrs); - return arg; - } - } - - if let layout::Abi::Scalar(ref scalar) = arg.layout.abi { - if let PassMode::Direct(ref mut attrs) = arg.mode { - adjust_for_rust_scalar(attrs, - scalar, - arg.layout, - Size::ZERO, - is_return); - } - } - - arg - }; - - let mut fn_ty = FnType { - ret: arg_of(sig.output(), None), - args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| { - arg_of(ty, Some(i)) - }).collect(), - c_variadic: sig.c_variadic, - conv, - }; - fn_ty.adjust_for_abi(cx, sig.abi); - fn_ty - } - - fn adjust_for_abi(&mut self, - cx: &CodegenCx<'ll, 'tcx>, - abi: Abi) { - if abi == Abi::Unadjusted { return } - - if abi == Abi::Rust || abi == Abi::RustCall || - abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic { - let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| { - if arg.is_ignore() { return; } - - match arg.layout.abi { - layout::Abi::Aggregate { .. } => {} - - // This is a fun case! The gist of what this is doing is - // that we want callers and callees to always agree on the - // ABI of how they pass SIMD arguments. If we were to *not* - // make these arguments indirect then they'd be immediates - // in LLVM, which means that they'd used whatever the - // appropriate ABI is for the callee and the caller. That - // means, for example, if the caller doesn't have AVX - // enabled but the callee does, then passing an AVX argument - // across this boundary would cause corrupt data to show up. - // - // This problem is fixed by unconditionally passing SIMD - // arguments through memory between callers and callees - // which should get them all to agree on ABI regardless of - // target feature sets. Some more information about this - // issue can be found in #44367. - // - // Note that the platform intrinsic ABI is exempt here as - // that's how we connect up to LLVM and it's unstable - // anyway, we control all calls to it in libstd. - layout::Abi::Vector { .. } - if abi != Abi::PlatformIntrinsic && - cx.sess().target.target.options.simd_types_indirect => - { - arg.make_indirect(); - return - } - - _ => return - } - - let size = arg.layout.size; - if arg.layout.is_unsized() || size > layout::Pointer.size(cx) { - arg.make_indirect(); - } else { - // We want to pass small aggregates as immediates, but using - // a LLVM aggregate type for this leads to bad optimizations, - // so we pick an appropriately sized integer type instead. - arg.cast_to(Reg { - kind: RegKind::Integer, - size - }); - } - }; - fixup(&mut self.ret); - for arg in &mut self.args { - fixup(arg); - } - if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { - attrs.set(ArgAttribute::StructRet); - } - return; - } - - if let Err(msg) = self.adjust_for_cabi(cx, abi) { - cx.sess().fatal(&msg); - } - } - +impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> { fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type { let args_capacity: usize = self.args.iter().map(|arg| if arg.pad.is_some() { 1 } else { 0 } + @@ -836,22 +471,6 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> { } } -impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> { - FnType::new(&self, sig, extra_args) - } - fn new_vtable( - &self, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>] - ) -> FnType<'tcx, Ty<'tcx>> { - FnType::new_vtable(&self, sig, extra_args) - } - fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> { - FnType::of_instance(&self, instance) - } -} - impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { fn apply_attrs_callsite( &mut self, diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index b15a64c966b1..f26684d9ef04 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -321,12 +321,12 @@ pub fn provide(providers: &mut Providers<'_>) { // rustdoc needs to be able to document functions that use all the features, so // whitelist them all Lrc::new(llvm_util::all_known_features() - .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string()))) + .map(|(a, b)| (a.to_string(), b)) .collect()) } else { Lrc::new(llvm_util::target_feature_whitelist(tcx.sess) .iter() - .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string()))) + .map(|&(a, b)| (a.to_string(), b)) .collect()) } }; diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index cb59cf41a3ca..66ba95810a62 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -795,10 +795,10 @@ fn create_msvc_imps( return } // The x86 ABI seems to require that leading underscores are added to symbol - // names, so we need an extra underscore on 32-bit. There's also a leading + // names, so we need an extra underscore on x86. There's also a leading // '\x01' here which disables LLVM's symbol mangling (e.g., no extra // underscores added in front). - let prefix = if cgcx.target_pointer_width == "32" { + let prefix = if cgcx.target_arch == "x86" { "\x01__imp__" } else { "\x01__imp_" diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs index bc2bb97a19e5..48808eea3045 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -18,6 +18,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::base::to_immediate; use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef}; use rustc_codegen_ssa::mir::place::PlaceRef; +use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ops::{Deref, Range}; use std::ptr; @@ -72,6 +73,12 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { } } +impl HasTargetSpec for Builder<'_, '_, 'tcx> { + fn target_spec(&self) -> &Target { + &self.cx.target_spec() + } +} + impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> { type Ty = Ty<'tcx>; type TyLayout = TyLayout<'tcx>; diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 8c83e9ef538e..5f47108309fb 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -14,6 +14,7 @@ use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint, use rustc::hir::Node; use syntax_pos::Span; use rustc_target::abi::HasDataLayout; +use syntax::symbol::sym; use syntax_pos::symbol::LocalInternedString; use rustc::ty::{self, Ty}; use rustc_codegen_ssa::traits::*; @@ -248,7 +249,7 @@ impl CodegenCx<'ll, 'tcx> { debug!("get_static: sym={} attrs={:?}", sym, attrs); for attr in attrs { - if attr.check_name("thread_local") { + if attr.check_name(sym::thread_local) { llvm::set_thread_local_mode(g, self.tls_model); } } diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index 91496ffbe557..04c9e93c7a52 100644 --- a/src/librustc_codegen_llvm/debuginfo/gdb.rs +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -9,6 +9,7 @@ use rustc::session::config::DebugInfo; use rustc_codegen_ssa::traits::*; use syntax::attr; +use syntax::symbol::sym; /// Inserts a side-effect free instruction sequence that makes sure that the @@ -66,8 +67,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { let omit_gdb_pretty_printer_section = - attr::contains_name(&cx.tcx.hir().krate_attrs(), - "omit_gdb_pretty_printer_section"); + attr::contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section); !omit_gdb_pretty_printer_section && cx.sess().opts.debuginfo != DebugInfo::None && diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs index 3febcb019ce2..bcb14b8899ec 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -13,13 +13,13 @@ use crate::llvm; use crate::llvm::AttributePlace::Function; -use crate::abi::{FnType, FnTypeExt}; +use crate::abi::{FnType, FnTypeLlvmExt}; use crate::attributes; use crate::context::CodegenCx; use crate::type_::Type; use crate::value::Value; use rustc::ty::{self, PolyFnSig}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{FnTypeExt, LayoutOf}; use rustc::session::config::Sanitizer; use rustc_data_structures::small_c_str::SmallCStr; use rustc_codegen_ssa::traits::*; diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index ceb08f943678..9ae0e26196d9 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -20,7 +20,7 @@ use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive}; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; use rustc::hir; use syntax::ast::{self, FloatTy}; -use syntax::symbol::Symbol; +use syntax::symbol::LocalInternedString; use rustc_codegen_ssa::traits::*; @@ -213,7 +213,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } "type_name" => { let tp_ty = substs.type_at(0); - let ty_name = Symbol::intern(&tp_ty.to_string()).as_str(); + let ty_name = LocalInternedString::intern(&tp_ty.to_string()); self.const_str_slice(ty_name) } "type_id" => { diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index f1b8d532eeb7..274c89659628 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -7,6 +7,7 @@ use rustc_target::spec::MergeFunctions; use libc::c_int; use std::ffi::CString; use syntax::feature_gate::UnstableFeatures; +use syntax::symbol::sym; use std::str; use std::slice; @@ -93,106 +94,106 @@ unsafe fn configure_llvm(sess: &Session) { // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. -const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ - ("aclass", Some("arm_target_feature")), - ("mclass", Some("arm_target_feature")), - ("rclass", Some("arm_target_feature")), - ("dsp", Some("arm_target_feature")), - ("neon", Some("arm_target_feature")), - ("v5te", Some("arm_target_feature")), - ("v6", Some("arm_target_feature")), - ("v6k", Some("arm_target_feature")), - ("v6t2", Some("arm_target_feature")), - ("v7", Some("arm_target_feature")), - ("v8", Some("arm_target_feature")), - ("vfp2", Some("arm_target_feature")), - ("vfp3", Some("arm_target_feature")), - ("vfp4", Some("arm_target_feature")), +const ARM_WHITELIST: &[(&str, Option)] = &[ + ("aclass", Some(sym::arm_target_feature)), + ("mclass", Some(sym::arm_target_feature)), + ("rclass", Some(sym::arm_target_feature)), + ("dsp", Some(sym::arm_target_feature)), + ("neon", Some(sym::arm_target_feature)), + ("v5te", Some(sym::arm_target_feature)), + ("v6", Some(sym::arm_target_feature)), + ("v6k", Some(sym::arm_target_feature)), + ("v6t2", Some(sym::arm_target_feature)), + ("v7", Some(sym::arm_target_feature)), + ("v8", Some(sym::arm_target_feature)), + ("vfp2", Some(sym::arm_target_feature)), + ("vfp3", Some(sym::arm_target_feature)), + ("vfp4", Some(sym::arm_target_feature)), ]; -const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[ - ("fp", Some("aarch64_target_feature")), - ("neon", Some("aarch64_target_feature")), - ("sve", Some("aarch64_target_feature")), - ("crc", Some("aarch64_target_feature")), - ("crypto", Some("aarch64_target_feature")), - ("ras", Some("aarch64_target_feature")), - ("lse", Some("aarch64_target_feature")), - ("rdm", Some("aarch64_target_feature")), - ("fp16", Some("aarch64_target_feature")), - ("rcpc", Some("aarch64_target_feature")), - ("dotprod", Some("aarch64_target_feature")), - ("v8.1a", Some("aarch64_target_feature")), - ("v8.2a", Some("aarch64_target_feature")), - ("v8.3a", Some("aarch64_target_feature")), +const AARCH64_WHITELIST: &[(&str, Option)] = &[ + ("fp", Some(sym::aarch64_target_feature)), + ("neon", Some(sym::aarch64_target_feature)), + ("sve", Some(sym::aarch64_target_feature)), + ("crc", Some(sym::aarch64_target_feature)), + ("crypto", Some(sym::aarch64_target_feature)), + ("ras", Some(sym::aarch64_target_feature)), + ("lse", Some(sym::aarch64_target_feature)), + ("rdm", Some(sym::aarch64_target_feature)), + ("fp16", Some(sym::aarch64_target_feature)), + ("rcpc", Some(sym::aarch64_target_feature)), + ("dotprod", Some(sym::aarch64_target_feature)), + ("v8.1a", Some(sym::aarch64_target_feature)), + ("v8.2a", Some(sym::aarch64_target_feature)), + ("v8.3a", Some(sym::aarch64_target_feature)), ]; -const X86_WHITELIST: &[(&str, Option<&str>)] = &[ - ("adx", Some("adx_target_feature")), +const X86_WHITELIST: &[(&str, Option)] = &[ + ("adx", Some(sym::adx_target_feature)), ("aes", None), ("avx", None), ("avx2", None), - ("avx512bw", Some("avx512_target_feature")), - ("avx512cd", Some("avx512_target_feature")), - ("avx512dq", Some("avx512_target_feature")), - ("avx512er", Some("avx512_target_feature")), - ("avx512f", Some("avx512_target_feature")), - ("avx512ifma", Some("avx512_target_feature")), - ("avx512pf", Some("avx512_target_feature")), - ("avx512vbmi", Some("avx512_target_feature")), - ("avx512vl", Some("avx512_target_feature")), - ("avx512vpopcntdq", Some("avx512_target_feature")), + ("avx512bw", Some(sym::avx512_target_feature)), + ("avx512cd", Some(sym::avx512_target_feature)), + ("avx512dq", Some(sym::avx512_target_feature)), + ("avx512er", Some(sym::avx512_target_feature)), + ("avx512f", Some(sym::avx512_target_feature)), + ("avx512ifma", Some(sym::avx512_target_feature)), + ("avx512pf", Some(sym::avx512_target_feature)), + ("avx512vbmi", Some(sym::avx512_target_feature)), + ("avx512vl", Some(sym::avx512_target_feature)), + ("avx512vpopcntdq", Some(sym::avx512_target_feature)), ("bmi1", None), ("bmi2", None), - ("cmpxchg16b", Some("cmpxchg16b_target_feature")), - ("f16c", Some("f16c_target_feature")), + ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)), + ("f16c", Some(sym::f16c_target_feature)), ("fma", None), ("fxsr", None), ("lzcnt", None), - ("mmx", Some("mmx_target_feature")), - ("movbe", Some("movbe_target_feature")), + ("mmx", Some(sym::mmx_target_feature)), + ("movbe", Some(sym::movbe_target_feature)), ("pclmulqdq", None), ("popcnt", None), ("rdrand", None), ("rdseed", None), - ("rtm", Some("rtm_target_feature")), + ("rtm", Some(sym::rtm_target_feature)), ("sha", None), ("sse", None), ("sse2", None), ("sse3", None), ("sse4.1", None), ("sse4.2", None), - ("sse4a", Some("sse4a_target_feature")), + ("sse4a", Some(sym::sse4a_target_feature)), ("ssse3", None), - ("tbm", Some("tbm_target_feature")), + ("tbm", Some(sym::tbm_target_feature)), ("xsave", None), ("xsavec", None), ("xsaveopt", None), ("xsaves", None), ]; -const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[ - ("hvx", Some("hexagon_target_feature")), - ("hvx-double", Some("hexagon_target_feature")), +const HEXAGON_WHITELIST: &[(&str, Option)] = &[ + ("hvx", Some(sym::hexagon_target_feature)), + ("hvx-double", Some(sym::hexagon_target_feature)), ]; -const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[ - ("altivec", Some("powerpc_target_feature")), - ("power8-altivec", Some("powerpc_target_feature")), - ("power9-altivec", Some("powerpc_target_feature")), - ("power8-vector", Some("powerpc_target_feature")), - ("power9-vector", Some("powerpc_target_feature")), - ("vsx", Some("powerpc_target_feature")), +const POWERPC_WHITELIST: &[(&str, Option)] = &[ + ("altivec", Some(sym::powerpc_target_feature)), + ("power8-altivec", Some(sym::powerpc_target_feature)), + ("power9-altivec", Some(sym::powerpc_target_feature)), + ("power8-vector", Some(sym::powerpc_target_feature)), + ("power9-vector", Some(sym::powerpc_target_feature)), + ("vsx", Some(sym::powerpc_target_feature)), ]; -const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[ - ("fp64", Some("mips_target_feature")), - ("msa", Some("mips_target_feature")), +const MIPS_WHITELIST: &[(&str, Option)] = &[ + ("fp64", Some(sym::mips_target_feature)), + ("msa", Some(sym::mips_target_feature)), ]; -const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ - ("simd128", Some("wasm_target_feature")), - ("atomics", Some("wasm_target_feature")), +const WASM_WHITELIST: &[(&str, Option)] = &[ + ("simd128", Some(sym::wasm_target_feature)), + ("atomics", Some(sym::wasm_target_feature)), ]; /// When rustdoc is running, provide a list of all known features so that all their respective @@ -200,7 +201,7 @@ const WASM_WHITELIST: &[(&str, Option<&str>)] = &[ /// /// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this /// iterator! -pub fn all_known_features() -> impl Iterator)> { +pub fn all_known_features() -> impl Iterator)> { ARM_WHITELIST.iter().cloned() .chain(AARCH64_WHITELIST.iter().cloned()) .chain(X86_WHITELIST.iter().cloned()) @@ -247,7 +248,7 @@ pub fn target_features(sess: &Session) -> Vec { } pub fn target_feature_whitelist(sess: &Session) - -> &'static [(&'static str, Option<&'static str>)] + -> &'static [(&'static str, Option)] { match &*sess.target.target.arch { "arm" => ARM_WHITELIST, diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs index a5ed64a66a39..a3d3f0756a5f 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/src/librustc_codegen_llvm/type_.rs @@ -10,7 +10,7 @@ use rustc_codegen_ssa::traits::*; use crate::common; use crate::type_of::LayoutLlvmExt; -use crate::abi::{LlvmType, FnTypeExt}; +use crate::abi::{LlvmType, FnTypeLlvmExt}; use syntax::ast; use rustc::ty::Ty; use rustc::ty::layout::{self, Align, Size, TyLayout}; diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs index ff25ed925661..800bf505125d 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -1,8 +1,8 @@ -use crate::abi::{FnType, FnTypeExt}; +use crate::abi::{FnType}; use crate::common::*; use crate::type_::Type; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout}; use rustc_target::abi::{FloatTy, TyLayoutMethods}; use rustc_mir::monomorphize::item::DefPathBasedNames; use rustc_codegen_ssa::traits::*; diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 576bcc8f38e6..1c793996c83d 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -28,7 +28,7 @@ use rustc_target::spec::MergeFunctions; use syntax::attr; use syntax::ext::hygiene::Mark; use syntax_pos::MultiSpan; -use syntax_pos::symbol::Symbol; +use syntax_pos::symbol::{Symbol, sym}; use jobserver::{Client, Acquired}; use std::any::Any; @@ -248,6 +248,7 @@ pub struct CodegenContext { pub tm_factory: TargetMachineFactory, pub msvc_imps_needed: bool, pub target_pointer_width: String, + pub target_arch: String, pub debuginfo: config::DebugInfo, // Number of cgus excluding the allocator/metadata modules @@ -382,11 +383,11 @@ pub fn start_async_codegen( let sess = tcx.sess; let crate_name = tcx.crate_name(LOCAL_CRATE); let crate_hash = tcx.crate_hash(LOCAL_CRATE); - let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, "no_builtins"); + let no_builtins = attr::contains_name(&tcx.hir().krate().attrs, sym::no_builtins); let subsystem = attr::first_attr_value_str_by_name(&tcx.hir().krate().attrs, - "windows_subsystem"); + sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { - if subsystem != "windows" && subsystem != "console" { + if subsystem != sym::windows && subsystem != sym::console { tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \ `windows` and `console` are allowed", subsystem)); @@ -1103,6 +1104,7 @@ fn start_executing_work( total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), + target_arch: tcx.sess.target.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, assembler_cmd, }; diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index 8021d4b11d0c..06d7b6c78f14 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -243,9 +243,8 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> } PlaceContext::MutatingUse(MutatingUseContext::Drop) => { - let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir, - self.fx.cx.tcx()); - let ty = self.fx.monomorphize(&ty.ty); + let ty = self.fx.mir.local_decls[local].ty; + let ty = self.fx.monomorphize(&ty); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index e64c847db651..c7dd019fc3eb 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -1,6 +1,6 @@ use rustc::middle::lang_items; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, LayoutOf, HasTyCtxt}; +use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Place, PlaceBase, Static, StaticKind}; use rustc::mir::interpret::InterpError; use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode}; @@ -15,7 +15,7 @@ use crate::traits::*; use std::borrow::Cow; -use syntax::symbol::Symbol; +use syntax::symbol::LocalInternedString; use syntax_pos::Pos; use super::{FunctionCx, LocalRef}; @@ -334,14 +334,14 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ty::ParamEnv::reveal_all(), &sig, ); - let fn_ty = bx.new_vtable(sig, &[]); + let fn_ty = FnType::new_vtable(&bx, sig, &[]); let vtable = args[1]; args = &args[..1]; (meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty) } _ => { (bx.get_fn(drop_fn), - bx.fn_type_of_instance(&drop_fn)) + FnType::of_instance(&bx, &drop_fn)) } }; helper.do_call(self, &mut bx, fn_ty, drop_fn, args, @@ -401,7 +401,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Get the location information. let loc = bx.sess().source_map().lookup_char_pos(span.lo()); - let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); + let filename = LocalInternedString::intern(&loc.file.name.to_string()); let line = bx.const_u32(loc.line as u32); let col = bx.const_u32(loc.col.to_usize() as u32 + 1); @@ -423,7 +423,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } _ => { let str = msg.description(); - let msg_str = Symbol::intern(str).as_str(); + let msg_str = LocalInternedString::intern(str); let msg_file_line_col = bx.static_panic_msg( Some(msg_str), filename, @@ -439,7 +439,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Obtain the panic entry point. let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = bx.fn_type_of_instance(&instance); + let fn_ty = FnType::of_instance(&bx, &instance); let llfn = bx.get_fn(instance); // Codegen the actual panic invoke/call. @@ -518,7 +518,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let fn_ty = match def { Some(ty::InstanceDef::Virtual(..)) => { - bx.new_vtable(sig, &extra_args) + FnType::new_vtable(&bx, sig, &extra_args) } Some(ty::InstanceDef::DropGlue(_, None)) => { // Empty drop glue; a no-op. @@ -526,7 +526,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { helper.funclet_br(self, &mut bx, target); return; } - _ => bx.new_fn_type(sig, &extra_args) + _ => FnType::new(&bx, sig, &extra_args) }; // Emit a panic or a no-op for `panic_if_uninhabited`. @@ -535,7 +535,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let layout = bx.layout_of(ty); if layout.abi.is_uninhabited() { let loc = bx.sess().source_map().lookup_char_pos(span.lo()); - let filename = Symbol::intern(&loc.file.name.to_string()).as_str(); + let filename = LocalInternedString::intern(&loc.file.name.to_string()); let line = bx.const_u32(loc.line as u32); let col = bx.const_u32(loc.col.to_usize() as u32 + 1); @@ -543,7 +543,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "Attempted to instantiate uninhabited type {}", ty ); - let msg_str = Symbol::intern(&str).as_str(); + let msg_str = LocalInternedString::intern(&str); let msg_file_line_col = bx.static_panic_msg( Some(msg_str), filename, @@ -556,7 +556,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def_id = common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem); let instance = ty::Instance::mono(bx.tcx(), def_id); - let fn_ty = bx.fn_type_of_instance(&instance); + let fn_ty = FnType::of_instance(&bx, &instance); let llfn = bx.get_fn(instance); // Codegen the actual panic invoke/call. diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index fcf099235aa1..060d7d18625f 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts}; -use rustc::ty::layout::{TyLayout, HasTyCtxt}; +use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt}; use rustc::mir::{self, Mir}; use rustc::session::config::DebugInfo; use rustc_mir::monomorphize::Instance; @@ -202,7 +202,7 @@ pub fn codegen_mir<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>( ) { assert!(!instance.substs.needs_infer()); - let fn_ty = cx.new_fn_type(sig, &[]); + let fn_ty = FnType::new(cx, sig, &[]); debug!("fn_ty: {:?}", fn_ty); let mut debug_context = cx.create_function_debug_context(instance, sig, llfn, mir); diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 8d3e64c1aa6c..586db5cfabea 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/src/librustc_codegen_ssa/mir/rvalue.rs @@ -5,6 +5,7 @@ use rustc::mir; use rustc::middle::lang_items::ExchangeMallocFnLangItem; use rustc_apfloat::{ieee, Float, Status, Round}; use std::{u128, i128}; +use syntax::symbol::sym; use crate::base; use crate::MemFlags; @@ -181,9 +182,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { match operand.layout.ty.sty { ty::FnDef(def_id, substs) => { - if bx.cx().tcx().has_attr(def_id, "rustc_args_required_const") { - bug!("reifying a fn ptr that requires \ - const arguments"); + if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { + bug!("reifying a fn ptr that requires const arguments"); } OperandValue::Immediate( callee::resolve_and_get_fn(bx.cx(), def_id, substs)) diff --git a/src/librustc_codegen_ssa/traits/abi.rs b/src/librustc_codegen_ssa/traits/abi.rs index a8fd4e1d2c7c..509255c37be7 100644 --- a/src/librustc_codegen_ssa/traits/abi.rs +++ b/src/librustc_codegen_ssa/traits/abi.rs @@ -1,13 +1,7 @@ use super::BackendTypes; -use rustc::ty::{FnSig, Instance, Ty}; +use rustc::ty::{Ty}; use rustc_target::abi::call::FnType; -pub trait AbiMethods<'tcx> { - fn new_fn_type(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>; - fn new_vtable(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>; - fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>>; -} - pub trait AbiBuilderMethods<'tcx>: BackendTypes { fn apply_attrs_callsite(&mut self, ty: &FnType<'tcx, Ty<'tcx>>, callsite: Self::Value); fn get_param(&self, index: usize) -> Self::Value; diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index a3f99cd869e2..0c4c4547a795 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -11,6 +11,7 @@ use crate::mir::place::PlaceRef; use crate::MemFlags; use rustc::ty::Ty; use rustc::ty::layout::{Align, Size, HasParamEnv}; +use rustc_target::spec::{HasTargetSpec}; use std::ops::Range; use std::iter::TrustedLen; @@ -30,6 +31,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: + AsmBuilderMethods<'tcx> + StaticBuilderMethods<'tcx> + HasParamEnv<'tcx> + + HasTargetSpec { fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self; diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs index c237cd8bd264..2bb619e79f5e 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/src/librustc_codegen_ssa/traits/mod.rs @@ -27,7 +27,7 @@ mod statics; mod type_; mod write; -pub use self::abi::{AbiBuilderMethods, AbiMethods}; +pub use self::abi::{AbiBuilderMethods}; pub use self::asm::{AsmBuilderMethods, AsmMethods}; pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; @@ -41,7 +41,8 @@ pub use self::type_::{ ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods, }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; -use rustc::ty::layout::{HasParamEnv}; +use rustc::ty::layout::{HasParamEnv, HasTyCtxt}; +use rustc_target::spec::{HasTargetSpec}; use std::fmt; @@ -56,11 +57,12 @@ pub trait CodegenMethods<'tcx>: + ConstMethods<'tcx> + StaticMethods + DebugInfoMethods<'tcx> - + AbiMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> + HasParamEnv<'tcx> + + HasTyCtxt<'tcx> + + HasTargetSpec { } @@ -71,11 +73,12 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + ConstMethods<'tcx> + StaticMethods + DebugInfoMethods<'tcx> - + AbiMethods<'tcx> + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> + HasParamEnv<'tcx> + + HasTyCtxt<'tcx> + + HasTargetSpec { } diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index 437515f1e9ab..b4ba90c61f65 100644 --- a/src/librustc_codegen_utils/lib.rs +++ b/src/librustc_codegen_utils/lib.rs @@ -23,6 +23,7 @@ extern crate rustc; use rustc::ty::TyCtxt; use rustc::hir::def_id::LOCAL_CRATE; +use syntax::symbol::sym; pub mod link; pub mod codegen_backend; @@ -35,7 +36,7 @@ pub mod symbol_names_test; /// reporting an error. pub fn check_for_rustc_errors_attr(tcx: TyCtxt<'_, '_, '_>) { if let Some((def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - if tcx.has_attr(def_id, "rustc_error") { + if tcx.has_attr(def_id, sym::rustc_error) { tcx.sess.span_fatal(tcx.def_span(def_id), "compilation successful"); } } diff --git a/src/librustc_codegen_utils/link.rs b/src/librustc_codegen_utils/link.rs index f3a1b219f8a8..a2ac64fa7e0c 100644 --- a/src/librustc_codegen_utils/link.rs +++ b/src/librustc_codegen_utils/link.rs @@ -2,6 +2,7 @@ use rustc::session::config::{self, OutputFilenames, Input, OutputType}; use rustc::session::Session; use std::path::{Path, PathBuf}; use syntax::{ast, attr}; +use syntax::symbol::sym; use syntax_pos::Span; pub fn out_filename(sess: &Session, @@ -49,13 +50,13 @@ pub fn find_crate_name(sess: Option<&Session>, // as used. After doing this, however, we still prioritize a crate name from // the command line over one found in the #[crate_name] attribute. If we // find both we ensure that they're the same later on as well. - let attr_crate_name = attr::find_by_name(attrs, "crate_name") + let attr_crate_name = attr::find_by_name(attrs, sym::crate_name) .and_then(|at| at.value_str().map(|s| (at, s))); if let Some(sess) = sess { if let Some(ref s) = sess.opts.crate_name { if let Some((attr, name)) = attr_crate_name { - if name != &**s { + if name.as_str() != *s { let msg = format!("--crate-name and #[crate_name] are \ required to match, but `{}` != `{}`", s, name); diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index d50a9a1607b2..6915687ceba9 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -101,7 +101,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_mir::monomorphize::item::{InstantiationMode, MonoItem, MonoItemExt}; use rustc_mir::monomorphize::Instance; -use syntax_pos::symbol::{Symbol, InternedString}; +use syntax_pos::symbol::InternedString; use log::debug; @@ -238,13 +238,13 @@ fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> if def_id.is_local() { if tcx.plugin_registrar_fn(LOCAL_CRATE) == Some(def_id) { let disambiguator = tcx.sess.local_crate_disambiguator(); - return Symbol::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator)) - .as_interned_str(); + return + InternedString::intern(&tcx.sess.generate_plugin_registrar_symbol(disambiguator)); } if tcx.proc_macro_decls_static(LOCAL_CRATE) == Some(def_id) { let disambiguator = tcx.sess.local_crate_disambiguator(); - return Symbol::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator)) - .as_interned_str(); + return + InternedString::intern(&tcx.sess.generate_proc_macro_decls_symbol(disambiguator)); } } @@ -322,7 +322,7 @@ fn compute_symbol_name(tcx: TyCtxt<'_, 'tcx, 'tcx>, instance: Instance<'tcx>) -> let _ = printer.write_str("{{vtable-shim}}"); } - Symbol::intern(&printer.path.finish(hash)).as_interned_str() + InternedString::intern(&printer.path.finish(hash)) } // Follow C++ namespace-mangling style, see diff --git a/src/librustc_codegen_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs index 6a2b6f1321b8..27ae0b97e594 100644 --- a/src/librustc_codegen_utils/symbol_names_test.rs +++ b/src/librustc_codegen_utils/symbol_names_test.rs @@ -6,11 +6,11 @@ use rustc::hir; use rustc::ty::TyCtxt; - use rustc_mir::monomorphize::Instance; +use syntax::symbol::{Symbol, sym}; -const SYMBOL_NAME: &'static str = "rustc_symbol_name"; -const DEF_PATH: &'static str = "rustc_def_path"; +const SYMBOL_NAME: Symbol = sym::rustc_symbol_name; +const DEF_PATH: Symbol = sym::rustc_def_path; pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // if the `rustc_attrs` feature is not enabled, then the diff --git a/src/librustc_data_structures/flock.rs b/src/librustc_data_structures/flock.rs index 255c5fd7fe7e..b63701dbc096 100644 --- a/src/librustc_data_structures/flock.rs +++ b/src/librustc_data_structures/flock.rs @@ -44,7 +44,6 @@ cfg_if! { } #[cfg(any(target_os = "dragonfly", - target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))] mod os { diff --git a/src/librustc_data_structures/macros.rs b/src/librustc_data_structures/macros.rs index 029e7267c824..7fc23999284a 100644 --- a/src/librustc_data_structures/macros.rs +++ b/src/librustc_data_structures/macros.rs @@ -10,3 +10,12 @@ macro_rules! static_assert { static $name: () = [()][!($test: bool) as usize]; } } + +/// Type size assertion. The first argument is a type and the second argument is its expected size. +#[macro_export] +#[allow_internal_unstable(underscore_const_names)] +macro_rules! static_assert_size { + ($ty:ty, $size:expr) => { + const _: [(); $size] = [(); ::std::mem::size_of::<$ty>()]; + } +} diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index fa573907d4c7..2b844aa24d49 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -15,7 +15,6 @@ use crate::bit_set; /// extended to 64 bits if needed. pub struct StableHasher { state: SipHasher128, - bytes_hashed: u64, width: PhantomData, } @@ -33,7 +32,6 @@ impl StableHasher { pub fn new() -> Self { StableHasher { state: SipHasher128::new_with_keys(0, 0), - bytes_hashed: 0, width: PhantomData, } } @@ -61,11 +59,6 @@ impl StableHasher { pub fn finalize(self) -> (u64, u64) { self.state.finish128() } - - #[inline] - pub fn bytes_hashed(&self) -> u64 { - self.bytes_hashed - } } impl Hasher for StableHasher { @@ -76,37 +69,31 @@ impl Hasher for StableHasher { #[inline] fn write(&mut self, bytes: &[u8]) { self.state.write(bytes); - self.bytes_hashed += bytes.len() as u64; } #[inline] fn write_u8(&mut self, i: u8) { self.state.write_u8(i); - self.bytes_hashed += 1; } #[inline] fn write_u16(&mut self, i: u16) { self.state.write_u16(i.to_le()); - self.bytes_hashed += 2; } #[inline] fn write_u32(&mut self, i: u32) { self.state.write_u32(i.to_le()); - self.bytes_hashed += 4; } #[inline] fn write_u64(&mut self, i: u64) { self.state.write_u64(i.to_le()); - self.bytes_hashed += 8; } #[inline] fn write_u128(&mut self, i: u128) { self.state.write_u128(i.to_le()); - self.bytes_hashed += 16; } #[inline] @@ -115,37 +102,31 @@ impl Hasher for StableHasher { // platforms. This is important for symbol hashes when cross compiling, // for example. self.state.write_u64((i as u64).to_le()); - self.bytes_hashed += 8; } #[inline] fn write_i8(&mut self, i: i8) { self.state.write_i8(i); - self.bytes_hashed += 1; } #[inline] fn write_i16(&mut self, i: i16) { self.state.write_i16(i.to_le()); - self.bytes_hashed += 2; } #[inline] fn write_i32(&mut self, i: i32) { self.state.write_i32(i.to_le()); - self.bytes_hashed += 4; } #[inline] fn write_i64(&mut self, i: i64) { self.state.write_i64(i.to_le()); - self.bytes_hashed += 8; } #[inline] fn write_i128(&mut self, i: i128) { self.state.write_i128(i.to_le()); - self.bytes_hashed += 16; } #[inline] @@ -154,12 +135,35 @@ impl Hasher for StableHasher { // platforms. This is important for symbol hashes when cross compiling, // for example. self.state.write_i64((i as i64).to_le()); - self.bytes_hashed += 8; } } /// Something that implements `HashStable` can be hashed in a way that is /// stable across multiple compilation sessions. +/// +/// Note that `HashStable` imposes rather more strict requirements than usual +/// hash functions: +/// +/// - Stable hashes are sometimes used as identifiers. Therefore they must +/// conform to the corresponding `PartialEq` implementations: +/// +/// - `x == y` implies `hash_stable(x) == hash_stable(y)`, and +/// - `x != y` implies `hash_stable(x) != hash_stable(y)`. +/// +/// That second condition is usually not required for hash functions +/// (e.g. `Hash`). In practice this means that `hash_stable` must feed any +/// information into the hasher that a `PartialEq` comparision takes into +/// account. See [#49300](https://github.com/rust-lang/rust/issues/49300) +/// for an example where violating this invariant has caused trouble in the +/// past. +/// +/// - `hash_stable()` must be independent of the current +/// compilation session. E.g. they must not hash memory addresses or other +/// things that are "randomly" assigned per compilation session. +/// +/// - `hash_stable()` must be independent of the host architecture. The +/// `StableHasher` takes care of endianness and `isize`/`usize` platform +/// differences. pub trait HashStable { fn hash_stable(&self, hcx: &mut CTX, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 5b42b049b5b1..02f8eee67b15 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -63,6 +63,7 @@ use syntax::ast; use syntax::source_map::FileLoader; use syntax::feature_gate::{GatedCfg, UnstableFeatures}; use syntax::parse::{self, PResult}; +use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, MultiSpan, FileName}; pub mod pretty; @@ -669,7 +670,7 @@ impl RustcDefaultCalls { // through to build scripts. let value = value.as_ref().map(|s| s.as_str()); let value = value.as_ref().map(|s| s.as_ref()); - if name != "target_feature" || value != Some("crt-static") { + if name != sym::target_feature || value != Some("crt-static") { if !allow_unstable_cfg && gated_cfg.is_some() { return None } diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index fc8bf0baa99f..812321ff5e6c 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -648,7 +648,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, // have to be user friendly. let name = format!( "hir_id_{}_{}", - hir_id.owner.as_array_index(), + hir_id.owner.index(), hir_id.local_id.index(), ); let lcfg = LabelledCFG { @@ -805,8 +805,7 @@ pub fn print_after_hir_lowering<'tcx>( src_name, &mut rdr, box out, - annotation.pp_ann(), - true) + annotation.pp_ann()) }) } @@ -829,8 +828,7 @@ pub fn print_after_hir_lowering<'tcx>( src_name, &mut rdr, box out, - annotation.pp_ann(), - true); + annotation.pp_ann()); for node_id in uii.all_matching_node_ids(hir_map) { let node = hir_map.get(node_id); pp_state.print_node(node)?; diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index f74dcd6070c7..31f697a724a0 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -100,6 +100,18 @@ impl<'a> DiagnosticBuilder<'a> { self.cancel(); } + /// Emit the diagnostic unless `delay` is true, + /// in which case the emission will be delayed as a bug. + /// + /// See `emit` and `delay_as_bug` for details. + pub fn emit_unless(&mut self, delay: bool) { + if delay { + self.delay_as_bug() + } else { + self.emit() + } + } + /// Buffers the diagnostic for later emission, unless handler /// has disabled such buffering. pub fn buffer(mut self, buffered_diagnostics: &mut Vec) { diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 2c83501c86f5..04dad9c5355c 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -27,12 +27,13 @@ use rustc::mir::mono::CodegenUnitNameBuilder; use rustc::ty::TyCtxt; use std::collections::BTreeSet; use syntax::ast; +use syntax::symbol::{Symbol, sym}; use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_CODEGENED, ATTR_EXPECTED_CGU_REUSE}; -const MODULE: &str = "module"; -const CFG: &str = "cfg"; -const KIND: &str = "kind"; +const MODULE: Symbol = sym::module; +const CFG: Symbol = sym::cfg; +const KIND: Symbol = sym::kind; pub fn assert_module_sources<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.dep_graph.with_ignore(|| { @@ -146,7 +147,7 @@ impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> { comp_kind); } - fn field(&self, attr: &ast::Attribute, name: &str) -> ast::Name { + fn field(&self, attr: &ast::Attribute, name: Symbol) -> ast::Name { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.check_name(name) { if let Some(value) = item.value_str() { diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 6f5b411946c2..f404a4f82e67 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -23,14 +23,15 @@ use rustc::hir::def_id::DefId; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir::intravisit; use rustc::ich::{ATTR_DIRTY, ATTR_CLEAN}; -use syntax::ast::{self, Attribute, NestedMetaItem}; -use rustc_data_structures::fx::FxHashSet; -use syntax_pos::Span; use rustc::ty::TyCtxt; +use rustc_data_structures::fx::FxHashSet; +use syntax::ast::{self, Attribute, NestedMetaItem}; +use syntax::symbol::{Symbol, sym}; +use syntax_pos::Span; -const EXCEPT: &str = "except"; -const LABEL: &str = "label"; -const CFG: &str = "cfg"; +const EXCEPT: Symbol = sym::except; +const LABEL: Symbol = sym::label; +const CFG: Symbol = sym::cfg; // Base and Extra labels to build up the labels @@ -591,7 +592,7 @@ fn expect_associated_value(tcx: TyCtxt<'_, '_, '_>, item: &NestedMetaItem) -> as // nodes. pub struct FindAllAttrs<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - attr_names: Vec<&'static str>, + attr_names: Vec, found_attrs: Vec<&'tcx Attribute>, } diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 54b3e7342056..c5ac8860ccd9 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -230,7 +230,7 @@ impl BoxedResolver { pub struct PluginInfo { syntax_exts: Vec, - attributes: Vec<(String, AttributeType)>, + attributes: Vec<(Symbol, AttributeType)>, } pub fn register_plugins<'a>( diff --git a/src/librustc_interface/proc_macro_decls.rs b/src/librustc_interface/proc_macro_decls.rs index 8ed03efd1a78..e9f2f0410d44 100644 --- a/src/librustc_interface/proc_macro_decls.rs +++ b/src/librustc_interface/proc_macro_decls.rs @@ -4,6 +4,7 @@ use rustc::hir; use rustc::ty::TyCtxt; use rustc::ty::query::Providers; use syntax::attr; +use syntax::symbol::sym; pub fn find<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> Option { tcx.proc_macro_decls_static(LOCAL_CRATE) @@ -27,7 +28,7 @@ struct Finder { impl<'v> ItemLikeVisitor<'v> for Finder { fn visit_item(&mut self, item: &hir::Item) { - if attr::contains_name(&item.attrs, "rustc_proc_macro_decls") { + if attr::contains_name(&item.attrs, sym::rustc_proc_macro_decls) { self.decls = Some(item.hir_id); } } diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index 17523aedffb5..d2d0d1918078 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -35,7 +35,7 @@ use syntax::mut_visit::{*, MutVisitor, visit_clobber}; use syntax::ast::BlockCheckMode; use syntax::util::lev_distance::find_best_match_for_name; use syntax::source_map::{FileLoader, RealFileLoader, SourceMap}; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::{self, ast, attr}; #[cfg(not(parallel_compiler))] use std::{thread, panic}; @@ -495,24 +495,24 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec = attrs .iter() .filter_map(|a| { - if a.check_name("crate_type") { + if a.check_name(sym::crate_type) { match a.value_str() { - Some(ref n) if *n == "rlib" => Some(config::CrateType::Rlib), - Some(ref n) if *n == "dylib" => Some(config::CrateType::Dylib), - Some(ref n) if *n == "cdylib" => Some(config::CrateType::Cdylib), - Some(ref n) if *n == "lib" => Some(config::default_lib_output()), - Some(ref n) if *n == "staticlib" => Some(config::CrateType::Staticlib), - Some(ref n) if *n == "proc-macro" => Some(config::CrateType::ProcMacro), - Some(ref n) if *n == "bin" => Some(config::CrateType::Executable), - Some(ref n) => { + Some(sym::rlib) => Some(config::CrateType::Rlib), + Some(sym::dylib) => Some(config::CrateType::Dylib), + Some(sym::cdylib) => Some(config::CrateType::Cdylib), + Some(sym::lib) => Some(config::default_lib_output()), + Some(sym::staticlib) => Some(config::CrateType::Staticlib), + Some(sym::proc_dash_macro) => Some(config::CrateType::ProcMacro), + Some(sym::bin) => Some(config::CrateType::Executable), + Some(n) => { let crate_types = vec![ - Symbol::intern("rlib"), - Symbol::intern("dylib"), - Symbol::intern("cdylib"), - Symbol::intern("lib"), - Symbol::intern("staticlib"), - Symbol::intern("proc-macro"), - Symbol::intern("bin") + sym::rlib, + sym::dylib, + sym::cdylib, + sym::lib, + sym::staticlib, + sym::proc_dash_macro, + sym::bin ]; if let ast::MetaItemKind::NameValue(spanned) = a.meta().unwrap().node { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f7a89271ec55..af4f1b88b0fb 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -42,7 +42,7 @@ use syntax::edition::Edition; use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType}; use syntax::feature_gate::{Stability, deprecated_attributes}; use syntax_pos::{BytePos, Span, SyntaxContext}; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, keywords, sym}; use syntax::errors::{Applicability, DiagnosticBuilder}; use syntax::print::pprust::expr_to_string; use syntax::visit::FnKind; @@ -207,7 +207,7 @@ impl UnsafeCode { impl EarlyLintPass for UnsafeCode { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { - if attr.check_name("allow_internal_unsafe") { + if attr.check_name(sym::allow_internal_unsafe) { self.report_unsafe(cx, attr.span, "`allow_internal_unsafe` allows defining \ macros using unsafe without triggering \ the `unsafe_code` lint at their call site"); @@ -285,7 +285,7 @@ pub struct MissingDoc { impl_lint_pass!(MissingDoc => [MISSING_DOCS]); fn has_doc(attr: &ast::Attribute) -> bool { - if !attr.check_name("doc") { + if !attr.check_name(sym::doc) { return false; } @@ -295,7 +295,7 @@ fn has_doc(attr: &ast::Attribute) -> bool { if let Some(list) = attr.meta_item_list() { for meta in list { - if meta.check_name("include") || meta.check_name("hidden") { + if meta.check_name(sym::include) || meta.check_name(sym::hidden) { return true; } } @@ -355,10 +355,10 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext<'_, '_>, attrs: &[ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.check_name("doc") && + attr.check_name(sym::doc) && match attr.meta_item_list() { None => false, - Some(l) => attr::list_contains_name(&l, "hidden"), + Some(l) => attr::list_contains_name(&l, sym::hidden), } }); self.doc_hidden_stack.push(doc_hidden); @@ -723,7 +723,7 @@ impl UnusedDocComment { let span = sugared_span.take().unwrap_or_else(|| attr.span); - if attr.check_name("doc") { + if attr.check_name(sym::doc) { let mut err = cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, "unused doc comment"); err.span_label( @@ -829,7 +829,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { match it.node { hir::ItemKind::Fn(.., ref generics, _) => { - if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, "no_mangle") { + if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) { for param in &generics.params { match param.kind { GenericParamKind::Lifetime { .. } => {} @@ -856,7 +856,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems { } } hir::ItemKind::Const(..) => { - if attr::contains_name(&it.attrs, "no_mangle") { + if attr::contains_name(&it.attrs, sym::no_mangle) { // Const items do not refer to a particular location in memory, and therefore // don't have anything to attach a symbol to let msg = "const items should never be #[no_mangle]"; @@ -947,7 +947,7 @@ declare_lint_pass!( impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnstableFeatures { fn check_attribute(&mut self, ctx: &LateContext<'_, '_>, attr: &ast::Attribute) { - if attr.check_name("feature") { + if attr.check_name(sym::feature) { if let Some(items) = attr.meta_item_list() { for item in items { ctx.span_lint(UNSTABLE_FEATURES, item.span(), "unstable feature"); @@ -1382,7 +1382,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnnameableTestItems { return; } - if let Some(attr) = attr::find_by_name(&it.attrs, "rustc_test_marker") { + if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) { cx.struct_span_lint( UNNAMEABLE_TEST_ITEMS, attr.span, diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 0bb9d4389dd0..ba72beecc1a1 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -371,11 +371,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { reference: "issue #46043 ", edition: None, }, - FutureIncompatibleInfo { - id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS), - reference: "issue #46205 ", - edition: None, - }, FutureIncompatibleInfo { id: LintId::of(ORDER_DEPENDENT_TRAIT_OBJECTS), reference: "issue #56484 ", @@ -491,6 +486,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { "replaced with a generic attribute input check"); store.register_removed("duplicate_matcher_binding_name", "converted into hard error, see https://github.com/rust-lang/rust/issues/57742"); + store.register_removed("incoherent_fundamental_impls", + "converted into hard error, see https://github.com/rust-lang/rust/issues/46205"); } pub fn register_internals(store: &mut lint::LintStore, sess: Option<&Session>) { diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 7a003d14b2bf..551eded9858a 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -9,6 +9,7 @@ use lint::{EarlyLintPass, LintPass, LateLintPass}; use syntax::ast; use syntax::attr; use syntax::errors::Applicability; +use syntax::symbol::sym; use syntax_pos::{BytePos, symbol::Ident, Span}; #[derive(PartialEq)] @@ -253,7 +254,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - attr::find_by_name(&cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID), "crate_name") + attr::find_by_name(&cx.tcx.hir().attrs_by_hir_id(hir::CRATE_HIR_ID), sym::crate_name) .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { @@ -315,7 +316,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonSnakeCase { } FnKind::ItemFn(ident, _, header, _, attrs) => { // Skip foreign-ABI #[no_mangle] functions (Issue #31924) - if header.abi != Abi::Rust && attr::contains_name(attrs, "no_mangle") { + if header.abi != Abi::Rust && attr::contains_name(attrs, sym::no_mangle) { return; } self.check_snake_case(cx, "function", ident); @@ -390,7 +391,7 @@ impl NonUpperCaseGlobals { impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_, '_>, it: &hir::Item) { match it.node { - hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, "no_mangle") => { + hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); } hir::ItemKind::Const(..) => { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f4ebfd79fe1d..38b6e2c19793 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -62,7 +62,7 @@ impl TypeLimits { /// Returns `true` iff the lint was overridden. fn lint_overflowing_range_endpoint<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, - lit: &ast::Lit, + lit: &hir::Lit, lit_val: u128, max: u128, expr: &'tcx hir::Expr, @@ -132,7 +132,7 @@ fn uint_ty_range(uint_ty: ast::UintTy) -> (u128, u128) { } } -fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &ast::Lit) -> Option { +fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &hir::Lit) -> Option { let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?; let firstch = src.chars().next()?; @@ -249,7 +249,7 @@ fn lint_int_literal<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, type_limits: &TypeLimits, e: &'tcx hir::Expr, - lit: &ast::Lit, + lit: &hir::Lit, t: ast::IntTy, v: u128, ) { @@ -301,7 +301,7 @@ fn lint_int_literal<'a, 'tcx>( fn lint_uint_literal<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, e: &'tcx hir::Expr, - lit: &ast::Lit, + lit: &hir::Lit, t: ast::UintTy, ) { let uint_type = if let ast::UintTy::Usize = t { @@ -363,7 +363,7 @@ fn lint_literal<'a, 'tcx>( cx: &LateContext<'a, 'tcx>, type_limits: &TypeLimits, e: &'tcx hir::Expr, - lit: &ast::Lit, + lit: &hir::Lit, ) { match cx.tables.node_type(e.hir_id).sty { ty::Int(t) => { diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 92508ad51f10..c3dfd44ad857 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -12,7 +12,7 @@ use syntax::attr; use syntax::errors::Applicability; use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use syntax::print::pprust; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax::symbol::Symbol; use syntax::util::parser; use syntax_pos::Span; @@ -170,7 +170,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults { descr_post_path: &str, ) -> bool { for attr in cx.tcx.get_attrs(def_id).iter() { - if attr.check_name("must_use") { + if attr.check_name(sym::must_use) { let msg = format!("unused {}`{}`{} that must be used", descr_pre_path, cx.tcx.def_path_str(def_id), descr_post_path); let mut err = cx.struct_span_lint(UNUSED_MUST_USE, sp, &msg); @@ -243,8 +243,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { } let plugin_attributes = cx.sess().plugin_attributes.borrow_mut(); - for &(ref name, ty) in plugin_attributes.iter() { - if ty == AttributeType::Whitelisted && attr.check_name(&**name) { + for &(name, ty) in plugin_attributes.iter() { + if ty == AttributeType::Whitelisted && attr.check_name(name) { debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty); break; } @@ -262,7 +262,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes { // Has a plugin registered this attribute as one that must be used at // the crate level? let plugin_crate = plugin_attributes.iter() - .find(|&&(ref x, t)| name == x.as_str() && AttributeType::CrateLevel == t) + .find(|&&(x, t)| name == x && AttributeType::CrateLevel == t) .is_some(); if known_crate || plugin_crate { let msg = match attr.style { diff --git a/src/librustc_macros/src/symbols.rs b/src/librustc_macros/src/symbols.rs index 169c5e137183..a4c7daf088ff 100644 --- a/src/librustc_macros/src/symbols.rs +++ b/src/librustc_macros/src/symbols.rs @@ -11,7 +11,7 @@ use quote::quote; #[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(Keywords); - syn::custom_keyword!(Other); + syn::custom_keyword!(Symbols); } struct Keyword { @@ -33,14 +33,24 @@ impl Parse for Keyword { } } -struct Symbol(Ident); +struct Symbol { + name: Ident, + value: Option, +} impl Parse for Symbol { fn parse(input: ParseStream<'_>) -> Result { - let ident: Ident = input.parse()?; + let name = input.parse()?; + let value = match input.parse::() { + Ok(_) => Some(input.parse()?), + Err(_) => None, + }; input.parse::()?; - Ok(Symbol(ident)) + Ok(Symbol { + name, + value, + }) } } @@ -69,7 +79,7 @@ impl Parse for Input { braced!(content in input); let keywords = content.parse()?; - input.parse::()?; + input.parse::()?; let content; braced!(content in input); let symbols = content.parse()?; @@ -116,19 +126,22 @@ pub fn symbols(input: TokenStream) -> TokenStream { } for symbol in &input.symbols.0 { - let value = &symbol.0; - let value_str = value.to_string(); - check_dup(&value_str); + let name = &symbol.name; + let value = match &symbol.value { + Some(value) => value.value(), + None => name.to_string(), + }; + check_dup(&value); prefill_stream.extend(quote! { - #value_str, + #value, }); symbols_stream.extend(quote! { - pub const #value: Symbol = Symbol::new(#counter); + pub const #name: Symbol = Symbol::new(#counter); }); counter += 1; } - TokenStream::from(quote! { + let tt = TokenStream::from(quote! { macro_rules! keywords { () => { #keyword_stream @@ -159,5 +172,11 @@ pub fn symbols(input: TokenStream) -> TokenStream { ]) } } - }) + }); + + // To see the generated code generated, uncomment this line, recompile, and + // run the resulting output through `rustfmt`. + //eprintln!("{}", tt); + + tt } diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index c47d7d85a376..3e00ba3c6200 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -27,7 +27,7 @@ use std::{cmp, fs}; use syntax::ast; use syntax::attr; use syntax::ext::base::SyntaxExtension; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::visit; use syntax::{span_err, span_fatal}; use syntax_pos::{Span, DUMMY_SP}; @@ -95,7 +95,7 @@ enum LoadError<'a> { impl<'a> LoadError<'a> { fn report(self) -> ! { match self { - LoadError::LocatorError(mut locate_ctxt) => locate_ctxt.report_errs(), + LoadError::LocatorError(locate_ctxt) => locate_ctxt.report_errs(), } } } @@ -365,8 +365,8 @@ impl<'a> CrateLoader<'a> { span, ident, crate_name: name, - hash: hash.map(|a| &*a), - extra_filename: extra_filename, + hash, + extra_filename, filesearch: self.sess.target_filesearch(path_kind), target: &self.sess.target.target, triple: self.sess.opts.target_triple.clone(), @@ -650,9 +650,8 @@ impl<'a> CrateLoader<'a> { /// SVH and DefIndex of the registrar function. pub fn find_plugin_registrar(&mut self, span: Span, - name: &str) + name: Symbol) -> Option<(PathBuf, CrateDisambiguator)> { - let name = Symbol::intern(name); let ekrate = self.read_extension_crate(span, name, name); if ekrate.target_only { @@ -704,7 +703,7 @@ impl<'a> CrateLoader<'a> { let desired_strategy = self.sess.panic_strategy(); let mut runtime_found = false; let mut needs_panic_runtime = attr::contains_name(&krate.attrs, - "needs_panic_runtime"); + sym::needs_panic_runtime); self.cstore.iter_crate_data(|cnum, data| { needs_panic_runtime = needs_panic_runtime || @@ -837,7 +836,7 @@ impl<'a> CrateLoader<'a> { let mut uses_std = false; self.cstore.iter_crate_data(|_, data| { - if data.name == "std" { + if data.name == sym::std { uses_std = true; } }); @@ -898,7 +897,7 @@ impl<'a> CrateLoader<'a> { // about through the `#![needs_allocator]` attribute and is typically // written down in liballoc. let mut needs_allocator = attr::contains_name(&krate.attrs, - "needs_allocator"); + sym::needs_allocator); self.cstore.iter_crate_data(|_, data| { needs_allocator = needs_allocator || data.root.needs_allocator; }); @@ -964,7 +963,7 @@ impl<'a> CrateLoader<'a> { // allocator. At this point our allocator request is typically fulfilled // by the standard library, denoted by the `#![default_lib_allocator]` // attribute. - let mut has_default = attr::contains_name(&krate.attrs, "default_lib_allocator"); + let mut has_default = attr::contains_name(&krate.attrs, sym::default_lib_allocator); self.cstore.iter_crate_data(|_, data| { if data.root.has_default_lib_allocator { has_default = true; @@ -987,7 +986,7 @@ impl<'a> CrateLoader<'a> { impl<'ast> visit::Visitor<'ast> for Finder { fn visit_item(&mut self, i: &'ast ast::Item) { - if attr::contains_name(&i.attrs, "global_allocator") { + if attr::contains_name(&i.attrs, sym::global_allocator) { self.0 = true; } visit::walk_item(self, i) @@ -1065,7 +1064,7 @@ impl<'a> CrateLoader<'a> { } None => item.ident.name, }; - let dep_kind = if attr::contains_name(&item.attrs, "no_link") { + let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) { DepKind::UnexportedMacrosOnly } else { DepKind::Explicit diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index dfeaeca323f8..087256a97105 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -31,7 +31,7 @@ use syntax::source_map; use syntax::edition::Edition; use syntax::parse::source_file_to_stream; use syntax::parse::parser::emit_unclosed_delims; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::{Span, NO_EXPANSION, FileName}; use rustc_data_structures::bit_set::BitSet; @@ -432,7 +432,7 @@ impl cstore::CStore { let data = self.get_crate_data(id.krate); if let Some(ref proc_macros) = data.proc_macros { return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone()); - } else if data.name == "proc_macro" && data.item_name(id.index) == "quote" { + } else if data.name == sym::proc_macro && data.item_name(id.index) == "quote" { use syntax::ext::base::SyntaxExtension; use syntax_ext::proc_macro_impl::BangProcMacro; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 4b9db466da84..d882fe6f27ec 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -29,7 +29,7 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, Ident}; use syntax::source_map; -use syntax::symbol::InternedString; +use syntax::symbol::{InternedString, sym}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::hygiene::Mark; use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP, NO_EXPANSION}; @@ -264,7 +264,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { #[inline] fn specialized_decode(&mut self) -> Result { - Ok(DefIndex::from_raw_u32(self.read_u32()?)) + Ok(DefIndex::from_u32(self.read_u32()?)) } } @@ -841,7 +841,7 @@ impl<'a, 'tcx> CrateMetadata { // for other constructors correct visibilities // were already encoded in metadata. let attrs = self.get_item_attrs(def_id.index, sess); - if attr::contains_name(&attrs, "non_exhaustive") { + if attr::contains_name(&attrs, sym::non_exhaustive) { let crate_def_id = self.local_def_id(CRATE_DEF_INDEX); vis = ty::Visibility::Restricted(crate_def_id); } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0946dad53203..939aadcc9ec9 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -33,7 +33,7 @@ use std::u32; use syntax::ast; use syntax::attr; use syntax::source_map::Spanned; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax_pos::{self, hygiene, FileName, SourceFile, Span}; use log::{debug, trace}; @@ -134,7 +134,7 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { #[inline] fn specialized_encode(&mut self, def_index: &DefIndex) -> Result<(), Self::Error> { - self.emit_u32(def_index.as_raw_u32()) + self.emit_u32(def_index.as_u32()) } } @@ -469,7 +469,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let attrs = tcx.hir().krate_attrs(); let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateType::ProcMacro); - let has_default_lib_allocator = attr::contains_name(&attrs, "default_lib_allocator"); + let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator); let has_global_allocator = *tcx.sess.has_global_allocator.get(); let has_panic_handler = *tcx.sess.has_panic_handler.try_get().unwrap_or(&false); @@ -496,13 +496,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { None }, - compiler_builtins: attr::contains_name(&attrs, "compiler_builtins"), - needs_allocator: attr::contains_name(&attrs, "needs_allocator"), - needs_panic_runtime: attr::contains_name(&attrs, "needs_panic_runtime"), - no_builtins: attr::contains_name(&attrs, "no_builtins"), - panic_runtime: attr::contains_name(&attrs, "panic_runtime"), - profiler_runtime: attr::contains_name(&attrs, "profiler_runtime"), - sanitizer_runtime: attr::contains_name(&attrs, "sanitizer_runtime"), + compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins), + needs_allocator: attr::contains_name(&attrs, sym::needs_allocator), + needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime), + no_builtins: attr::contains_name(&attrs, sym::no_builtins), + panic_runtime: attr::contains_name(&attrs, sym::panic_runtime), + profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime), + sanitizer_runtime: attr::contains_name(&attrs, sym::sanitizer_runtime), crate_deps, dylib_dependency_formats, diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 4c1e39cd0a9e..934e871559c7 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -93,7 +93,7 @@ impl Index { pub fn record_index(&mut self, item: DefIndex, entry: Lazy>) { assert!(entry.position < (u32::MAX as usize)); let position = entry.position as u32; - let array_index = item.as_array_index(); + let array_index = item.index(); let positions = &mut self.positions; assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX, @@ -126,7 +126,7 @@ impl<'tcx> LazySeq { def_index, self.len); - let position = u32::read_from_bytes_at(bytes, 1 + def_index.as_array_index()); + let position = u32::read_from_bytes_at(bytes, 1 + def_index.index()); if position == u32::MAX { debug!("Index::lookup: position=u32::MAX"); None diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 6741b5235db3..f4682465a659 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -2,6 +2,7 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; use rustc::ty::TyCtxt; use rustc_target::spec::abi::Abi; +use syntax::symbol::sym; pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { let mut collector = Collector { @@ -10,7 +11,7 @@ pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { tcx.hir().krate().visit_all_item_likes(&mut collector); for attr in tcx.hir().krate().attrs.iter() { - if attr.path == "link_args" { + if attr.path == sym::link_args { if let Some(linkarg) = attr.value_str() { collector.add_link_args(&linkarg.as_str()); } @@ -37,7 +38,7 @@ impl<'tcx> ItemLikeVisitor<'tcx> for Collector { } // First, add all of the custom #[link_args] attributes - for m in it.attrs.iter().filter(|a| a.check_name("link_args")) { + for m in it.attrs.iter().filter(|a| a.check_name(sym::link_args)) { if let Some(linkarg) = m.value_str() { self.add_link_args(&linkarg.as_str()); } diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs index 116042c53fb9..3832c8ee227d 100644 --- a/src/librustc_metadata/locator.rs +++ b/src/librustc_metadata/locator.rs @@ -225,7 +225,7 @@ use rustc::session::search_paths::PathKind; use rustc::util::nodemap::FxHashMap; use errors::DiagnosticBuilder; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::struct_span_err; use syntax_pos::Span; use rustc_target::spec::{Target, TargetTriple}; @@ -321,7 +321,7 @@ impl<'a> Context<'a> { } } - pub fn report_errs(&mut self) -> ! { + pub fn report_errs(self) -> ! { let add = match self.root { &None => String::new(), &Some(ref r) => format!(" which `{}` depends on", r.ident), @@ -408,7 +408,7 @@ impl<'a> Context<'a> { self.ident, add); - if (self.ident == "std" || self.ident == "core") + if (self.ident == sym::std || self.ident == sym::core) && self.triple != TargetTriple::from_triple(config::host_triple()) { err.note(&format!("the `{}` target may not be installed", self.triple)); } @@ -901,8 +901,7 @@ fn get_metadata_section_imp(target: &Target, let mut inflated = Vec::new(); match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => { - let buf = unsafe { OwningRef::new_assert_stable_address(inflated) }; - rustc_erase_owner!(buf.map_owner_box()) + rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()) } Err(_) => { return Err(format!("failed to decompress metadata: {}", filename.display())); diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index e0665127c0fb..fee08f421549 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -8,7 +8,7 @@ use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::source_map::Span; use syntax::feature_gate::{self, GateIssue}; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::{span_err, struct_span_err}; pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec { @@ -47,7 +47,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { } // Process all of the #[link(..)]-style arguments - for m in it.attrs.iter().filter(|a| a.check_name("link")) { + for m in it.attrs.iter().filter(|a| a.check_name(sym::link)) { let items = match m.meta_item_list() { Some(item) => item, None => continue, @@ -62,7 +62,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { let mut kind_specified = false; for item in items.iter() { - if item.check_name("kind") { + if item.check_name(sym::kind) { kind_specified = true; let kind = match item.value_str() { Some(name) => name, @@ -81,9 +81,9 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { cstore::NativeUnknown } }; - } else if item.check_name("name") { + } else if item.check_name(sym::name) { lib.name = item.value_str(); - } else if item.check_name("cfg") { + } else if item.check_name(sym::cfg) { let cfg = match item.meta_item_list() { Some(list) => list, None => continue, // skip like historical compilers @@ -98,7 +98,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> { } else { self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`"); } - } else if item.check_name("wasm_import_module") { + } else if item.check_name(sym::wasm_import_module) { match item.value_str() { Some(s) => lib.wasm_import_module = Some(s), None => { @@ -156,7 +156,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { } if lib.cfg.is_some() && !self.tcx.features().link_cfg { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - "link_cfg", + sym::link_cfg, span.unwrap(), GateIssue::Language, "is feature gated"); @@ -164,7 +164,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { if lib.kind == cstore::NativeStaticNobundle && !self.tcx.features().static_nobundle { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - "static_nobundle", + sym::static_nobundle, span.unwrap_or_else(|| syntax_pos::DUMMY_SP), GateIssue::Language, "kind=\"static-nobundle\" is feature gated"); @@ -181,7 +181,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { let any_duplicate = self.libs .iter() .filter_map(|lib| lib.name.as_ref()) - .any(|n| n == name); + .any(|n| n.as_str() == *name); if new_name.is_empty() { self.tcx.sess.err( &format!("an empty renaming target was specified for library `{}`",name)); @@ -212,7 +212,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { // can move them to the end of the list below. let mut existing = self.libs.drain_filter(|lib| { if let Some(lib_name) = lib.name { - if lib_name == name as &str { + if lib_name.as_str() == *name { if let Some(k) = kind { lib.kind = k; } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 8aa6456ebe77..1a1000f0bb41 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -20,6 +20,7 @@ use rustc_data_structures::indexed_vec::Idx; use rustc_errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; use syntax::source_map::CompilerDesugaringKind; +use syntax::symbol::sym; use super::borrow_set::BorrowData; use super::{MirBorrowckCtxt}; @@ -825,18 +826,21 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let borrow_span = borrow_spans.var_or_use(); if let BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Return, + category, span, ref opt_place_desc, from_closure: false, .. } = explanation { - return self.report_cannot_return_reference_to_local( + if let Some(diag) = self.try_report_cannot_return_reference_to_local( borrow, borrow_span, span, + category, opt_place_desc.as_ref(), - ); + ) { + return diag; + } } let mut err = self.infcx.tcx.path_does_not_live_long_enough( @@ -1014,17 +1018,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); if let BorrowExplanation::MustBeValidFor { - category: ConstraintCategory::Return, + category, span, from_closure: false, .. } = explanation { - return self.report_cannot_return_reference_to_local( + if let Some(diag) = self.try_report_cannot_return_reference_to_local( borrow, proper_span, span, + category, None, - ); + ) { + return diag; + } } let tcx = self.infcx.tcx; @@ -1063,15 +1070,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err } - fn report_cannot_return_reference_to_local( + fn try_report_cannot_return_reference_to_local( &self, borrow: &BorrowData<'tcx>, borrow_span: Span, return_span: Span, + category: ConstraintCategory, opt_place_desc: Option<&String>, - ) -> DiagnosticBuilder<'cx> { + ) -> Option> { let tcx = self.infcx.tcx; + let return_kind = match category { + ConstraintCategory::Return => "return", + ConstraintCategory::Yield => "yield", + _ => return None, + }; + // FIXME use a better heuristic than Spans let reference_desc = if return_span == self.mir.source_info(borrow.reserve_location).span { "reference to" @@ -1109,7 +1123,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let local = if let Place::Base(PlaceBase::Local(local)) = *root_place { local } else { - bug!("report_cannot_return_reference_to_local: not a local") + bug!("try_report_cannot_return_reference_to_local: not a local") }; match self.mir.local_kind(local) { LocalKind::ReturnPointer | LocalKind::Temp => { @@ -1130,6 +1144,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mut err = tcx.cannot_return_reference_to_local( return_span, + return_kind, reference_desc, &place_desc, Origin::Mir, @@ -1139,7 +1154,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { err.span_label(borrow_span, note); } - err + Some(err) } fn report_escaping_closure_capture( @@ -1839,7 +1854,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. }) ) = place { let attrs = self.infcx.tcx.get_attrs(*def_id); - let is_thread_local = attrs.iter().any(|attr| attr.check_name("thread_local")); + let is_thread_local = attrs.iter().any(|attr| attr.check_name(sym::thread_local)); debug!( "is_place_thread_local: attrs={:?} is_thread_local={:?}", diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs index c64d4b4a531e..35efc6195be3 100644 --- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs +++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs @@ -310,9 +310,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { opt_place_desc, } } else { + debug!("explain_why_borrow_contains_point: \ + Could not generate a region name"); BorrowExplanation::Unexplained } } else { + debug!("explain_why_borrow_contains_point: \ + Could not generate an error region vid"); BorrowExplanation::Unexplained } } diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs index ad43c8ef66f4..fa490c108c89 100644 --- a/src/librustc_mir/borrow_check/nll/mod.rs +++ b/src/librustc_mir/borrow_check/nll/mod.rs @@ -20,6 +20,7 @@ use std::io; use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; +use syntax::symbol::sym; use self::mir_util::PassWhere; use polonius_engine::{Algorithm, Output}; @@ -280,7 +281,7 @@ fn dump_annotation<'a, 'gcx, 'tcx>( ) { let tcx = infcx.tcx; let base_def_id = tcx.closure_base_def_id(mir_def_id); - if !tcx.has_attr(base_def_id, "rustc_regions") { + if !tcx.has_attr(base_def_id, sym::rustc_regions) { return; } diff --git a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs index 4e197867bfb3..4d8acd241acd 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/error_reporting/region_name.rs @@ -12,7 +12,6 @@ use rustc::ty::subst::{SubstsRef, UnpackedKind}; use rustc::ty::{self, RegionKind, RegionVid, Ty, TyCtxt}; use rustc::ty::print::RegionHighlightMode; use rustc_errors::DiagnosticBuilder; -use syntax::ast::Name; use syntax::symbol::keywords; use syntax_pos::Span; use syntax_pos::symbol::InternedString; @@ -34,6 +33,7 @@ crate enum RegionNameSource { MatchedAdtAndSegment(Span), AnonRegionFromUpvar(Span, String), AnonRegionFromOutput(Span, String, String), + AnonRegionFromYieldTy(Span, String), } impl RegionName { @@ -48,7 +48,8 @@ impl RegionName { RegionNameSource::MatchedHirTy(..) | RegionNameSource::MatchedAdtAndSegment(..) | RegionNameSource::AnonRegionFromUpvar(..) | - RegionNameSource::AnonRegionFromOutput(..) => false, + RegionNameSource::AnonRegionFromOutput(..) | + RegionNameSource::AnonRegionFromYieldTy(..) => false, } } @@ -58,8 +59,8 @@ impl RegionName { } #[allow(dead_code)] - crate fn name(&self) -> &InternedString { - &self.name + crate fn name(&self) -> InternedString { + self.name } crate fn highlight_region_name( @@ -105,6 +106,12 @@ impl RegionName { format!("return type{} is {}", mir_description, type_name), ); }, + RegionNameSource::AnonRegionFromYieldTy(span, type_name) => { + diag.span_label( + *span, + format!("yield type is {}", type_name), + ); + } RegionNameSource::Static => {}, } } @@ -170,6 +177,11 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.give_name_if_anonymous_region_appears_in_output( infcx, mir, mir_def_id, fr, counter, ) + }) + .or_else(|| { + self.give_name_if_anonymous_region_appears_in_yield_ty( + infcx, mir, mir_def_id, fr, counter, + ) }); debug!("give_region_a_name: gave name {:?}", value); @@ -193,7 +205,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { match error_region { ty::ReEarlyBound(ebr) => { if ebr.has_name() { - let span = self.get_named_span(tcx, error_region, &ebr.name); + let span = self.get_named_span(tcx, error_region, ebr.name); Some(RegionName { name: ebr.name, source: RegionNameSource::NamedEarlyBoundRegion(span) @@ -210,7 +222,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { ty::ReFree(free_region) => match free_region.bound_region { ty::BoundRegion::BrNamed(_, name) => { - let span = self.get_named_span(tcx, error_region, &name); + let span = self.get_named_span(tcx, error_region, name); Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span), @@ -293,7 +305,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, tcx: TyCtxt<'_, '_, 'tcx>, error_region: &RegionKind, - name: &InternedString, + name: InternedString, ) -> Span { let scope = error_region.free_region_binding_scope(tcx); let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID); @@ -676,10 +688,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "give_name_if_anonymous_region_appears_in_output: return_ty = {:?}", return_ty ); - if !infcx - .tcx - .any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) - { + if !tcx.any_free_region_meets(&return_ty, |r| r.to_region_vid() == fr) { return None; } @@ -724,12 +733,63 @@ impl<'tcx> RegionInferenceContext<'tcx> { }) } + fn give_name_if_anonymous_region_appears_in_yield_ty( + &self, + infcx: &InferCtxt<'_, '_, 'tcx>, + mir: &Mir<'tcx>, + mir_def_id: DefId, + fr: RegionVid, + counter: &mut usize, + ) -> Option { + // Note: generators from `async fn` yield `()`, so we don't have to + // worry about them here. + let yield_ty = self.universal_regions.yield_ty?; + debug!( + "give_name_if_anonymous_region_appears_in_yield_ty: yield_ty = {:?}", + yield_ty, + ); + + let tcx = infcx.tcx; + + if !tcx.any_free_region_meets(&yield_ty, |r| r.to_region_vid() == fr) { + return None; + } + + let mut highlight = RegionHighlightMode::default(); + highlight.highlighting_region_vid(fr, *counter); + let type_name = infcx.extract_type_name(&yield_ty, Some(highlight)); + + let mir_node_id = tcx.hir().as_local_node_id(mir_def_id).expect("non-local mir"); + + let yield_span = match tcx.hir().get(mir_node_id) { + hir::Node::Expr(hir::Expr { + node: hir::ExprKind::Closure(_, _, _, span, _), + .. + }) => ( + tcx.sess.source_map().end_point(*span) + ), + _ => mir.span, + }; + + debug!( + "give_name_if_anonymous_region_appears_in_yield_ty: \ + type_name = {:?}, yield_span = {:?}", + yield_span, + type_name, + ); + + Some(RegionName { + name: self.synthesize_region_name(counter), + source: RegionNameSource::AnonRegionFromYieldTy(yield_span, type_name), + }) + } + /// Creates a synthetic region named `'1`, incrementing the /// counter. fn synthesize_region_name(&self, counter: &mut usize) -> InternedString { let c = *counter; *counter += 1; - Name::intern(&format!("'{:?}", c)).as_interned_str() + InternedString::intern(&format!("'{:?}", c)) } } diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 713e3fe0218b..5f444d4ceeb8 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -192,7 +192,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::Pointer { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } - | ExprKind::If { .. } | ExprKind::Match { .. } | ExprKind::Loop { .. } | ExprKind::Block { .. } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index e745ee0f190d..fbc4835a6557 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -345,7 +345,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Literal { .. } | ExprKind::Block { .. } | ExprKind::Match { .. } - | ExprKind::If { .. } | ExprKind::NeverToAny { .. } | ExprKind::Use { .. } | ExprKind::Loop { .. } diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 4e24b6853d6e..222ce6d1c968 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -45,7 +45,6 @@ impl Category { | ExprKind::ValueTypeAscription { .. } => Some(Category::Place), ExprKind::LogicalOp { .. } - | ExprKind::If { .. } | ExprKind::Match { .. } | ExprKind::NeverToAny { .. } | ExprKind::Use { .. } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 30ed9cef36f7..15795a64e3b7 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -76,43 +76,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { end_block.unit() } } - ExprKind::If { - condition: cond_expr, - then: then_expr, - otherwise: else_expr, - } => { - let operand = unpack!(block = this.as_local_operand(block, cond_expr)); - - let mut then_block = this.cfg.start_new_block(); - let mut else_block = this.cfg.start_new_block(); - let term = TerminatorKind::if_(this.hir.tcx(), operand, then_block, else_block); - this.cfg.terminate(block, source_info, term); - - unpack!(then_block = this.into(destination, then_block, then_expr)); - else_block = if let Some(else_expr) = else_expr { - unpack!(this.into(destination, else_block, else_expr)) - } else { - // Body of the `if` expression without an `else` clause must return `()`, thus - // we implicitly generate a `else {}` if it is not specified. - this.cfg - .push_assign_unit(else_block, source_info, destination); - else_block - }; - - let join_block = this.cfg.start_new_block(); - this.cfg.terminate( - then_block, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - this.cfg.terminate( - else_block, - source_info, - TerminatorKind::Goto { target: join_block }, - ); - - join_block.unit() - } ExprKind::LogicalOp { op, lhs, rhs } => { // And: // diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 83221aca6c5b..a9d23a0afeab 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,4 +1,5 @@ use syntax::ast::{self, MetaItem}; +use syntax::symbol::{Symbol, sym}; use rustc_data_structures::bit_set::{BitSet, BitSetOperator, HybridBitSet}; use rustc_data_structures::indexed_vec::Idx; @@ -100,9 +101,9 @@ where fn propagate(&mut self) { self.flow_state.propagate(); } } -pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option { +pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option { for attr in attrs { - if attr.check_name("rustc_mir") { + if attr.check_name(sym::rustc_mir) { let items = attr.meta_item_list(); for item in items.iter().flat_map(|l| l.iter()) { match item.meta_item() { @@ -158,10 +159,8 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a, BD> DataflowAnalysis<'a, 'tcx, BD> where BD: BitD return None; }; - let print_preflow_to = - name_found(tcx.sess, attributes, "borrowck_graphviz_preflow"); - let print_postflow_to = - name_found(tcx.sess, attributes, "borrowck_graphviz_postflow"); + let print_preflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_preflow); + let print_postflow_to = name_found(tcx.sess, attributes, sym::borrowck_graphviz_postflow); let mut mbcx = DataflowBuilder { def_id, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 5e646a49e0e4..50140880a368 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -601,13 +601,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arms: arms.iter().map(|a| convert_arm(cx, a)).collect(), } } - hir::ExprKind::If(ref cond, ref then, ref otherwise) => { - ExprKind::If { - condition: cond.to_ref(), - then: then.to_ref(), - otherwise: otherwise.to_ref(), - } - } hir::ExprKind::While(ref cond, ref body, _) => { ExprKind::Loop { condition: Some(cond.to_ref()), diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 7aed0bace8c0..e8070b21bb8c 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -16,7 +16,7 @@ use rustc::ty::subst::{Kind, InternalSubsts}; use rustc::ty::layout::VariantIdx; use syntax::ast; use syntax::attr; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use rustc::hir; use crate::hair::constant::{lit_to_const, LitToConstError}; @@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on // the settings for the crate they are codegened in. - let mut check_overflow = attr::contains_name(attrs, "rustc_inherit_overflow_checks"); + let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks); // Respect -C overflow-checks. check_overflow |= tcx.sess.overflow_checks(); diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 2e53bee3f3d7..d4f139e103a6 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -185,11 +185,6 @@ pub enum ExprKind<'tcx> { cast: PointerCast, source: ExprRef<'tcx>, }, - If { - condition: ExprRef<'tcx>, - then: ExprRef<'tcx>, - otherwise: Option>, - }, Loop { condition: Option>, body: ExprRef<'tcx>, diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index edd36abc0b8a..fd4416fc2b76 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -388,6 +388,18 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { } } + fn is_non_exhaustive_variant<'p>(&self, pattern: &'p Pattern<'tcx>) -> bool + where 'a: 'p + { + match *pattern.kind { + PatternKind::Variant { adt_def, variant_index, .. } => { + let ref variant = adt_def.variants[variant_index]; + variant.is_field_list_non_exhaustive() + } + _ => false, + } + } + fn is_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { match ty.sty { ty::Adt(adt_def, ..) => adt_def.is_variant_list_non_exhaustive(), @@ -1097,10 +1109,17 @@ pub fn is_useful<'p, 'a: 'p, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>, debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v[0]); if let Some(constructors) = pat_constructors(cx, v[0], pcx) { - debug!("is_useful - expanding constructors: {:#?}", constructors); - split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c| - is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) - ).find(|result| result.is_useful()).unwrap_or(NotUseful) + let is_declared_nonexhaustive = cx.is_non_exhaustive_variant(v[0]) && !cx.is_local(pcx.ty); + debug!("is_useful - expanding constructors: {:#?}, is_declared_nonexhaustive: {:?}", + constructors, is_declared_nonexhaustive); + + if is_declared_nonexhaustive { + Useful + } else { + split_grouped_constructors(cx.tcx, constructors, matrix, pcx.ty).into_iter().map(|c| + is_useful_specialized(cx, matrix, v, c, pcx.ty, witness) + ).find(|result| result.is_useful()).unwrap_or(NotUseful) + } } else { debug!("is_useful - expanding wildcard"); diff --git a/src/librustc_mir/hair/pattern/check_match.rs b/src/librustc_mir/hair/pattern/check_match.rs index 1a7266859ad9..a1b2e6461e5b 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -208,7 +208,11 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { .map(|variant| variant.ident) .collect(); } - def.variants.is_empty() + + let is_non_exhaustive_and_non_local = + def.is_variant_list_non_exhaustive() && !def.did.is_local(); + + !(is_non_exhaustive_and_non_local) && def.variants.is_empty() }, _ => false } @@ -365,6 +369,7 @@ fn check_arms<'a, 'tcx>( match is_useful(cx, &seen, &v, LeaveOutWitness) { NotUseful => { match source { + hir::MatchSource::IfDesugar { .. } => bug!(), hir::MatchSource::IfLetDesugar { .. } => { cx.tcx.lint_hir( lint::builtin::IRREFUTABLE_LET_PATTERNS, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 01b1780a2054..0576bb53d8f4 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -27,6 +27,7 @@ use std::cmp::Ordering; use std::fmt; use syntax::ast; use syntax::ptr::P; +use syntax::symbol::sym; use syntax_pos::Span; #[derive(Clone, Debug)] @@ -978,7 +979,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { self.tcx.sess.span_err(span, "cannot use unions in constant patterns"); PatternKind::Wild } - ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, "structural_match") => { + ty::Adt(adt_def, _) if !self.tcx.has_attr(adt_def.did, sym::structural_match) => { let path = self.tcx.def_path_str(adt_def.did); let msg = format!( "to use a constant of type `{}` in a pattern, \ @@ -990,7 +991,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { PatternKind::Wild } ty::Ref(_, ty::TyS { sty: ty::Adt(adt_def, _), .. }, _) - if !self.tcx.has_attr(adt_def.did, "structural_match") => { + if !self.tcx.has_attr(adt_def.did, sym::structural_match) => { // HACK(estebank): Side-step ICE #53708, but anything other than erroring here // would be wrong. Returnging `PatternKind::Wild` is not technically correct. let path = self.tcx.def_path_str(adt_def.did); diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 58e474658ead..2512525b4bb7 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -2,6 +2,7 @@ use rustc::ty::{self, Ty, TypeAndMut}; use rustc::ty::layout::{self, TyLayout, Size}; use rustc::ty::adjustment::{PointerCast}; use syntax::ast::{FloatTy, IntTy, UintTy}; +use syntax::symbol::sym; use rustc_apfloat::ieee::{Single, Double}; use rustc::mir::interpret::{ @@ -76,9 +77,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> // The src operand does not matter, just its type match src.layout.ty.sty { ty::FnDef(def_id, substs) => { - if self.tcx.has_attr(def_id, "rustc_args_required_const") { - bug!("reifying a fn ptr that requires \ - const arguments"); + if self.tcx.has_attr(def_id, sym::rustc_args_required_const) { + bug!("reifying a fn ptr that requires const arguments"); } let instance: EvalResult<'tcx, _> = ty::Instance::resolve( *self.tcx, diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index db827afdb94f..d4c1e5416d56 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -613,7 +613,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc trace!("{:?} is now live", local); let local_val = LocalValue::Uninitialized; - // StorageLive *always* kills the value that's currently stored + // StorageLive *always* kills the value that's currently stored. + // However, we do not error if the variable already is live; + // see . Ok(mem::replace(&mut self.frame_mut().locals[local].value, local_val)) } diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index 999e7402afd9..6b40245d39a8 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -10,7 +10,7 @@ use syntax::attr::InlineAttr; use std::fmt::{self, Write}; use std::iter; use rustc::mir::mono::Linkage; -use syntax_pos::symbol::Symbol; +use syntax_pos::symbol::InternedString; use syntax::source_map::Span; pub use rustc::mir::mono::MonoItem; @@ -61,7 +61,7 @@ pub trait MonoItemExt<'a, 'tcx>: fmt::Debug { MonoItem::GlobalAsm(hir_id) => { let def_id = tcx.hir().local_def_id_from_hir_id(hir_id); ty::SymbolName { - name: Symbol::intern(&format!("global_asm_{:?}", def_id)).as_interned_str() + name: InternedString::intern(&format!("global_asm_{:?}", def_id)) } } } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 078b347fb3f6..394d1f06029c 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -12,7 +12,7 @@ use rustc::lint::builtin::{SAFE_EXTERN_STATICS, SAFE_PACKED_BORROWS, UNUSED_UNSA use rustc::mir::*; use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext}; -use syntax::symbol::Symbol; +use syntax::symbol::{InternedString, sym}; use std::ops::Bound; @@ -167,9 +167,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { (CastTy::FnPtr, CastTy::Int(_)) => { self.register_violations(&[UnsafetyViolation { source_info: self.source_info, - description: Symbol::intern("cast of pointer to int").as_interned_str(), - details: Symbol::intern("casting pointers to integers in constants") - .as_interned_str(), + description: InternedString::intern("cast of pointer to int"), + details: InternedString::intern( + "casting pointers to integers in constants"), kind: UnsafetyViolationKind::General, }], &[]); }, @@ -185,9 +185,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty { self.register_violations(&[UnsafetyViolation { source_info: self.source_info, - description: Symbol::intern("pointer operation").as_interned_str(), - details: Symbol::intern("operations on pointers in constants") - .as_interned_str(), + description: InternedString::intern("pointer operation"), + details: InternedString::intern("operations on pointers in constants"), kind: UnsafetyViolationKind::General, }], &[]); } @@ -212,13 +211,11 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.source_scope_local_data[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern("borrow of packed field").as_interned_str(), - details: - Symbol::intern("fields of packed structs might be misaligned: \ - dereferencing a misaligned pointer or even just \ - creating a misaligned reference is undefined \ - behavior") - .as_interned_str(), + description: InternedString::intern("borrow of packed field"), + details: InternedString::intern( + "fields of packed structs might be misaligned: dereferencing a \ + misaligned pointer or even just creating a misaligned reference \ + is undefined behavior"), kind: UnsafetyViolationKind::BorrowPacked(lint_root) }], &[]); } @@ -315,12 +312,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.source_scope_local_data[source_info.scope].lint_root; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern("use of extern static").as_interned_str(), - details: - Symbol::intern("extern statics are not controlled by the Rust type \ - system: invalid data, aliasing violations or data \ - races will cause undefined behavior") - .as_interned_str(), + description: InternedString::intern("use of extern static"), + details: InternedString::intern( + "extern statics are not controlled by the Rust type system: invalid \ + data, aliasing violations or data races will cause undefined behavior"), kind: UnsafetyViolationKind::ExternStatic(lint_root) }], &[]); } @@ -340,8 +335,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern(description).as_interned_str(), - details: Symbol::intern(details).as_interned_str(), + description: InternedString::intern(description), + details: InternedString::intern(details), kind, }], &[]); } @@ -441,8 +436,8 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { let source_info = self.source_info; self.register_violations(&[UnsafetyViolation { source_info, - description: Symbol::intern(description).as_interned_str(), - details: Symbol::intern(details).as_interned_str(), + description: InternedString::intern(description), + details: InternedString::intern(details), kind: UnsafetyViolationKind::GeneralAndConstFn, }], &[]); } @@ -612,7 +607,7 @@ fn report_unused_unsafe(tcx: TyCtxt<'_, '_, '_>, fn builtin_derive_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option { debug!("builtin_derive_def_id({:?})", def_id); if let Some(impl_def_id) = tcx.impl_of_method(def_id) { - if tcx.has_attr(impl_def_id, "automatically_derived") { + if tcx.has_attr(impl_def_id, sym::automatically_derived) { debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id); Some(impl_def_id) } else { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 72af02782010..8f3dd72c4f24 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -3,15 +3,17 @@ use rustc::hir::def::DefKind; use rustc::mir::{ - Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local, + AggregateKind, Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local, NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem, SourceScope, SourceScopeLocalData, LocalDecl, Promoted, }; -use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext}; +use rustc::mir::visit::{ + Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, +}; use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult}; use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt}; -use syntax::source_map::DUMMY_SP; +use syntax_pos::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; use rustc_data_structures::indexed_vec::IndexVec; use rustc::ty::layout::{ @@ -19,7 +21,7 @@ use rustc::ty::layout::{ HasTyCtxt, TargetDataLayout, HasDataLayout, }; -use crate::interpret::{InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind}; +use crate::interpret::{self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind}; use crate::const_eval::{ CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx, }; @@ -497,6 +499,57 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { }, } } + + fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> { + Operand::Constant(Box::new( + Constant { + span, + ty, + user_ty: None, + literal: self.tcx.mk_const(ty::Const::from_scalar( + scalar, + ty, + )) + } + )) + } + + fn replace_with_const(&self, rval: &mut Rvalue<'tcx>, value: Const<'tcx>, span: Span) { + self.ecx.validate_operand( + value, + vec![], + None, + true, + ).expect("value should already be a valid const"); + + if let interpret::Operand::Immediate(im) = *value { + match im { + interpret::Immediate::Scalar(ScalarMaybeUndef::Scalar(scalar)) => { + *rval = Rvalue::Use(self.operand_from_scalar(scalar, value.layout.ty, span)); + }, + Immediate::ScalarPair( + ScalarMaybeUndef::Scalar(one), + ScalarMaybeUndef::Scalar(two) + ) => { + let ty = &value.layout.ty.sty; + if let ty::Tuple(substs) = ty { + *rval = Rvalue::Aggregate( + Box::new(AggregateKind::Tuple), + vec![ + self.operand_from_scalar(one, substs[0].expect_ty(), span), + self.operand_from_scalar(two, substs[1].expect_ty(), span), + ], + ); + } + }, + _ => { } + } + } + } + + fn should_const_prop(&self) -> bool { + self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 + } } fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -560,10 +613,10 @@ impl<'tcx> Visitor<'tcx> for CanConstProp { } } -impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { +impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { fn visit_constant( &mut self, - constant: &Constant<'tcx>, + constant: &mut Constant<'tcx>, location: Location, ) { trace!("visit_constant: {:?}", constant); @@ -573,11 +626,11 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { fn visit_statement( &mut self, - statement: &Statement<'tcx>, + statement: &mut Statement<'tcx>, location: Location, ) { trace!("visit_statement: {:?}", statement); - if let StatementKind::Assign(ref place, ref rval) = statement.kind { + if let StatementKind::Assign(ref place, ref mut rval) = statement.kind { let place_ty: Ty<'tcx> = place .ty(&self.local_decls, self.tcx) .ty; @@ -589,6 +642,10 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { trace!("storing {:?} to {:?}", value, local); assert!(self.places[local].is_none()); self.places[local] = Some(value); + + if self.should_const_prop() { + self.replace_with_const(rval, value, statement.source_info.span); + } } } } @@ -599,79 +656,116 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { fn visit_terminator( &mut self, - terminator: &Terminator<'tcx>, + terminator: &mut Terminator<'tcx>, location: Location, ) { self.super_terminator(terminator, location); - let source_info = terminator.source_info;; - if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind { - if let Some(value) = self.eval_operand(&cond, source_info) { - trace!("assertion on {:?} should be {:?}", value, expected); - let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected)); - if expected != self.ecx.read_scalar(value).unwrap() { - // poison all places this operand references so that further code - // doesn't use the invalid value - match cond { - Operand::Move(ref place) | Operand::Copy(ref place) => { - let mut place = place; - while let Place::Projection(ref proj) = *place { - place = &proj.base; + let source_info = terminator.source_info; + match &mut terminator.kind { + TerminatorKind::Assert { expected, msg, ref mut cond, .. } => { + if let Some(value) = self.eval_operand(&cond, source_info) { + trace!("assertion on {:?} should be {:?}", value, expected); + let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected)); + let value_const = self.ecx.read_scalar(value).unwrap(); + if expected != value_const { + // poison all places this operand references so that further code + // doesn't use the invalid value + match cond { + Operand::Move(ref place) | Operand::Copy(ref place) => { + let mut place = place; + while let Place::Projection(ref proj) = *place { + place = &proj.base; + } + if let Place::Base(PlaceBase::Local(local)) = *place { + self.places[local] = None; + } + }, + Operand::Constant(_) => {} + } + let span = terminator.source_info.span; + let hir_id = self + .tcx + .hir() + .as_local_hir_id(self.source.def_id()) + .expect("some part of a failing const eval must be local"); + use rustc::mir::interpret::InterpError::*; + let msg = match msg { + Overflow(_) | + OverflowNeg | + DivisionByZero | + RemainderByZero => msg.description().to_owned(), + BoundsCheck { ref len, ref index } => { + let len = self + .eval_operand(len, source_info) + .expect("len must be const"); + let len = match self.ecx.read_scalar(len) { + Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { + bits, .. + })) => bits, + other => bug!("const len not primitive: {:?}", other), + }; + let index = self + .eval_operand(index, source_info) + .expect("index must be const"); + let index = match self.ecx.read_scalar(index) { + Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { + bits, .. + })) => bits, + other => bug!("const index not primitive: {:?}", other), + }; + format!( + "index out of bounds: \ + the len is {} but the index is {}", + len, + index, + ) + }, + // Need proper const propagator for these + _ => return, + }; + self.tcx.lint_hir( + ::rustc::lint::builtin::CONST_ERR, + hir_id, + span, + &msg, + ); + } else { + if self.should_const_prop() { + if let ScalarMaybeUndef::Scalar(scalar) = value_const { + *cond = self.operand_from_scalar( + scalar, + self.tcx.types.bool, + source_info.span, + ); } - if let Place::Base(PlaceBase::Local(local)) = *place { - self.places[local] = None; - } - }, - Operand::Constant(_) => {} + } } - let span = terminator.source_info.span; - let hir_id = self - .tcx - .hir() - .as_local_hir_id(self.source.def_id()) - .expect("some part of a failing const eval must be local"); - use rustc::mir::interpret::InterpError::*; - let msg = match msg { - Overflow(_) | - OverflowNeg | - DivisionByZero | - RemainderByZero => msg.description().to_owned(), - BoundsCheck { ref len, ref index } => { - let len = self - .eval_operand(len, source_info) - .expect("len must be const"); - let len = match self.ecx.read_scalar(len) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { - bits, .. - })) => bits, - other => bug!("const len not primitive: {:?}", other), - }; - let index = self - .eval_operand(index, source_info) - .expect("index must be const"); - let index = match self.ecx.read_scalar(index) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { - bits, .. - })) => bits, - other => bug!("const index not primitive: {:?}", other), - }; - format!( - "index out of bounds: \ - the len is {} but the index is {}", - len, - index, - ) - }, - // Need proper const propagator for these - _ => return, - }; - self.tcx.lint_hir( - ::rustc::lint::builtin::CONST_ERR, - hir_id, - span, - &msg, - ); } - } + }, + TerminatorKind::SwitchInt { ref mut discr, switch_ty, .. } => { + if self.should_const_prop() { + if let Some(value) = self.eval_operand(&discr, source_info) { + if let ScalarMaybeUndef::Scalar(scalar) = + self.ecx.read_scalar(value).unwrap() { + *discr = self.operand_from_scalar(scalar, switch_ty, source_info.span); + } + } + } + }, + //none of these have Operands to const-propagate + TerminatorKind::Goto { .. } | + TerminatorKind::Resume | + TerminatorKind::Abort | + TerminatorKind::Return | + TerminatorKind::Unreachable | + TerminatorKind::Drop { .. } | + TerminatorKind::DropAndReplace { .. } | + TerminatorKind::Yield { .. } | + TerminatorKind::GeneratorDrop | + TerminatorKind::FalseEdges { .. } | + TerminatorKind::FalseUnwind { .. } => { } + //FIXME(wesleywiser) Call does have Operands that could be const-propagated + TerminatorKind::Call { .. } => { } } } } diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9a39e0717211..579f75ba5165 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -22,6 +22,7 @@ use rustc::middle::lang_items; use rustc::session::config::nightly_options; use syntax::ast::LitKind; use syntax::feature_gate::{emit_feature_err, GateIssue}; +use syntax::symbol::sym; use syntax_pos::{Span, DUMMY_SP}; use std::fmt; @@ -380,8 +381,8 @@ impl Qualif for IsNotPromotable { !allowed || cx.tcx.get_attrs(def_id).iter().any( - |attr| attr.check_name("thread_local" - )) + |attr| attr.check_name(sym::thread_local) + ) } } } @@ -939,7 +940,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if self.tcx .get_attrs(def_id) .iter() - .any(|attr| attr.check_name("thread_local")) { + .any(|attr| attr.check_name(sym::thread_local)) { if self.mode != Mode::Fn { span_err!(self.tcx.sess, self.span, E0625, "thread-local statics cannot be \ @@ -994,7 +995,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let ty::RawPtr(_) = base_ty.sty { if !self.tcx.features().const_raw_ptr_deref { emit_feature_err( - &self.tcx.sess.parse_sess, "const_raw_ptr_deref", + &self.tcx.sess.parse_sess, sym::const_raw_ptr_deref, self.span, GateIssue::Language, &format!( "dereferencing raw pointers in {}s is unstable", @@ -1018,7 +1019,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { Mode::ConstFn => { if !self.tcx.features().const_fn_union { emit_feature_err( - &self.tcx.sess.parse_sess, "const_fn_union", + &self.tcx.sess.parse_sess, sym::const_fn_union, self.span, GateIssue::Language, "unions in const fn are unstable", ); @@ -1123,7 +1124,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // in const fn and constants require the feature gate // FIXME: make it unsafe inside const fn and constants emit_feature_err( - &self.tcx.sess.parse_sess, "const_raw_ptr_to_usize_cast", + &self.tcx.sess.parse_sess, sym::const_raw_ptr_to_usize_cast, self.span, GateIssue::Language, &format!( "casting pointers to integers in {}s is unstable", @@ -1149,7 +1150,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // FIXME: make it unsafe to use these operations emit_feature_err( &self.tcx.sess.parse_sess, - "const_compare_raw_pointers", + sym::const_compare_raw_pointers, self.span, GateIssue::Language, &format!("comparing raw pointers inside {}", self.mode), @@ -1210,7 +1211,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // const eval transmute calls only with the feature gate if !self.tcx.features().const_transmute { emit_feature_err( - &self.tcx.sess.parse_sess, "const_transmute", + &self.tcx.sess.parse_sess, sym::const_transmute, self.span, GateIssue::Language, &format!("The use of std::mem::transmute() \ is gated in {}s", self.mode)); @@ -1249,7 +1250,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Don't allow panics in constants without the feature gate. emit_feature_err( &self.tcx.sess.parse_sess, - "const_panic", + sym::const_panic, self.span, GateIssue::Language, &format!("panicking in {}s is unstable", self.mode), @@ -1260,7 +1261,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // Check `#[unstable]` const fns or `#[rustc_const_unstable]` // functions without the feature gate active in this crate in // order to report a better error message than the one below. - if !self.span.allows_unstable(&feature.as_str()) { + if !self.span.allows_unstable(feature) { let mut err = self.tcx.sess.struct_span_err(self.span, &format!("`{}` is not yet stable as a const fn", self.tcx.def_path_str(def_id))); @@ -1592,7 +1593,7 @@ impl MirPass for QualifyAndPromoteConstants { if mode == Mode::Static { // `#[thread_local]` statics don't have to be `Sync`. for attr in &tcx.get_attrs(def_id)[..] { - if attr.check_name("thread_local") { + if attr.check_name(sym::thread_local) { return; } } @@ -1616,7 +1617,7 @@ impl MirPass for QualifyAndPromoteConstants { fn args_required_const(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option> { let attrs = tcx.get_attrs(def_id); - let attr = attrs.iter().find(|a| a.check_name("rustc_args_required_const"))?; + let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?; let mut ret = FxHashSet::default(); for meta in attr.meta_item_list()? { match meta.literal()?.node { diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 246f876235d7..815821f6ff03 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -1,5 +1,6 @@ use rustc_target::spec::abi::{Abi}; use syntax::ast; +use syntax::symbol::sym; use syntax_pos::Span; use rustc::ty::{self, TyCtxt}; @@ -27,7 +28,7 @@ impl MirPass for SanityCheck { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource<'tcx>, mir: &mut Mir<'tcx>) { let def_id = src.def_id(); - if !tcx.has_attr(def_id, "rustc_mir") { + if !tcx.has_attr(def_id, sym::rustc_mir) { debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id)); return; } else { @@ -52,16 +53,16 @@ impl MirPass for SanityCheck { DefinitelyInitializedPlaces::new(tcx, mir, &mdpe), |bd, i| DebugFormatted::new(&bd.move_data().move_paths[i])); - if has_rustc_mir_with(&attributes, "rustc_peek_maybe_init").is_some() { + if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() { sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_inits); } - if has_rustc_mir_with(&attributes, "rustc_peek_maybe_uninit").is_some() { + if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_uninit).is_some() { sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_uninits); } - if has_rustc_mir_with(&attributes, "rustc_peek_definite_init").is_some() { + if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() { sanity_check_via_rustc_peek(tcx, mir, def_id, &attributes, &flow_def_inits); } - if has_rustc_mir_with(&attributes, "stop_after_dataflow").is_some() { + if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() { tcx.sess.fatal("stop_after_dataflow ended compilation"); } } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 4563c9f18a3e..a5dfb736b819 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -634,6 +634,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { fn cannot_return_reference_to_local( self, span: Span, + return_kind: &str, reference_desc: &str, path_desc: &str, o: Origin, @@ -642,7 +643,8 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { self, span, E0515, - "cannot return {REFERENCE} {LOCAL}{OGN}", + "cannot {RETURN} {REFERENCE} {LOCAL}{OGN}", + RETURN=return_kind, REFERENCE=reference_desc, LOCAL=path_desc, OGN = o @@ -650,7 +652,7 @@ pub trait BorrowckErrors<'cx>: Sized + Copy { err.span_label( span, - format!("returns a {} data owned by the current function", reference_desc), + format!("{}s a {} data owned by the current function", return_kind, reference_desc), ); self.cancel_if_wrong_origin(err, o) diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index 04b0e16cd9a8..fc4c6b3fd3f2 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -27,7 +27,7 @@ pub fn graphviz_safe_def_name(def_id: DefId) -> String { format!( "{}_{}", def_id.krate.index(), - def_id.index.as_array_index(), + def_id.index.index(), ) } @@ -167,7 +167,7 @@ fn write_graph_label<'a, 'gcx, 'tcx, W: Write>(tcx: TyCtxt<'a, 'gcx, 'tcx>, write!(w, r#"{:?}: {}; // {}
"#, Place::Base(PlaceBase::Local(local)), escape(&decl.ty), name)?; } else { - write!(w, r#"let mut {:?}: {};
"#, + write!(w, r#"{:?}: {};
"#, Place::Base(PlaceBase::Local(local)), escape(&decl.ty))?; } } diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 6cb3161382af..2bea1db841ae 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashMap; use syntax::ast::*; use syntax::attr; use syntax::source_map::Spanned; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax::ptr::P; use syntax::visit::{self, Visitor}; use syntax::{span_err, struct_span_err, walk_list}; @@ -54,21 +54,21 @@ struct AstValidator<'a> { has_proc_macro_decls: bool, has_global_allocator: bool, - // Used to ban nested `impl Trait`, e.g., `impl Into`. - // Nested `impl Trait` _is_ allowed in associated type position, - // e.g `impl Iterator` + /// Used to ban nested `impl Trait`, e.g., `impl Into`. + /// Nested `impl Trait` _is_ allowed in associated type position, + /// e.g `impl Iterator` outer_impl_trait: Option, - // Used to ban `impl Trait` in path projections like `::Item` - // or `Foo::Bar` + /// Used to ban `impl Trait` in path projections like `::Item` + /// or `Foo::Bar` is_impl_trait_banned: bool, - // rust-lang/rust#57979: the ban of nested `impl Trait` was buggy - // until PRs #57730 and #57981 landed: it would jump directly to - // walk_ty rather than visit_ty (or skip recurring entirely for - // impl trait in projections), and thus miss some cases. We track - // whether we should downgrade to a warning for short-term via - // these booleans. + /// rust-lang/rust#57979: the ban of nested `impl Trait` was buggy + /// until PRs #57730 and #57981 landed: it would jump directly to + /// walk_ty rather than visit_ty (or skip recurring entirely for + /// impl trait in projections), and thus miss some cases. We track + /// whether we should downgrade to a warning for short-term via + /// these booleans. warning_period_57979_didnt_record_next_impl_trait: bool, warning_period_57979_impl_trait_in_proj: bool, } @@ -565,7 +565,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } - if attr::contains_name(&item.attrs, "global_allocator") { + if attr::contains_name(&item.attrs, sym::global_allocator) { self.has_global_allocator = true; } @@ -676,8 +676,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } ItemKind::Mod(_) => { // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). - attr::first_attr_value_str_by_name(&item.attrs, "path"); - if attr::contains_name(&item.attrs, "warn_directory_ownership") { + attr::first_attr_value_str_by_name(&item.attrs, sym::path); + if attr::contains_name(&item.attrs, sym::warn_directory_ownership) { let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP; let msg = "cannot declare a new module at this location"; self.session.buffer_lint(lint, item.id, item.span, msg); diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index 7041a5593abb..dea5774aa6eb 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -12,6 +12,7 @@ use rustc::ty::ParamEnv; use rustc::ty::Ty; use rustc::ty::TyCtxt; use syntax::ast::Attribute; +use syntax::symbol::sym; pub fn test_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { if tcx.features().rustc_attrs { @@ -32,7 +33,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> { if let ItemKind::Ty(..) = item.node { for attr in self.tcx.get_attrs(item_def_id).iter() { - if attr.check_name("rustc_layout") { + if attr.check_name(sym::rustc_layout) { self.dump_layout_of(item_def_id, item, attr); } } @@ -54,26 +55,26 @@ impl<'a, 'tcx> VarianceTest<'a, 'tcx> { // The `..` are the names of fields to dump. let meta_items = attr.meta_item_list().unwrap_or_default(); for meta_item in meta_items { - match meta_item.name_or_empty().get() { - "abi" => { + match meta_item.name_or_empty() { + sym::abi => { self.tcx .sess .span_err(item.span, &format!("abi: {:?}", ty_layout.abi)); } - "align" => { + sym::align => { self.tcx .sess .span_err(item.span, &format!("align: {:?}", ty_layout.align)); } - "size" => { + sym::size => { self.tcx .sess .span_err(item.span, &format!("size: {:?}", ty_layout.size)); } - "homogeneous_aggregate" => { + sym::homogeneous_aggregate => { self.tcx.sess.span_err( item.span, &format!( diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 0f651fafcd2a..37917aaa4a80 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -25,6 +25,7 @@ use rustc::ty::query::Providers; use rustc::ty::subst::{InternalSubsts, SubstsRef}; use rustc::util::nodemap::{ItemLocalSet, HirIdSet}; use rustc::hir; +use syntax::symbol::sym; use syntax_pos::{Span, DUMMY_SP}; use log::debug; use Promotability::*; @@ -335,7 +336,7 @@ fn check_expr_kind<'a, 'tcx>( if v.in_static { for attr in &v.tcx.get_attrs(did)[..] { - if attr.check_name("thread_local") { + if attr.check_name(sym::thread_local) { debug!("Reference to Static(id={:?}) is unpromotable \ due to a #[thread_local] attribute", did); return NotPromotable; @@ -518,15 +519,6 @@ fn check_expr_kind<'a, 'tcx>( NotPromotable } - hir::ExprKind::If(ref lhs, ref rhs, ref option_expr) => { - let _ = v.check_expr(lhs); - let _ = v.check_expr(rhs); - if let Some(ref expr) = option_expr { - let _ = v.check_expr(&expr); - } - NotPromotable - } - // Loops (not very meaningful in constants). hir::ExprKind::While(ref expr, ref box_block, ref _option_label) => { let _ = v.check_expr(expr); diff --git a/src/librustc_plugin/build.rs b/src/librustc_plugin/build.rs index 31018a7cd7a3..8259419c64ae 100644 --- a/src/librustc_plugin/build.rs +++ b/src/librustc_plugin/build.rs @@ -1,6 +1,7 @@ //! Used by `rustc` when compiling a plugin crate. use syntax::attr; +use syntax::symbol::sym; use syntax_pos::Span; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::hir; @@ -15,8 +16,7 @@ struct RegistrarFinder { impl<'v> ItemLikeVisitor<'v> for RegistrarFinder { fn visit_item(&mut self, item: &hir::Item) { if let hir::ItemKind::Fn(..) = item.node { - if attr::contains_name(&item.attrs, - "plugin_registrar") { + if attr::contains_name(&item.attrs, sym::plugin_registrar) { self.registrars.push((item.hir_id, item.span)); } } diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 8b86bddb29f4..680bdcc4bbe9 100644 --- a/src/librustc_plugin/load.rs +++ b/src/librustc_plugin/load.rs @@ -11,6 +11,7 @@ use std::mem; use std::path::PathBuf; use syntax::ast; use syntax::span_err; +use syntax::symbol::{Symbol, keywords, sym}; use syntax_pos::{Span, DUMMY_SP}; /// Pointer to a registrar function. @@ -45,7 +46,7 @@ pub fn load_plugins(sess: &Session, // the feature enabled will result in an error later... if sess.features_untracked().plugin { for attr in &krate.attrs { - if !attr.check_name("plugin") { + if !attr.check_name(sym::plugin) { continue; } @@ -57,9 +58,9 @@ pub fn load_plugins(sess: &Session, for plugin in plugins { // plugins must have a name and can't be key = value let name = plugin.name_or_empty(); - if !name.is_empty() && !plugin.is_value_str() { + if name != keywords::Invalid.name() && !plugin.is_value_str() { let args = plugin.meta_item_list().map(ToOwned::to_owned); - loader.load_plugin(plugin.span(), &name, args.unwrap_or_default()); + loader.load_plugin(plugin.span(), name, args.unwrap_or_default()); } else { call_malformed_plugin_attribute(sess, attr.span); } @@ -69,7 +70,7 @@ pub fn load_plugins(sess: &Session, if let Some(plugins) = addl_plugins { for plugin in plugins { - loader.load_plugin(DUMMY_SP, &plugin, vec![]); + loader.load_plugin(DUMMY_SP, Symbol::intern(&plugin), vec![]); } } @@ -85,7 +86,7 @@ impl<'a> PluginLoader<'a> { } } - fn load_plugin(&mut self, span: Span, name: &str, args: Vec) { + fn load_plugin(&mut self, span: Span, name: Symbol, args: Vec) { let registrar = self.reader.find_plugin_registrar(span, name); if let Some((lib, disambiguator)) = registrar { diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 5c5b6f232b27..c2d1d5fa65af 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -7,7 +7,7 @@ use rustc::util::nodemap::FxHashMap; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT}; use syntax::ext::base::MacroExpanderFn; use syntax::ext::hygiene; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::ast; use syntax::feature_gate::AttributeType; use syntax_pos::Span; @@ -49,7 +49,7 @@ pub struct Registry<'a> { pub llvm_passes: Vec, #[doc(hidden)] - pub attributes: Vec<(String, AttributeType)>, + pub attributes: Vec<(Symbol, AttributeType)>, } impl<'a> Registry<'a> { @@ -86,7 +86,7 @@ impl<'a> Registry<'a> { /// /// This is the most general hook into `libsyntax`'s expansion behavior. pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) { - if name == "macro_rules" { + if name == sym::macro_rules { panic!("user-defined macros may not be named `macro_rules`"); } self.syntax_exts.push((name, match extension { @@ -169,7 +169,7 @@ impl<'a> Registry<'a> { /// Registered attributes will bypass the `custom_attribute` feature gate. /// `Whitelisted` attributes will additionally not trigger the `unused_attribute` /// lint. `CrateLevel` attributes will not be allowed on anything other than a crate. - pub fn register_attribute(&mut self, name: String, ty: AttributeType) { + pub fn register_attribute(&mut self, name: Symbol, ty: AttributeType) { self.attributes.push((name, ty)); } } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index e561b387389e..cd21713cddf9 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -27,7 +27,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; use syntax::ast::Ident; use syntax::attr; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax_pos::Span; use std::{cmp, fmt, mem}; @@ -260,7 +260,8 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) ctor_vis = ty::Visibility::Restricted( DefId::local(CRATE_DEF_INDEX)); let attrs = tcx.get_attrs(variant.def_id); - span = attr::find_by_name(&attrs, "non_exhaustive").unwrap().span; + span = attr::find_by_name(&attrs, sym::non_exhaustive) + .unwrap().span; descr = "crate-visible"; } @@ -291,7 +292,7 @@ fn def_id_visibility<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) if adt_def.non_enum_variant().is_field_list_non_exhaustive() { ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); - span = attr::find_by_name(&item.attrs, "non_exhaustive") + span = attr::find_by_name(&item.attrs, sym::non_exhaustive) .unwrap().span; descr = "crate-visible"; } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3c5760c746fc..3b58a99d19fe 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -37,7 +37,7 @@ use syntax::feature_gate::is_builtin_attr; use syntax::parse::token::{self, Token}; use syntax::span_err; use syntax::std_inject::injected_crate_name; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; @@ -257,7 +257,7 @@ impl<'a> Resolver<'a> { } ast::UseTreeKind::Glob => { let subclass = GlobImport { - is_prelude: attr::contains_name(&item.attrs, "prelude_import"), + is_prelude: attr::contains_name(&item.attrs, sym::prelude_import), max_vis: Cell::new(ty::Visibility::Invisible), }; self.add_import_directive( @@ -314,7 +314,7 @@ impl<'a> Resolver<'a> { Ident::new(keywords::SelfLower.name(), new_span) ), kind: ast::UseTreeKind::Simple( - Some(Ident::new(Name::gensym("__dummy"), new_span)), + Some(Ident::from_str_and_span("__dummy", new_span).gensym()), ast::DUMMY_NODE_ID, ast::DUMMY_NODE_ID, ), @@ -369,7 +369,7 @@ impl<'a> Resolver<'a> { }; self.populate_module_if_necessary(module); - if injected_crate_name().map_or(false, |name| ident.name == name) { + if injected_crate_name().map_or(false, |name| ident.name.as_str() == name) { self.injected_crate = Some(module); } @@ -427,7 +427,7 @@ impl<'a> Resolver<'a> { let module_kind = ModuleKind::Def(DefKind::Mod, def_id, ident.name); let module = self.arenas.alloc_module(ModuleData { no_implicit_prelude: parent.no_implicit_prelude || { - attr::contains_name(&item.attrs, "no_implicit_prelude") + attr::contains_name(&item.attrs, sym::no_implicit_prelude) }, ..ModuleData::new(Some(parent), module_kind, def_id, expansion, item.span) }); @@ -456,12 +456,12 @@ impl<'a> Resolver<'a> { // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - if attr::contains_name(&item.attrs, "proc_macro") || - attr::contains_name(&item.attrs, "proc_macro_attribute") { + if attr::contains_name(&item.attrs, sym::proc_macro) || + attr::contains_name(&item.attrs, sym::proc_macro_attribute) { let res = Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), res.def_id()); self.define(parent, ident, MacroNS, (res, vis, sp, expansion)); } - if let Some(attr) = attr::find_by_name(&item.attrs, "proc_macro_derive") { + if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { if let Some(trait_attr) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { if let Some(ident) = trait_attr.ident() { @@ -518,7 +518,7 @@ impl<'a> Resolver<'a> { let mut ctor_vis = vis; - let has_non_exhaustive = attr::contains_name(&item.attrs, "non_exhaustive"); + let has_non_exhaustive = attr::contains_name(&item.attrs, sym::non_exhaustive); // If the structure is marked as non_exhaustive then lower the visibility // to within the crate. @@ -599,7 +599,7 @@ impl<'a> Resolver<'a> { // If the variant is marked as non_exhaustive then lower the visibility to within the // crate. let mut ctor_vis = vis; - let has_non_exhaustive = attr::contains_name(&variant.node.attrs, "non_exhaustive"); + let has_non_exhaustive = attr::contains_name(&variant.node.attrs, sym::non_exhaustive); if has_non_exhaustive && vis == ty::Visibility::Public { ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)); } @@ -825,7 +825,7 @@ impl<'a> Resolver<'a> { let mut import_all = None; let mut single_imports = Vec::new(); for attr in &item.attrs { - if attr.check_name("macro_use") { + if attr.check_name(sym::macro_use) { if self.current_module.parent.is_some() { span_err!(self.session, item.span, E0468, "an `extern crate` loading macros must be at the crate root"); @@ -908,7 +908,7 @@ impl<'a> Resolver<'a> { /// Returns `true` if this attribute list contains `macro_use`. fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { for attr in attrs { - if attr.check_name("macro_escape") { + if attr.check_name(sym::macro_escape) { let msg = "macro_escape is a deprecated synonym for macro_use"; let mut err = self.session.struct_span_warn(attr.span, msg); if let ast::AttrStyle::Inner = attr.style { @@ -916,7 +916,7 @@ impl<'a> Resolver<'a> { } else { err.emit(); } - } else if !attr.check_name("macro_use") { + } else if !attr.check_name(sym::macro_use) { continue; } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 18da89b9099a..c4a4dd306055 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -43,7 +43,7 @@ use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::base::MacroKind; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, keywords, sym}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::visit::{self, FnKind, Visitor}; @@ -1812,8 +1812,8 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_str_path( &mut self, span: Span, - crate_root: Option<&str>, - components: &[&str], + crate_root: Option, + components: &[Symbol], is_value: bool ) -> hir::Path { let root = if crate_root.is_some() { @@ -1825,7 +1825,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { .chain( crate_root.into_iter() .chain(components.iter().cloned()) - .map(Ident::from_str) + .map(Ident::with_empty_ctxt) ).map(|i| self.new_ast_path_segment(i)).collect::>(); @@ -1964,7 +1964,7 @@ impl<'a> Resolver<'a> { keywords::Invalid.name(), ); let graph_root = arenas.alloc_module(ModuleData { - no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"), + no_implicit_prelude: attr::contains_name(&krate.attrs, sym::no_implicit_prelude), ..ModuleData::new(None, root_module_kind, root_def_id, Mark::root(), krate.span) }); let mut module_map = FxHashMap::default(); @@ -1978,12 +1978,12 @@ impl<'a> Resolver<'a> { session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default())) .collect(); - if !attr::contains_name(&krate.attrs, "no_core") { - extern_prelude.insert(Ident::from_str("core"), Default::default()); - if !attr::contains_name(&krate.attrs, "no_std") { - extern_prelude.insert(Ident::from_str("std"), Default::default()); + if !attr::contains_name(&krate.attrs, sym::no_core) { + extern_prelude.insert(Ident::with_empty_ctxt(sym::core), Default::default()); + if !attr::contains_name(&krate.attrs, sym::no_std) { + extern_prelude.insert(Ident::with_empty_ctxt(sym::std), Default::default()); if session.rust_2018() { - extern_prelude.insert(Ident::from_str("meta"), Default::default()); + extern_prelude.insert(Ident::with_empty_ctxt(sym::meta), Default::default()); } } } @@ -3374,7 +3374,7 @@ impl<'a> Resolver<'a> { self.trait_map.insert(id, traits); } - let mut std_path = vec![Segment::from_ident(Ident::from_str("std"))]; + let mut std_path = vec![Segment::from_ident(Ident::with_empty_ctxt(sym::std))]; std_path.extend(path); if self.primitive_type_table.primitive_types.contains_key(&path[0].ident.name) { let cl = CrateLint::No; @@ -4225,7 +4225,7 @@ impl<'a> Resolver<'a> { let add_module_candidates = |module: Module<'_>, names: &mut Vec| { for (&(ident, _), resolution) in module.resolutions.borrow().iter() { if let Some(binding) = resolution.borrow().binding { - if !ident.name.is_gensymed() && filter_fn(binding.res()) { + if !ident.is_gensymed() && filter_fn(binding.res()) { names.push(TypoSuggestion { candidate: ident.name, article: binding.res().article(), @@ -4243,7 +4243,7 @@ impl<'a> Resolver<'a> { for rib in self.ribs[ns].iter().rev() { // Locals and type parameters for (ident, &res) in &rib.bindings { - if !ident.name.is_gensymed() && filter_fn(res) { + if !ident.is_gensymed() && filter_fn(res) { names.push(TypoSuggestion { candidate: ident.name, article: res.article(), @@ -4273,7 +4273,7 @@ impl<'a> Resolver<'a> { }, ); - if !ident.name.is_gensymed() && filter_fn(crate_mod) { + if !ident.is_gensymed() && filter_fn(crate_mod) { Some(TypoSuggestion { candidate: ident.name, article: "a", @@ -4298,7 +4298,6 @@ impl<'a> Resolver<'a> { names.extend( self.primitive_type_table.primitive_types .iter() - .filter(|(name, _)| !name.is_gensymed()) .map(|(name, _)| { TypoSuggestion { candidate: *name, diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 79a92d595c2e..e34a33ef8fad 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -22,7 +22,7 @@ use syntax::ext::tt::macro_rules; use syntax::feature_gate::{ feature_err, is_builtin_attr_name, AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES, }; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, keywords, sym}; use syntax::visit::Visitor; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::{Span, DUMMY_SP}; @@ -172,7 +172,7 @@ impl<'a> base::Resolver for Resolver<'a> { fn add_builtin(&mut self, ident: ast::Ident, ext: Lrc) { let def_id = DefId { krate: CrateNum::BuiltinMacros, - index: DefIndex::from_array_index(self.macro_map.len()), + index: DefIndex::from(self.macro_map.len()), }; let kind = ext.kind(); self.macro_map.insert(def_id, ext); @@ -313,7 +313,8 @@ impl<'a> Resolver<'a> { if !features.rustc_attrs { let msg = "unless otherwise specified, attributes with the prefix \ `rustc_` are reserved for internal compiler diagnostics"; - self.report_unknown_attribute(path.span, &name, msg, "rustc_attrs"); + self.report_unknown_attribute(path.span, &name, msg, + sym::rustc_attrs); } } else if !features.custom_attribute { let msg = format!("The attribute `{}` is currently unknown to the \ @@ -323,7 +324,7 @@ impl<'a> Resolver<'a> { path.span, &name, &msg, - "custom_attribute", + sym::custom_attribute, ); } } @@ -345,7 +346,7 @@ impl<'a> Resolver<'a> { Ok((res, self.get_macro(res))) } - fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: &str) { + fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: Symbol) { let mut err = feature_err( &self.session.parse_sess, feature, @@ -693,7 +694,7 @@ impl<'a> Resolver<'a> { WhereToResolve::LegacyPluginHelpers => { if (use_prelude || rust_2015) && self.session.plugin_attributes.borrow().iter() - .any(|(name, _)| ident.name == &**name) { + .any(|(name, _)| ident.name == *name) { let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper), ty::Visibility::Public, DUMMY_SP, Mark::root()) .to_name_binding(self.arenas); @@ -981,7 +982,7 @@ impl<'a> Resolver<'a> { let msg = format!("cannot find {} `{}{}` in this scope", kind.descr(), ident, bang); let mut err = self.session.struct_span_err(ident.span, &msg); - self.suggest_macro_name(&ident.as_str(), kind, &mut err, ident.span); + self.suggest_macro_name(ident.name, kind, &mut err, ident.span); err.emit(); } } @@ -1009,11 +1010,12 @@ impl<'a> Resolver<'a> { } } - fn suggest_macro_name(&mut self, name: &str, kind: MacroKind, + fn suggest_macro_name(&mut self, name: Symbol, kind: MacroKind, err: &mut DiagnosticBuilder<'a>, span: Span) { // First check if this is a locally-defined bang macro. let suggestion = if let MacroKind::Bang = kind { - find_best_match_for_name(self.macro_names.iter().map(|ident| &ident.name), name, None) + find_best_match_for_name( + self.macro_names.iter().map(|ident| &ident.name), &name.as_str(), None) } else { None // Then check global macros. @@ -1022,7 +1024,7 @@ impl<'a> Resolver<'a> { .filter_map(|(name, binding)| { if binding.macro_kind() == Some(kind) { Some(name) } else { None } }); - find_best_match_for_name(names, name, None) + find_best_match_for_name(names, &name.as_str(), None) // Then check modules. }).or_else(|| { let is_macro = |res| { @@ -1032,7 +1034,7 @@ impl<'a> Resolver<'a> { false } }; - let ident = Ident::new(Symbol::intern(name), span); + let ident = Ident::new(name, span); self.lookup_typo_candidate(&[Segment::from_ident(ident)], MacroNS, is_macro, span) .map(|suggestion| suggestion.candidate) }); @@ -1091,7 +1093,7 @@ impl<'a> Resolver<'a> { current_legacy_scope: &mut LegacyScope<'a>) { self.local_macro_def_scopes.insert(item.id, self.current_module); let ident = item.ident; - if ident.name == "macro_rules" { + if ident.name == sym::macro_rules { self.session.span_err(item.span, "user-defined macros may not be named `macro_rules`"); } @@ -1106,7 +1108,7 @@ impl<'a> Resolver<'a> { let ident = ident.modern(); self.macro_names.insert(ident); let res = Res::Def(DefKind::Macro(MacroKind::Bang), def_id); - let is_macro_export = attr::contains_name(&item.attrs, "macro_export"); + let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); let vis = if is_macro_export { ty::Visibility::Public } else { @@ -1124,7 +1126,7 @@ impl<'a> Resolver<'a> { self.define(module, ident, MacroNS, (res, vis, item.span, expansion, IsMacroExport)); } else { - if !attr::contains_name(&item.attrs, "rustc_doc_only_macro") { + if !attr::contains_name(&item.attrs, sym::rustc_doc_only_macro) { self.check_reserved_macro_name(ident, MacroNS); } self.unused_macros.insert(def_id); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 9e6b8d035458..3a6a8b56ff35 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -29,7 +29,7 @@ use rustc::{bug, span_bug}; use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID}; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax::util::lev_distance::find_best_match_for_name; use syntax::{struct_span_err, unwrap_or}; use syntax_pos::{MultiSpan, Span}; @@ -496,7 +496,8 @@ impl<'a> Resolver<'a> { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ns == MacroNS && - (ident.name == "cfg" || ident.name == "cfg_attr" || ident.name == "derive") { + (ident.name == sym::cfg || ident.name == sym::cfg_attr || + ident.name == sym::derive) { self.session.span_err(ident.span, &format!("name `{}` is reserved in macro namespace", ident)); } @@ -706,7 +707,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { has_errors = true; if let SingleImport { source, ref source_bindings, .. } = import.subclass { - if source.name == "self" { + if source.name == keywords::SelfLower.name() { // Silence `unresolved import` error if E0429 is already emitted if let Err(Determined) = source_bindings.value_ns.get() { continue; @@ -1041,7 +1042,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let initial_res = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; if let Some(target_binding) = target_bindings[ns].get() { - if target.name == "_" && + // Note that as_str() de-gensyms the Symbol + if target.name.as_str() == "_" && initial_binding.is_extern_crate() && !initial_binding.is_import() { this.record_use(ident, ns, target_binding, directive.module_path.is_empty()); @@ -1392,7 +1394,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // (e.g. implicitly injected `std`) cannot be properly encoded in metadata, // so they can cause name conflict errors downstream. let is_good_import = binding.is_import() && !binding.is_ambiguity() && - !(ident.name.is_gensymed() && ident.name != "_"); + // Note that as_str() de-gensyms the Symbol + !(ident.is_gensymed() && ident.name.as_str() != "_"); if is_good_import || binding.is_macro_def() { let res = binding.res(); if res != Res::Err { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a45e32ddb669..1e65f868ebac 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -463,10 +463,12 @@ impl<'l, 'tcx: 'l, 'll, O: DumpOutput + 'll> DumpVisitor<'l, 'tcx, 'll, O> { } // walk type and init value - self.visit_ty(typ); - if let Some(expr) = expr { - self.visit_expr(expr); - } + self.nest_tables(id, |v| { + v.visit_ty(typ); + if let Some(expr) = expr { + v.visit_expr(expr); + } + }); } // FIXME tuple structs should generate tuple-specific data. diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index f3e0fb32ec2d..d34f5633946b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -879,7 +879,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = String::new(); for attr in attrs { - if attr.check_name("doc") { + if attr.check_name(sym::doc) { if let Some(val) = attr.value_str() { if attr.is_sugared_doc { result.push_str(&strip_doc_comment_decoration(&val.as_str())); @@ -889,10 +889,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push('\n'); } else if let Some(meta_list) = attr.meta_item_list() { meta_list.into_iter() - .filter(|it| it.check_name("include")) + .filter(|it| it.check_name(sym::include)) .filter_map(|it| it.meta_item_list().map(|l| l.to_owned())) .flat_map(|it| it) - .filter(|meta| meta.check_name("contents")) + .filter(|meta| meta.check_name(sym::contents)) .filter_map(|meta| meta.value_str()) .for_each(|val| { result.push_str(&val.as_str()); @@ -1170,7 +1170,7 @@ fn generated_code(span: Span) -> bool { fn id_from_def_id(id: DefId) -> rls_data::Id { rls_data::Id { krate: id.krate.as_u32(), - index: id.index.as_raw_u32(), + index: id.index.as_u32(), } } @@ -1197,7 +1197,7 @@ fn null_id() -> rls_data::Id { fn lower_attributes(attrs: Vec, scx: &SaveContext<'_, '_>) -> Vec { attrs.into_iter() // Only retain real attributes. Doc comments are lowered separately. - .filter(|attr| attr.path != "doc") + .filter(|attr| attr.path != sym::doc) .map(|mut attr| { // Remove the surrounding '#[..]' or '#![..]' of the pretty printed // attribute. First normalize all inner attribute (#![..]) to outer diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs index 9dd343b6c8de..53364e72bfe3 100644 --- a/src/librustc_target/spec/apple_base.rs +++ b/src/librustc_target/spec/apple_base.rs @@ -14,7 +14,7 @@ pub fn opts() -> TargetOptions { // // Here we detect what version is being requested, defaulting to 10.7. ELF // TLS is flagged as enabled if it looks to be supported. - let version = macos_deployment_target().unwrap_or((10, 7)); + let version = macos_deployment_target(); TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections @@ -35,7 +35,7 @@ pub fn opts() -> TargetOptions { } } -fn macos_deployment_target() -> Option<(u32, u32)> { +fn macos_deployment_target() -> (u32, u32) { let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok(); let version = deployment_target.as_ref().and_then(|s| { let mut i = s.splitn(2, '.'); @@ -44,17 +44,10 @@ fn macos_deployment_target() -> Option<(u32, u32)> { a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok() }); - version + version.unwrap_or((10, 7)) } pub fn macos_llvm_target(arch: &str) -> String { - let version = macos_deployment_target(); - let llvm_target = match version { - Some((major, minor)) => { - format!("{}-apple-macosx{}.{}.0", arch, major, minor) - }, - None => format!("{}-apple-darwin", arch) - }; - - llvm_target + let (major, minor) = macos_deployment_target(); + format!("{}-apple-macosx{}.{}.0", arch, major, minor) } diff --git a/src/librustc_target/spec/bitrig_base.rs b/src/librustc_target/spec/bitrig_base.rs deleted file mode 100644 index 9b34119fc00c..000000000000 --- a/src/librustc_target/spec/bitrig_base.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::spec::{TargetOptions, RelroLevel}; -use std::default::Default; - -pub fn opts() -> TargetOptions { - TargetOptions { - dynamic_linking: true, - executables: true, - target_family: Some("unix".to_string()), - linker_is_gnu: true, - has_rpath: true, - position_independent_executables: true, - relro_level: RelroLevel::Full, - - .. Default::default() - } -} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 46fefd78f451..844edbb946a5 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -47,7 +47,6 @@ mod android_base; mod apple_base; mod apple_ios_base; mod arm_base; -mod bitrig_base; mod cloudabi_base; mod dragonfly_base; mod freebsd_base; @@ -390,8 +389,6 @@ supported_targets! { ("i686-unknown-dragonfly", i686_unknown_dragonfly), ("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly), - ("x86_64-unknown-bitrig", x86_64_unknown_bitrig), - ("aarch64-unknown-openbsd", aarch64_unknown_openbsd), ("i686-unknown-openbsd", i686_unknown_openbsd), ("x86_64-unknown-openbsd", x86_64_unknown_openbsd), @@ -444,7 +441,7 @@ supported_targets! { ("asmjs-unknown-emscripten", asmjs_unknown_emscripten), ("wasm32-unknown-emscripten", wasm32_unknown_emscripten), ("wasm32-unknown-unknown", wasm32_unknown_unknown), - ("wasm32-unknown-wasi", wasm32_unknown_wasi), + ("wasm32-wasi", wasm32_wasi), ("wasm32-experimental-emscripten", wasm32_experimental_emscripten), ("thumbv6m-none-eabi", thumbv6m_none_eabi), diff --git a/src/librustc_target/spec/wasm32_unknown_wasi.rs b/src/librustc_target/spec/wasm32_wasi.rs similarity index 80% rename from src/librustc_target/spec/wasm32_unknown_wasi.rs rename to src/librustc_target/spec/wasm32_wasi.rs index 0412635bfe2d..bb33493a7733 100644 --- a/src/librustc_target/spec/wasm32_unknown_wasi.rs +++ b/src/librustc_target/spec/wasm32_wasi.rs @@ -1,4 +1,4 @@ -//! The `wasm32-unknown-wasi` target is a new and still (as of March 2019) +//! The `wasm32-wasi` target is a new and still (as of April 2019) an //! experimental target. The definition in this file is likely to be tweaked //! over time and shouldn't be relied on too much. //! @@ -13,14 +13,14 @@ //! serve two use cases here with this target: //! //! * First, we want Rust usage of the target to be as hassle-free as possible, -//! ideally avoiding the need to configure and install a local -//! wasm32-unknown-wasi toolchain. +//! ideally avoiding the need to configure and install a local wasm32-wasi +//! toolchain. //! //! * Second, one of the primary use cases of LLVM's new wasm backend and the //! wasm support in LLD is that any compiled language can interoperate with -//! any other. To that the `wasm32-unknown-wasi` target is the first with a -//! viable C standard library and sysroot common definition, so we want Rust -//! and C/C++ code to interoperate when compiled to `wasm32-unknown-unknown`. +//! any other. To that the `wasm32-wasi` target is the first with a viable C +//! standard library and sysroot common definition, so we want Rust and C/C++ +//! code to interoperate when compiled to `wasm32-unknown-unknown`. //! //! You'll note, however, that the two goals above are somewhat at odds with one //! another. To attempt to solve both use cases in one go we define a target @@ -39,8 +39,8 @@ //! necessary. //! //! All in all, by default, no external dependencies are required. You can -//! compile `wasm32-unknown-wasi` binaries straight out of the box. You can't, -//! however, reliably interoperate with C code in this mode (yet). +//! compile `wasm32-wasi` binaries straight out of the box. You can't, however, +//! reliably interoperate with C code in this mode (yet). //! //! ## Interop with C required //! @@ -53,17 +53,17 @@ //! //! 2. If you're using rustc to build a linked artifact then you'll need to //! specify `-C linker` to a `clang` binary that supports -//! `wasm32-unknown-wasi` and is configured with the `wasm32-unknown-wasi` -//! sysroot. This will cause Rust code to be linked against the libc.a that -//! the specified `clang` provides. +//! `wasm32-wasi` and is configured with the `wasm32-wasi` sysroot. This +//! will cause Rust code to be linked against the libc.a that the specified +//! `clang` provides. //! //! 3. If you're building a staticlib and integrating Rust code elsewhere, then //! compiling with `-C target-feature=-crt-static` is all you need to do. //! //! You can configure the linker via Cargo using the -//! `CARGO_TARGET_WASM32_UNKNOWN_WASI_LINKER` env var. Be sure to also set -//! `CC_wasm32-unknown-wasi` if any crates in the dependency graph are using -//! the `cc` crate. +//! `CARGO_TARGET_WASM32_WASI_LINKER` env var. Be sure to also set +//! `CC_wasm32-wasi` if any crates in the dependency graph are using the `cc` +//! crate. //! //! ## Remember, this is all in flux //! @@ -82,7 +82,7 @@ pub fn target() -> Result { .pre_link_args .entry(LinkerFlavor::Gcc) .or_insert(Vec::new()) - .push("--target=wasm32-unknown-wasi".to_string()); + .push("--target=wasm32-wasi".to_string()); // When generating an executable be sure to put the startup object at the // front so the main function is correctly hooked up. @@ -98,13 +98,13 @@ pub fn target() -> Result { options.crt_static_respected = true; Ok(Target { - llvm_target: "wasm32-unknown-wasi".to_string(), + llvm_target: "wasm32-wasi".to_string(), target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), target_os: "wasi".to_string(), target_env: String::new(), - target_vendor: "unknown".to_string(), + target_vendor: String::new(), data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128".to_string(), arch: "wasm32".to_string(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Wasm), diff --git a/src/librustc_target/spec/x86_64_unknown_bitrig.rs b/src/librustc_target/spec/x86_64_unknown_bitrig.rs deleted file mode 100644 index 999d93a7e609..000000000000 --- a/src/librustc_target/spec/x86_64_unknown_bitrig.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; - -pub fn target() -> TargetResult { - let mut base = super::bitrig_base::opts(); - base.cpu = "x86-64".to_string(); - base.max_atomic_width = Some(64); - base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); - base.stack_probes = true; - - Ok(Target { - llvm_target: "x86_64-unknown-bitrig".to_string(), - target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), - target_c_int_width: "32".to_string(), - data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(), - arch: "x86_64".to_string(), - target_os: "bitrig".to_string(), - target_env: String::new(), - target_vendor: "unknown".to_string(), - linker_flavor: LinkerFlavor::Gcc, - options: base, - }) -} diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index 50c213026329..580b1571e52b 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -21,6 +21,7 @@ use rustc::ty::query::Providers; use rustc::ty::{self, List, TyCtxt}; use rustc::ty::subst::{Subst, InternalSubsts}; use syntax::ast; +use syntax::symbol::sym; use std::iter; @@ -640,11 +641,11 @@ impl<'a, 'tcx> ClauseDumper<'a, 'tcx> { for attr in attrs { let mut clauses = None; - if attr.check_name("rustc_dump_program_clauses") { + if attr.check_name(sym::rustc_dump_program_clauses) { clauses = Some(self.tcx.program_clauses_for(def_id)); } - if attr.check_name("rustc_dump_env_program_clauses") { + if attr.check_name(sym::rustc_dump_env_program_clauses) { let environment = self.tcx.environment(def_id); clauses = Some(self.tcx.program_clauses_for_env(environment)); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 16033c6c50fd..4b052aec5fc2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -25,6 +25,7 @@ use syntax::ast; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; +use syntax::symbol::sym; use syntax_pos::{DUMMY_SP, Span, MultiSpan}; use crate::util::common::ErrorReported; use crate::util::nodemap::FxHashMap; @@ -289,6 +290,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. + let mut reported_late_bound_region_err = None; if !infer_lifetimes { if let Some(span_late) = def.has_late_bound_regions { let msg = "cannot specify lifetime arguments explicitly \ @@ -300,13 +302,13 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); err.emit(); - return (true, None); + reported_late_bound_region_err = Some(true); } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note.to_string()); tcx.lint_hir(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].id(), multispan, msg); - return (false, None); + reported_late_bound_region_err = Some(false); } } } @@ -324,7 +326,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { // For kinds without defaults (i.e., lifetimes), `required == permitted`. // For other kinds (i.e., types), `permitted` may be greater than `required`. if required <= provided && provided <= permitted { - return (false, None); + return (reported_late_bound_region_err.unwrap_or(false), None); } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -379,7 +381,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { potential_assoc_types) }; - if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { + if reported_late_bound_region_err.is_none() + && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) { check_kind_count( "lifetime", param_counts.lifetimes, @@ -409,7 +412,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { arg_counts.lifetimes, ) } else { - (false, None) + (reported_late_bound_region_err.unwrap_or(false), None) } } @@ -802,7 +805,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { } else { "parenthetical notation is only stable when used with `Fn`-family traits" }; - emit_feature_err(&self.tcx().sess.parse_sess, "unboxed_closures", + emit_feature_err(&self.tcx().sess.parse_sess, sym::unboxed_closures, span, GateIssue::Language, msg); } @@ -1902,7 +1905,18 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { ty, }; - let expr = &tcx.hir().body(ast_const.body).value; + let mut expr = &tcx.hir().body(ast_const.body).value; + + // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments + // currently have to be wrapped in curly brackets, so it's necessary to special-case. + if let ExprKind::Block(block, _) = &expr.node { + if block.stmts.is_empty() { + if let Some(trailing) = &block.expr { + expr = &trailing; + } + } + } + if let ExprKind::Path(ref qpath) = expr.node { if let hir::QPath::Resolved(_, ref path) = qpath { if let Res::Def(DefKind::ConstParam, def_id) = path.res { diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index e9e202ce3799..a69f639e8941 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -2,12 +2,12 @@ use crate::check::{FnCtxt, Expectation, Diverges, Needs}; use crate::check::coercion::CoerceMany; use crate::util::nodemap::FxHashMap; use errors::{Applicability, DiagnosticBuilder}; -use rustc::hir::{self, PatKind, Pat}; +use rustc::hir::{self, PatKind, Pat, ExprKind}; use rustc::hir::def::{Res, DefKind, CtorKind}; use rustc::hir::pat_util::EnumerateAndAdjustIterator; use rustc::infer; use rustc::infer::type_variable::TypeVariableOrigin; -use rustc::traits::ObligationCauseCode; +use rustc::traits::{ObligationCause, ObligationCauseCode}; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::subst::Kind; use syntax::ast; @@ -15,6 +15,7 @@ use syntax::source_map::Spanned; use syntax::ptr::P; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; +use syntax_pos::hygiene::CompilerDesugaringKind; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; @@ -22,10 +23,9 @@ use std::cmp; use super::report_unexpected_variant_res; impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - /// `match_discrim_span` argument having a `Span` indicates that this pattern is part of - /// a match expression arm guard, and it points to the match discriminant to add context - /// in type errors. In the folloowing example, `match_discrim_span` corresponds to the - /// `a + b` expression: + /// `discrim_span` argument having a `Span` indicates that this pattern is part of a match + /// expression arm guard, and it points to the match discriminant to add context in type errors. + /// In the following example, `discrim_span` corresponds to the `a + b` expression: /// /// ```text /// error[E0308]: mismatched types @@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { pat: &'gcx hir::Pat, mut expected: Ty<'tcx>, mut def_bm: ty::BindingMode, - match_discrim_span: Option, + discrim_span: Option, ) { let tcx = self.tcx; @@ -176,7 +176,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // &'static str <: expected // // that's equivalent to there existing a LUB. - self.demand_suptype(pat.span, expected, pat_ty); + if let Some(mut err) = self.demand_suptype_diag(pat.span, expected, pat_ty) { + err.emit_unless(discrim_span + .filter(|&s| s.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary)) + .is_some()); + } + pat_ty } PatKind::Range(ref begin, ref end, _) => { @@ -224,8 +229,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let common_type = self.resolve_type_vars_if_possible(&lhs_ty); // subtyping doesn't matter here, as the value is some kind of scalar - self.demand_eqtype_pat(pat.span, expected, lhs_ty, match_discrim_span); - self.demand_eqtype_pat(pat.span, expected, rhs_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, lhs_ty, discrim_span); + self.demand_eqtype_pat(pat.span, expected, rhs_ty, discrim_span); common_type } PatKind::Binding(ba, var_id, _, ref sub) => { @@ -254,13 +259,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is // required. However, we use equality, which is stronger. See (*) for // an explanation. - self.demand_eqtype_pat(pat.span, region_ty, local_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, region_ty, local_ty, discrim_span); } // otherwise the type of x is the expected type T ty::BindByValue(_) => { // As above, `T <: typeof(x)` is required but we // use equality, see (*) below. - self.demand_eqtype_pat(pat.span, expected, local_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, local_ty, discrim_span); } } @@ -268,11 +273,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // what the type of the binding `x` ought to be if var_id != pat.hir_id { let vt = self.local_ty(pat.span, var_id).decl_ty; - self.demand_eqtype_pat(pat.span, vt, local_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, vt, local_ty, discrim_span); } if let Some(ref p) = *sub { - self.check_pat_walk(&p, expected, def_bm, match_discrim_span); + self.check_pat_walk(&p, expected, def_bm, discrim_span); } local_ty @@ -285,14 +290,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ddpos, expected, def_bm, - match_discrim_span, + discrim_span, ) } PatKind::Path(ref qpath) => { self.check_pat_path(pat, qpath, expected) } PatKind::Struct(ref qpath, ref fields, etc) => { - self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, match_discrim_span) + self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm, discrim_span) } PatKind::Tuple(ref elements, ddpos) => { let mut expected_len = elements.len(); @@ -318,7 +323,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| tcx.types.err); for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) { - self.check_pat_walk(elem, &tcx.types.err, def_bm, match_discrim_span); + self.check_pat_walk(elem, &tcx.types.err, def_bm, discrim_span); } tcx.mk_tup(element_tys_iter) } else { @@ -327,7 +332,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { elem, &element_tys[i].expect_ty(), def_bm, - match_discrim_span, + discrim_span, ); } pat_ty @@ -341,11 +346,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Here, `demand::subtype` is good enough, but I don't // think any errors can be introduced by using // `demand::eqtype`. - self.demand_eqtype_pat(pat.span, expected, uniq_ty, match_discrim_span); - self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, uniq_ty, discrim_span); + self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); uniq_ty } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span); + self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); tcx.types.err } } @@ -384,10 +389,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }; - self.check_pat_walk(&inner, inner_ty, def_bm, match_discrim_span); + self.check_pat_walk(&inner, inner_ty, def_bm, discrim_span); rptr_ty } else { - self.check_pat_walk(&inner, tcx.types.err, def_bm, match_discrim_span); + self.check_pat_walk(&inner, tcx.types.err, def_bm, discrim_span); tcx.types.err } } @@ -445,13 +450,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; for elt in before { - self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span); + self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); } if let Some(ref slice) = *slice { - self.check_pat_walk(&slice, slice_ty, def_bm, match_discrim_span); + self.check_pat_walk(&slice, slice_ty, def_bm, discrim_span); } for elt in after { - self.check_pat_walk(&elt, inner_ty, def_bm, match_discrim_span); + self.check_pat_walk(&elt, inner_ty, def_bm, discrim_span); } expected_ty } @@ -595,6 +600,323 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); ) -> Ty<'tcx> { let tcx = self.tcx; + use hir::MatchSource::*; + let (source_if, if_no_else, if_desugar) = match match_src { + IfDesugar { contains_else_clause } => (true, !contains_else_clause, true), + IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false), + _ => (false, false, false), + }; + + // Type check the descriminant and get its type. + let discrim_ty = if if_desugar { + // Here we want to ensure: + // + // 1. That default match bindings are *not* accepted in the condition of an + // `if` expression. E.g. given `fn foo() -> &bool;` we reject `if foo() { .. }`. + // + // 2. By expecting `bool` for `expr` we get nice diagnostics for e.g. `if x = y { .. }`. + // + // FIXME(60707): Consider removing hack with principled solution. + self.check_expr_has_type_or_error(discrim, self.tcx.types.bool) + } else { + self.demand_discriminant_type(arms, discrim) + }; + + // If there are no arms, that is a diverging match; a special case. + if arms.is_empty() { + self.diverges.set(self.diverges.get() | Diverges::Always); + return tcx.types.never; + } + + self.warn_arms_when_scrutinee_diverges(arms, source_if); + + // Otherwise, we have to union together the types that the + // arms produce and so forth. + let discrim_diverges = self.diverges.get(); + self.diverges.set(Diverges::Maybe); + + // rust-lang/rust#55810: Typecheck patterns first (via eager + // collection into `Vec`), so we get types for all bindings. + let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| { + let mut all_pats_diverge = Diverges::WarnedAlways; + for p in &arm.pats { + self.diverges.set(Diverges::Maybe); + let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable); + self.check_pat_walk(&p, discrim_ty, binding_mode, Some(discrim.span)); + all_pats_diverge &= self.diverges.get(); + } + + // As discussed with @eddyb, this is for disabling unreachable_code + // warnings on patterns (they're now subsumed by unreachable_patterns + // warnings). + match all_pats_diverge { + Diverges::Maybe => Diverges::Maybe, + Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways, + } + }).collect(); + + // Now typecheck the blocks. + // + // The result of the match is the common supertype of all the + // arms. Start out the value as bottom, since it's the, well, + // bottom the type lattice, and we'll be moving up the lattice as + // we process each arm. (Note that any match with 0 arms is matching + // on any empty type and is therefore unreachable; should the flow + // of execution reach it, we will panic, so bottom is an appropriate + // type in that case) + let mut all_arms_diverge = Diverges::WarnedAlways; + + let expected = expected.adjust_for_branches(self); + + let mut coercion = { + let coerce_first = match expected { + // We don't coerce to `()` so that if the match expression is a + // statement it's branches can have any consistent type. That allows + // us to give better error messages (pointing to a usually better + // arm for inconsistent arms or to the whole match when a `()` type + // is required). + Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety, + _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), + }; + CoerceMany::with_coercion_sites(coerce_first, arms) + }; + + let mut other_arms = vec![]; // used only for diagnostics + let mut prior_arm_ty = None; + for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { + if let Some(g) = &arm.guard { + self.diverges.set(pats_diverge); + match g { + hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool), + }; + } + + self.diverges.set(pats_diverge); + let arm_ty = self.check_expr_with_expectation(&arm.body, expected); + all_arms_diverge &= self.diverges.get(); + + let span = expr.span; + + if source_if { + let then_expr = &arms[0].body; + match (i, if_no_else) { + (0, _) => coercion.coerce(self, &self.misc(span), then_expr, arm_ty), + (_, true) => self.if_fallback_coercion(span, then_expr, &mut coercion), + (_, _) => { + let then_ty = prior_arm_ty.unwrap(); + let cause = self.if_cause(span, then_expr, &arm.body, then_ty, arm_ty); + coercion.coerce(self, &cause, &arm.body, arm_ty); + } + } + } else { + let arm_span = if let hir::ExprKind::Block(blk, _) = &arm.body.node { + // Point at the block expr instead of the entire block + blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span) + } else { + arm.body.span + }; + let (span, code) = match i { + // The reason for the first arm to fail is not that the match arms diverge, + // but rather that there's a prior obligation that doesn't hold. + 0 => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), + _ => (span, ObligationCauseCode::MatchExpressionArm { + arm_span, + source: match_src, + prior_arms: other_arms.clone(), + last_ty: prior_arm_ty.unwrap(), + discrim_hir_id: discrim.hir_id, + }), + }; + let cause = self.cause(span, code); + coercion.coerce(self, &cause, &arm.body, arm_ty); + other_arms.push(arm_span); + if other_arms.len() > 5 { + other_arms.remove(0); + } + } + prior_arm_ty = Some(arm_ty); + } + + // We won't diverge unless the discriminant or all arms diverge. + self.diverges.set(discrim_diverges | all_arms_diverge); + + coercion.complete(self) + } + + /// When the previously checked expression (the scrutinee) diverges, + /// warn the user about the match arms being unreachable. + fn warn_arms_when_scrutinee_diverges(&self, arms: &'gcx [hir::Arm], source_if: bool) { + if self.diverges.get().always() { + let msg = if source_if { "block in `if` expression" } else { "arm" }; + for arm in arms { + self.warn_if_unreachable(arm.body.hir_id, arm.body.span, msg); + } + } + } + + /// Handle the fallback arm of a desugared if(-let) like a missing else. + fn if_fallback_coercion( + &self, + span: Span, + then_expr: &'gcx hir::Expr, + coercion: &mut CoerceMany<'gcx, 'tcx, '_, rustc::hir::Arm>, + ) { + // If this `if` expr is the parent's function return expr, + // the cause of the type coercion is the return type, point at it. (#25228) + let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, span); + let cause = self.cause(span, ObligationCauseCode::IfExpressionWithNoElse); + coercion.coerce_forced_unit(self, &cause, &mut |err| { + if let Some((span, msg)) = &ret_reason { + err.span_label(*span, msg.as_str()); + } else if let ExprKind::Block(block, _) = &then_expr.node { + if let Some(expr) = &block.expr { + err.span_label(expr.span, "found here".to_string()); + } + } + err.note("`if` expressions without `else` evaluate to `()`"); + err.help("consider adding an `else` block that evaluates to the expected type"); + }, ret_reason.is_none()); + } + + fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, span: Span) -> Option<(Span, String)> { + use hir::Node::{Block, Item, Local}; + + let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id( + self.tcx.hir().get_parent_node_by_hir_id(hir_id), + )); + if let Block(block) = node { + // check that the body's parent is an fn + let parent = self.tcx.hir().get_by_hir_id( + self.tcx.hir().get_parent_node_by_hir_id( + self.tcx.hir().get_parent_node_by_hir_id(block.hir_id), + ), + ); + if let (Some(expr), Item(hir::Item { + node: hir::ItemKind::Fn(..), .. + })) = (&block.expr, parent) { + // check that the `if` expr without `else` is the fn body's expr + if expr.span == span { + return self.get_fn_decl(hir_id).map(|(fn_decl, _)| ( + fn_decl.output.span(), + format!("expected `{}` because of this return type", fn_decl.output), + )); + } + } + } + if let Local(hir::Local { ty: Some(_), pat, .. }) = node { + return Some((pat.span, "expected because of this assignment".to_string())); + } + None + } + + fn if_cause( + &self, + span: Span, + then_expr: &'gcx hir::Expr, + else_expr: &'gcx hir::Expr, + then_ty: Ty<'tcx>, + else_ty: Ty<'tcx>, + ) -> ObligationCause<'tcx> { + let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { + // The `if`/`else` isn't in one line in the output, include some context to make it + // clear it is an if/else expression: + // ``` + // LL | let x = if true { + // | _____________- + // LL || 10i32 + // || ----- expected because of this + // LL || } else { + // LL || 10u32 + // || ^^^^^ expected i32, found u32 + // LL || }; + // ||_____- if and else have incompatible types + // ``` + Some(span) + } else { + // The entire expression is in one line, only point at the arms + // ``` + // LL | let x = if true { 10i32 } else { 10u32 }; + // | ----- ^^^^^ expected i32, found u32 + // | | + // | expected because of this + // ``` + None + }; + + let mut remove_semicolon = None; + let error_sp = if let ExprKind::Block(block, _) = &else_expr.node { + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + remove_semicolon = self.could_remove_semicolon(block, then_ty); + stmt.span + } else { // empty block, point at its entirety + // Avoid overlapping spans that aren't as readable: + // ``` + // 2 | let x = if true { + // | _____________- + // 3 | | 3 + // | | - expected because of this + // 4 | | } else { + // | |____________^ + // 5 | || + // 6 | || }; + // | || ^ + // | ||_____| + // | |______if and else have incompatible types + // | expected integer, found () + // ``` + // by not pointing at the entire expression: + // ``` + // 2 | let x = if true { + // | ------- if and else have incompatible types + // 3 | 3 + // | - expected because of this + // 4 | } else { + // | ____________^ + // 5 | | + // 6 | | }; + // | |_____^ expected integer, found () + // ``` + if outer_sp.is_some() { + outer_sp = Some(self.tcx.sess.source_map().def_span(span)); + } + else_expr.span + } + } else { // shouldn't happen unless the parser has done something weird + else_expr.span + }; + + // Compute `Span` of `then` part of `if`-expression: + let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + remove_semicolon = remove_semicolon.or(self.could_remove_semicolon(block, else_ty)); + stmt.span + } else { // empty block, point at its entirety + outer_sp = None; // same as in `error_sp`, cleanup output + then_expr.span + } + } else { // shouldn't happen unless the parser has done something weird + then_expr.span + }; + + // Finally construct the cause: + self.cause(error_sp, ObligationCauseCode::IfExpression { + then: then_sp, + outer: outer_sp, + semicolon: remove_semicolon, + }) + } + + fn demand_discriminant_type( + &self, + arms: &'gcx [hir::Arm], + discrim: &'gcx hir::Expr, + ) -> Ty<'tcx> { // Not entirely obvious: if matches may create ref bindings, we want to // use the *precise* type of the discriminant, *not* some supertype, as // the "discriminant type" (issue #23116). @@ -653,143 +975,17 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); hir::MutMutable => 1, hir::MutImmutable => 0, }); - let discrim_ty; + if let Some(m) = contains_ref_bindings { - discrim_ty = self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m)); + self.check_expr_with_needs(discrim, Needs::maybe_mut_place(m)) } else { // ...but otherwise we want to use any supertype of the // discriminant. This is sort of a workaround, see note (*) in // `check_pat` for some details. - discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); + let discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); self.check_expr_has_type_or_error(discrim, discrim_ty); - }; - - // If there are no arms, that is a diverging match; a special case. - if arms.is_empty() { - self.diverges.set(self.diverges.get() | Diverges::Always); - return tcx.types.never; + discrim_ty } - - if self.diverges.get().always() { - for arm in arms { - self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm"); - } - } - - // Otherwise, we have to union together the types that the - // arms produce and so forth. - let discrim_diverges = self.diverges.get(); - self.diverges.set(Diverges::Maybe); - - // rust-lang/rust#55810: Typecheck patterns first (via eager - // collection into `Vec`), so we get types for all bindings. - let all_arm_pats_diverge: Vec<_> = arms.iter().map(|arm| { - let mut all_pats_diverge = Diverges::WarnedAlways; - for p in &arm.pats { - self.diverges.set(Diverges::Maybe); - self.check_pat_walk( - &p, - discrim_ty, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), - Some(discrim.span), - ); - all_pats_diverge &= self.diverges.get(); - } - - // As discussed with @eddyb, this is for disabling unreachable_code - // warnings on patterns (they're now subsumed by unreachable_patterns - // warnings). - match all_pats_diverge { - Diverges::Maybe => Diverges::Maybe, - Diverges::Always | Diverges::WarnedAlways => Diverges::WarnedAlways, - } - }).collect(); - - // Now typecheck the blocks. - // - // The result of the match is the common supertype of all the - // arms. Start out the value as bottom, since it's the, well, - // bottom the type lattice, and we'll be moving up the lattice as - // we process each arm. (Note that any match with 0 arms is matching - // on any empty type and is therefore unreachable; should the flow - // of execution reach it, we will panic, so bottom is an appropriate - // type in that case) - let mut all_arms_diverge = Diverges::WarnedAlways; - - let expected = expected.adjust_for_branches(self); - - let mut coercion = { - let coerce_first = match expected { - // We don't coerce to `()` so that if the match expression is a - // statement it's branches can have any consistent type. That allows - // us to give better error messages (pointing to a usually better - // arm for inconsistent arms or to the whole match when a `()` type - // is required). - Expectation::ExpectHasType(ety) if ety != self.tcx.mk_unit() => ety, - _ => self.next_ty_var(TypeVariableOrigin::MiscVariable(expr.span)), - }; - CoerceMany::with_coercion_sites(coerce_first, arms) - }; - - let mut other_arms = vec![]; // used only for diagnostics - let mut prior_arm_ty = None; - for (i, (arm, pats_diverge)) in arms.iter().zip(all_arm_pats_diverge).enumerate() { - if let Some(ref g) = arm.guard { - self.diverges.set(pats_diverge); - match g { - hir::Guard::If(e) => self.check_expr_has_type_or_error(e, tcx.types.bool), - }; - } - - self.diverges.set(pats_diverge); - let arm_ty = self.check_expr_with_expectation(&arm.body, expected); - all_arms_diverge &= self.diverges.get(); - - // Handle the fallback arm of a desugared if-let like a missing else. - let is_if_let_fallback = match match_src { - hir::MatchSource::IfLetDesugar { contains_else_clause: false } => { - i == arms.len() - 1 && arm_ty.is_unit() - } - _ => false - }; - - let arm_span = if let hir::ExprKind::Block(ref blk, _) = arm.body.node { - // Point at the block expr instead of the entire block - blk.expr.as_ref().map(|e| e.span).unwrap_or(arm.body.span) - } else { - arm.body.span - }; - if is_if_let_fallback { - let cause = self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse); - assert!(arm_ty.is_unit()); - coercion.coerce_forced_unit(self, &cause, &mut |_| (), true); - } else { - let cause = if i == 0 { - // The reason for the first arm to fail is not that the match arms diverge, - // but rather that there's a prior obligation that doesn't hold. - self.cause(arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)) - } else { - self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { - arm_span, - source: match_src, - prior_arms: other_arms.clone(), - last_ty: prior_arm_ty.unwrap(), - discrim_hir_id: discrim.hir_id, - }) - }; - coercion.coerce(self, &cause, &arm.body, arm_ty); - } - other_arms.push(arm_span); - if other_arms.len() > 5 { - other_arms.remove(0); - } - prior_arm_ty = Some(arm_ty); - } - - // We won't diverge unless the discriminant or all arms diverge. - self.diverges.set(discrim_diverges | all_arms_diverge); - - coercion.complete(self) } fn check_pat_struct( @@ -800,7 +996,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); etc: bool, expected: Ty<'tcx>, def_bm: ty::BindingMode, - match_discrim_span: Option, + discrim_span: Option, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. @@ -809,18 +1005,13 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); variant_ty } else { for field in fields { - self.check_pat_walk( - &field.node.pat, - self.tcx.types.err, - def_bm, - match_discrim_span, - ); + self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, discrim_span); } return self.tcx.types.err; }; // Type-check the path. - self.demand_eqtype_pat(pat.span, expected, pat_ty, match_discrim_span); + self.demand_eqtype_pat(pat.span, expected, pat_ty, discrim_span); // Type-check subpatterns. if self.check_struct_pat_fields(pat_ty, pat.hir_id, pat.span, variant, fields, etc, def_bm) diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index d21ceb983f8f..90b2643d165b 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -68,6 +68,7 @@ use smallvec::{smallvec, SmallVec}; use std::ops::Deref; use syntax::feature_gate; use syntax::ptr::P; +use syntax::symbol::sym; use syntax_pos; struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { @@ -620,7 +621,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion { feature_gate::emit_feature_err(&self.tcx.sess.parse_sess, - "unsized_tuple_coercion", + sym::unsized_tuple_coercion, self.cause.span, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION); @@ -1248,12 +1249,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E> augment_error(&mut db); } - if expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some() { - // Error reported in `check_assign` so avoid emitting error again. - db.delay_as_bug(); - } else { - db.emit(); - } + // Error possibly reported in `check_assign` so avoid emitting error again. + db.emit_unless(expression.filter(|e| fcx.is_assign_to_bool(e, expected)).is_some()); self.final_ty = Some(fcx.tcx.types.err); } diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 1699447886ae..8d68179b495c 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -2,6 +2,7 @@ use crate::check::FnCtxt; use rustc::infer::InferOk; use rustc::traits::{self, ObligationCause, ObligationCauseCode}; +use syntax::symbol::sym; use syntax::util::parser::PREC_POSTFIX; use syntax_pos::Span; use rustc::hir; @@ -197,7 +198,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // FIXME? Other potential candidate methods: `as_ref` and // `as_mut`? - .find(|a| a.check_name("rustc_conversion_suggestion")).is_some() + .find(|a| a.check_name(sym::rustc_conversion_suggestion)).is_some() }); methods diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 40c60caffa42..c6191e6b579c 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -7,7 +7,7 @@ use rustc::ty::subst::Subst; use crate::require_same_types; use rustc_target::spec::abi::Abi; -use syntax::symbol::Symbol; +use syntax::symbol::InternedString; use rustc::hir; @@ -80,7 +80,7 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety { /// 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_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str()); + let param = |n| tcx.mk_ty_param(n, InternedString::intern(&format!("P{}", n))); let name = it.ident.as_str(); let mk_va_list_ty = || { @@ -397,7 +397,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_interned_str(); + let name = InternedString::intern(&format!("P{}", n)); tcx.mk_ty_param(n, name) }; diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b57ae361eb69..77d2ffab8efb 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -91,14 +91,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.associated_item(impl_did, item_name, Namespace::Value) - .or_else(|| { - self.associated_item( - self.tcx.impl_trait_ref(impl_did).unwrap().def_id, - item_name, - Namespace::Value, - ) - }).unwrap(); + let item = match self.associated_item( + impl_did, + item_name, + Namespace::Value, + ).or_else(|| { + let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?; + self.associated_item( + impl_trait_ref.def_id, + item_name, + Namespace::Value, + ) + }) { + Some(item) => item, + None => continue, + }; let note_span = self.tcx.hir().span_if_local(item.def_id).or_else(|| { self.tcx.hir().span_if_local(impl_did) }); @@ -132,9 +139,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } CandidateSource::TraitSource(trait_did) => { - let item = self - .associated_item(trait_did, item_name, Namespace::Value) - .unwrap(); + let item = match self.associated_item( + trait_did, + item_name, + Namespace::Value) + { + Some(item) => item, + None => continue, + }; let item_span = self.tcx.sess.source_map() .def_span(self.tcx.def_span(item.def_id)); if sources.len() > 1 { @@ -251,8 +263,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let &QPath::Resolved(_, ref path) = &qpath { if let hir::def::Res::Local(hir_id) = path.res { let span = tcx.hir().span_by_hir_id(hir_id); - let snippet = tcx.sess.source_map().span_to_snippet(span) - .unwrap(); + let snippet = tcx.sess.source_map().span_to_snippet(span); let filename = tcx.sess.source_map().span_to_filename(span); let parent_node = self.tcx.hir().get_by_hir_id( @@ -263,12 +274,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { concrete_type, ); - match (filename, parent_node) { + match (filename, parent_node, snippet) { (FileName::Real(_), Node::Local(hir::Local { source: hir::LocalSource::Normal, ty, .. - })) => { + }), Ok(ref snippet)) => { err.span_suggestion( // account for `let x: _ = 42;` // ^^^^ @@ -375,14 +386,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.hir().get_parent_node_by_hir_id(expr.hir_id), ); - let span = call_expr.span.trim_start(item_name.span).unwrap(); - - err.span_suggestion( - span, - "remove the arguments", - String::new(), - Applicability::MaybeIncorrect, - ); + if let Some(span) = call_expr.span.trim_start(item_name.span) { + err.span_suggestion( + span, + "remove the arguments", + String::new(), + Applicability::MaybeIncorrect, + ); + } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 965f52be31cd..362b6f0504d9 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -117,12 +117,13 @@ use rustc::ty::subst::{UnpackedKind, Subst, InternalSubsts, SubstsRef, UserSelfT use rustc::ty::util::{Representability, IntTypeExt, Discr}; use rustc::ty::layout::VariantIdx; use syntax_pos::{self, BytePos, Span, MultiSpan}; +use syntax_pos::hygiene::CompilerDesugaringKind; use syntax::ast; use syntax::attr; use syntax::feature_gate::{GateIssue, emit_feature_err}; use syntax::ptr::P; use syntax::source_map::{DUMMY_SP, original_sp}; -use syntax::symbol::{Symbol, LocalInternedString, keywords}; +use syntax::symbol::{Symbol, LocalInternedString, keywords, sym}; use syntax::util::lev_distance::find_best_match_for_name; use std::cell::{Cell, RefCell, Ref, RefMut}; @@ -1086,12 +1087,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Add formal parameters. for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { // Check the pattern. - fcx.check_pat_walk( - &arg.pat, - arg_ty, - ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), - None, - ); + let binding_mode = ty::BindingMode::BindByValue(hir::Mutability::MutImmutable); + fcx.check_pat_walk(&arg.pat, arg_ty, binding_mode, None); // Check that argument is Sized. // The check for a non-trivial pattern is a hack to avoid duplicate warnings @@ -1843,7 +1840,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if vs.is_empty() { let attributes = tcx.get_attrs(def_id); - if let Some(attr) = attr::find_by_name(&attributes, "repr") { + if let Some(attr) = attr::find_by_name(&attributes, sym::repr) { struct_span_err!( tcx.sess, attr.span, E0084, "unsupported representation for zero-variant enum") @@ -1856,7 +1853,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { if !tcx.features().repr128 { emit_feature_err(&tcx.sess.parse_sess, - "repr128", + sym::repr128, sp, GateIssue::Language, "repr with 128-bit type is unstable"); @@ -2045,15 +2042,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { - if self.diverges.get() == Diverges::Always { + if self.diverges.get() == Diverges::Always && + // If span arose from a desugaring of `if` then it is the condition itself, + // which diverges, that we are about to lint on. This gives suboptimal diagnostics + // and so we stop here and allow the block of the `if`-expression to be linted instead. + !span.is_compiler_desugaring(CompilerDesugaringKind::IfTemporary) { self.diverges.set(Diverges::WarnedAlways); debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - self.tcx().lint_hir( - lint::builtin::UNREACHABLE_CODE, - id, span, - &format!("unreachable {}", kind)); + let msg = format!("unreachable {}", kind); + self.tcx().lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, &msg); } } @@ -3084,7 +3083,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // AST fragment checking fn check_lit(&self, - lit: &ast::Lit, + lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { @@ -3161,13 +3160,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } if let Some(mut err) = self.demand_suptype_diag(expr.span, expected_ty, ty) { - if self.is_assign_to_bool(expr, expected_ty) { - // Error reported in `check_assign` so avoid emitting error again. - // FIXME(centril): Consider removing if/when `if` desugars to `match`. - err.delay_as_bug(); - } else { - err.emit(); - } + let expr = match &expr.node { + ExprKind::DropTemps(expr) => expr, + _ => expr, + }; + // Error possibly reported in `check_assign` so avoid emitting error again. + err.emit_unless(self.is_assign_to_bool(expr, expected_ty)); } ty } @@ -3330,194 +3328,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return_expr_ty); } - // A generic function for checking the 'then' and 'else' clauses in an 'if' - // or 'if-else' expression. - fn check_then_else(&self, - cond_expr: &'gcx hir::Expr, - then_expr: &'gcx hir::Expr, - opt_else_expr: Option<&'gcx hir::Expr>, - sp: Span, - expected: Expectation<'tcx>) -> Ty<'tcx> { - let cond_ty = self.check_expr_has_type_or_error(cond_expr, self.tcx.types.bool); - let cond_diverges = self.diverges.get(); - self.diverges.set(Diverges::Maybe); - - let expected = expected.adjust_for_branches(self); - let then_ty = self.check_expr_with_expectation(then_expr, expected); - let then_diverges = self.diverges.get(); - self.diverges.set(Diverges::Maybe); - - // We've already taken the expected type's preferences - // into account when typing the `then` branch. To figure - // out the initial shot at a LUB, we thus only consider - // `expected` if it represents a *hard* constraint - // (`only_has_type`); otherwise, we just go with a - // fresh type variable. - let coerce_to_ty = expected.coercion_target_type(self, sp); - let mut coerce: DynamicCoerceMany<'_, '_> = CoerceMany::new(coerce_to_ty); - - coerce.coerce(self, &self.misc(sp), then_expr, then_ty); - - if let Some(else_expr) = opt_else_expr { - let else_ty = self.check_expr_with_expectation(else_expr, expected); - let else_diverges = self.diverges.get(); - - let mut outer_sp = if self.tcx.sess.source_map().is_multiline(sp) { - // The `if`/`else` isn't in one line in the output, include some context to make it - // clear it is an if/else expression: - // ``` - // LL | let x = if true { - // | _____________- - // LL || 10i32 - // || ----- expected because of this - // LL || } else { - // LL || 10u32 - // || ^^^^^ expected i32, found u32 - // LL || }; - // ||_____- if and else have incompatible types - // ``` - Some(sp) - } else { - // The entire expression is in one line, only point at the arms - // ``` - // LL | let x = if true { 10i32 } else { 10u32 }; - // | ----- ^^^^^ expected i32, found u32 - // | | - // | expected because of this - // ``` - None - }; - let mut remove_semicolon = None; - let error_sp = if let ExprKind::Block(block, _) = &else_expr.node { - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - remove_semicolon = self.could_remove_semicolon(block, then_ty); - stmt.span - } else { // empty block, point at its entirety - // Avoid overlapping spans that aren't as readable: - // ``` - // 2 | let x = if true { - // | _____________- - // 3 | | 3 - // | | - expected because of this - // 4 | | } else { - // | |____________^ - // 5 | || - // 6 | || }; - // | || ^ - // | ||_____| - // | |______if and else have incompatible types - // | expected integer, found () - // ``` - // by not pointing at the entire expression: - // ``` - // 2 | let x = if true { - // | ------- if and else have incompatible types - // 3 | 3 - // | - expected because of this - // 4 | } else { - // | ____________^ - // 5 | | - // 6 | | }; - // | |_____^ expected integer, found () - // ``` - if outer_sp.is_some() { - outer_sp = Some(self.tcx.sess.source_map().def_span(sp)); - } - else_expr.span - } - } else { // shouldn't happen unless the parser has done something weird - else_expr.span - }; - let then_sp = if let ExprKind::Block(block, _) = &then_expr.node { - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - remove_semicolon = remove_semicolon.or( - self.could_remove_semicolon(block, else_ty)); - stmt.span - } else { // empty block, point at its entirety - outer_sp = None; // same as in `error_sp`, cleanup output - then_expr.span - } - } else { // shouldn't happen unless the parser has done something weird - then_expr.span - }; - - let if_cause = self.cause(error_sp, ObligationCauseCode::IfExpression { - then: then_sp, - outer: outer_sp, - semicolon: remove_semicolon, - }); - - coerce.coerce(self, &if_cause, else_expr, else_ty); - - // We won't diverge unless both branches do (or the condition does). - self.diverges.set(cond_diverges | then_diverges & else_diverges); - } else { - // If this `if` expr is the parent's function return expr, the cause of the type - // coercion is the return type, point at it. (#25228) - let ret_reason = self.maybe_get_coercion_reason(then_expr.hir_id, sp); - - let else_cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse); - coerce.coerce_forced_unit(self, &else_cause, &mut |err| { - if let Some((sp, msg)) = &ret_reason { - err.span_label(*sp, msg.as_str()); - } else if let ExprKind::Block(block, _) = &then_expr.node { - if let Some(expr) = &block.expr { - err.span_label(expr.span, "found here".to_string()); - } - } - err.note("`if` expressions without `else` evaluate to `()`"); - err.help("consider adding an `else` block that evaluates to the expected type"); - }, ret_reason.is_none()); - - // If the condition is false we can't diverge. - self.diverges.set(cond_diverges); - } - - let result_ty = coerce.complete(self); - if cond_ty.references_error() { - self.tcx.types.err - } else { - result_ty - } - } - - fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Span, String)> { - let node = self.tcx.hir().get_by_hir_id(self.tcx.hir().get_parent_node_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id(hir_id), - )); - if let Node::Block(block) = node { - // check that the body's parent is an fn - let parent = self.tcx.hir().get_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id( - self.tcx.hir().get_parent_node_by_hir_id(block.hir_id), - ), - ); - if let (Some(expr), Node::Item(hir::Item { - node: hir::ItemKind::Fn(..), .. - })) = (&block.expr, parent) { - // check that the `if` expr without `else` is the fn body's expr - if expr.span == sp { - return self.get_fn_decl(hir_id).map(|(fn_decl, _)| ( - fn_decl.output.span(), - format!("expected `{}` because of this return type", fn_decl.output), - )); - } - } - } - if let Node::Local(hir::Local { - ty: Some(_), pat, .. - }) = node { - return Some((pat.span, "expected because of this assignment".to_string())); - } - None - } - // Check field access expressions fn check_field(&self, expr: &'gcx hir::Expr, @@ -4062,7 +3872,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match expr.node { ExprKind::Block(..) | ExprKind::Loop(..) | ExprKind::While(..) | - ExprKind::If(..) | ExprKind::Match(..) => {} + ExprKind::Match(..) => {} _ => self.warn_if_unreachable(expr.hir_id, expr.span, "expression") } @@ -4387,7 +4197,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // ... except when we try to 'break rust;'. // ICE this expression in particular (see #43162). if let ExprKind::Path(QPath::Resolved(_, ref path)) = e.node { - if path.segments.len() == 1 && path.segments[0].ident.name == "rust" { + if path.segments.len() == 1 && + path.segments[0].ident.name == sym::rust { fatally_break_rust(self.tcx.sess); } } @@ -4444,10 +4255,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ExprKind::Assign(ref lhs, ref rhs) => { self.check_assign(expr, expected, lhs, rhs) } - ExprKind::If(ref cond, ref then_expr, ref opt_else_expr) => { - self.check_then_else(&cond, then_expr, opt_else_expr.as_ref().map(|e| &**e), - expr.span, expected) - } ExprKind::While(ref cond, ref body, _) => { let ctxt = BreakableCtxt { // cannot use break with a value from a while loop @@ -5261,7 +5068,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match expression.node { ExprKind::Call(..) | ExprKind::MethodCall(..) | - ExprKind::If(..) | ExprKind::While(..) | ExprKind::Loop(..) | ExprKind::Match(..) | @@ -5669,10 +5475,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { - span_bug!(span, + self.tcx.sess.delay_span_bug(span, &format!( "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", self_ty, - impl_ty); + impl_ty, + )); } } } @@ -5693,7 +5500,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { span: Span) { // We're only interested in functions tagged with // #[rustc_args_required_const], so ignore anything that's not. - if !self.tcx.has_attr(def_id, "rustc_args_required_const") { + if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { return } diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d1ca05780930..cd207478f8f6 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -305,8 +305,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, true, op) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, true, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " += "World!"). This means // we don't want the note in the else clause to be emitted @@ -400,8 +400,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, false, op) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, false, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted @@ -502,9 +502,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { false } + /// Provide actionable suggestions when trying to add two strings with incorrect types, + /// like `&str + &str`, `String + String` and `&str + &String`. + /// + /// If this function returns `true` it means a note was printed, so we don't need + /// to print the normal "implementation of `std::ops::Add` might be missing" note fn check_str_addition( &self, - expr: &'gcx hir::Expr, lhs_expr: &'gcx hir::Expr, rhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, @@ -514,45 +518,78 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op: hir::BinOp, ) -> bool { let source_map = self.tcx.sess.source_map(); + let remove_borrow_msg = "String concatenation appends the string on the right to the \ + string on the left and may require reallocation. This \ + requires ownership of the string on the left"; + let msg = "`to_owned()` can be used to create an owned `String` \ from a string reference. String concatenation \ appends the string on the right to the string \ on the left and may require reallocation. This \ requires ownership of the string on the left"; - // If this function returns true it means a note was printed, so we don't need - // to print the normal "implementation of `std::ops::Add` might be missing" note + + let is_std_string = |ty| &format!("{:?}", ty) == "std::string::String"; + match (&lhs_ty.sty, &rhs_ty.sty) { - (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) - if l_ty.sty == Str && r_ty.sty == Str => { - if !is_assign { - err.span_label(op.span, - "`+` can't be used to concatenate two `&str` strings"); + (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str + if (l_ty.sty == Str || is_std_string(l_ty)) && ( + r_ty.sty == Str || is_std_string(r_ty) || + &format!("{:?}", rhs_ty) == "&&str" + ) => + { + if !is_assign { // Do not supply this message if `&str += &str` + err.span_label( + op.span, + "`+` cannot be used to concatenate two `&str` strings", + ); match source_map.span_to_snippet(lhs_expr.span) { - Ok(lstring) => err.span_suggestion( - lhs_expr.span, - msg, - format!("{}.to_owned()", lstring), - Applicability::MachineApplicable, - ), + Ok(lstring) => { + err.span_suggestion( + lhs_expr.span, + if lstring.starts_with("&") { + remove_borrow_msg + } else { + msg + }, + if lstring.starts_with("&") { + // let a = String::new(); + // let _ = &a + "bar"; + format!("{}", &lstring[1..]) + } else { + format!("{}.to_owned()", lstring) + }, + Applicability::MachineApplicable, + ) + } _ => err.help(msg), }; } true } - (&Ref(_, l_ty, _), &Adt(..)) - if l_ty.sty == Str && &format!("{:?}", rhs_ty) == "std::string::String" => { - err.span_label(expr.span, - "`+` can't be used to concatenate a `&str` with a `String`"); + (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` + if (l_ty.sty == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => + { + err.span_label( + op.span, + "`+` cannot be used to concatenate a `&str` with a `String`", + ); match ( source_map.span_to_snippet(lhs_expr.span), source_map.span_to_snippet(rhs_expr.span), is_assign, ) { (Ok(l), Ok(r), false) => { + let to_string = if l.starts_with("&") { + // let a = String::new(); let b = String::new(); + // let _ = &a + b; + format!("{}", &l[1..]) + } else { + format!("{}.to_owned()", l) + }; err.multipart_suggestion( msg, vec![ - (lhs_expr.span, format!("{}.to_owned()", l)), + (lhs_expr.span, to_string), (rhs_expr.span, format!("&{}", r)), ], Applicability::MachineApplicable, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index fd7d6fe694cc..b009c8ea6dce 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -13,6 +13,7 @@ use rustc::infer::opaque_types::may_define_existential_type; use syntax::ast; use syntax::feature_gate::{self, GateIssue}; use syntax_pos::Span; +use syntax::symbol::sym; use errors::{DiagnosticBuilder, DiagnosticId}; use rustc::hir::itemlikevisit::ParItemLikeVisitor; @@ -796,7 +797,7 @@ fn check_method_receiver<'fcx, 'gcx, 'tcx>(fcx: &FnCtxt<'fcx, 'gcx, 'tcx>, // report error, would have worked with arbitrary_self_types feature_gate::feature_err( &fcx.tcx.sess.parse_sess, - "arbitrary_self_types", + sym::arbitrary_self_types, span, GateIssue::Language, &format!( diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index f9d83146e30c..13baf667808f 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -16,6 +16,7 @@ use rustc::mir::interpret::ConstValue; use rustc::util::nodemap::DefIdSet; use rustc_data_structures::sync::Lrc; use std::mem; +use syntax::symbol::sym; use syntax_pos::Span; /////////////////////////////////////////////////////////////////////////// @@ -36,8 +37,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let item_def_id = self.tcx.hir().local_def_id(item_id); // This attribute causes us to dump some writeback information - // in the form of errors, which is used for unit tests. - let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, "rustc_dump_user_substs"); + // in the form of errors, which is uSymbolfor unit tests. + let rustc_dump_user_substs = self.tcx.has_attr(item_def_id, sym::rustc_dump_user_substs); let mut wbcx = WritebackCx::new(self, body, rustc_dump_user_substs); for arg in &body.arguments { @@ -465,6 +466,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap(); let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id); + debug_assert!(!instantiated_ty.has_escaping_bound_vars()); + let generics = self.tcx().generics_of(def_id); let definition_ty = if generics.parent.is_some() { @@ -523,8 +526,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { }, lt_op: |region| { match region { - // ignore static regions - ty::ReStatic => region, + // Skip static and bound regions: they don't + // require substitution. + ty::ReStatic | ty::ReLateBound(..) => region, _ => { trace!("checking {:?}", region); for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) { @@ -611,26 +615,33 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } - let new = ty::ResolvedOpaqueTy { - concrete_type: definition_ty, - substs: self.tcx().lift_to_global(&opaque_defn.substs).unwrap(), - }; + if let Some(substs) = self.tcx().lift_to_global(&opaque_defn.substs) { + let new = ty::ResolvedOpaqueTy { + concrete_type: definition_ty, + substs, + }; - let old = self.tables - .concrete_existential_types - .insert(def_id, new); - if let Some(old) = old { - if old.concrete_type != definition_ty || old.substs != opaque_defn.substs { - span_bug!( - span, - "visit_opaque_types tried to write \ - different types for the same existential type: {:?}, {:?}, {:?}, {:?}", - def_id, - definition_ty, - opaque_defn, - old, - ); + let old = self.tables + .concrete_existential_types + .insert(def_id, new); + if let Some(old) = old { + if old.concrete_type != definition_ty || old.substs != opaque_defn.substs { + span_bug!( + span, + "visit_opaque_types tried to write \ + different types for the same existential type: {:?}, {:?}, {:?}, {:?}", + def_id, + definition_ty, + opaque_defn, + old, + ); + } } + } else { + self.tcx().sess.delay_span_bug( + span, + "cannot lift `opaque_defn` substs to global type context", + ); } } } diff --git a/src/librustc_typeck/check_unused.rs b/src/librustc_typeck/check_unused.rs index cbb6d9b29f59..3c3509f24ce1 100644 --- a/src/librustc_typeck/check_unused.rs +++ b/src/librustc_typeck/check_unused.rs @@ -158,6 +158,13 @@ fn unused_crates_lint<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) { continue; } + // If the extern crate is renamed, then we cannot suggest replacing it with a use as this + // would not insert the new name into the prelude, where other imports in the crate may be + // expecting it. + if extern_crate.orig_name.is_some() { + continue; + } + // If the extern crate has any attributes, they may have funky // semantics we can't faithfully represent using `use` (most // notably `#[macro_use]`). Ignore it. diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs index d0156db32e94..a9951c7fe447 100644 --- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs +++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs @@ -5,8 +5,6 @@ use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::traits::{self, IntercrateMode}; use rustc::ty::TyCtxt; -use crate::lint; - pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) { assert_eq!(crate_num, LOCAL_CRATE); @@ -20,8 +18,7 @@ struct InherentOverlapChecker<'a, 'tcx: 'a> { impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId, - overlap: traits::OverlapResult<'_>, - used_to_be_allowed: bool) { + overlap: traits::OverlapResult<'_>) { let name_and_namespace = |def_id| { let item = self.tcx.associated_item(def_id); @@ -36,22 +33,12 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for &item2 in &impl_items2[..] { if (name, namespace) == name_and_namespace(item2) { - let hir_id = self.tcx.hir().as_local_hir_id(impl1); - let mut err = if used_to_be_allowed && hir_id.is_some() { - self.tcx.struct_span_lint_hir( - lint::builtin::INCOHERENT_FUNDAMENTAL_IMPLS, - hir_id.unwrap(), - self.tcx.span_of_impl(item1).unwrap(), - &format!("duplicate definitions with name `{}` (E0592)", name) - ) - } else { + let mut err = struct_span_err!(self.tcx.sess, self.tcx.span_of_impl(item1).unwrap(), E0592, "duplicate definitions with name `{}`", - name) - }; - + name); err.span_label(self.tcx.span_of_impl(item1).unwrap(), format!("duplicate definitions for `{}`", name)); err.span_label(self.tcx.span_of_impl(item2).unwrap(), @@ -76,7 +63,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { for (i, &impl1_def_id) in impls.iter().enumerate() { for &impl2_def_id in &impls[(i + 1)..] { - let used_to_be_allowed = traits::overlapping_impls( + traits::overlapping_impls( self.tcx, impl1_def_id, impl2_def_id, @@ -86,28 +73,11 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> { impl1_def_id, impl2_def_id, overlap, - false, ); false }, || true, ); - - if used_to_be_allowed { - traits::overlapping_impls( - self.tcx, - impl1_def_id, - impl2_def_id, - IntercrateMode::Fixed, - |overlap| self.check_for_common_items_in_impls( - impl1_def_id, - impl2_def_id, - overlap, - true, - ), - || (), - ); - } } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4185999fdd6d..711d79f95f53 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -39,7 +39,7 @@ use syntax::ast::{Ident, MetaItemKind}; use syntax::attr::{InlineAttr, OptimizeAttr, list_contains_name, mark_used}; use syntax::source_map::Spanned; use syntax::feature_gate; -use syntax::symbol::{keywords, Symbol}; +use syntax::symbol::{InternedString, keywords, Symbol, sym}; use syntax_pos::{Span, DUMMY_SP}; use rustc::hir::def::{CtorKind, Res, DefKind}; @@ -750,7 +750,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty:: _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"), }; - let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar"); + let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar); if paren_sugar && !tcx.features().unboxed_closures { let mut err = tcx.sess.struct_span_err( item.span, @@ -765,7 +765,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty:: err.emit(); } - let is_marker = tcx.has_attr(def_id, "marker"); + let is_marker = tcx.has_attr(def_id, sym::marker); let def_path_hash = tcx.def_path_hash(def_id); let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, is_auto, is_marker, def_path_hash); tcx.alloc_trait_def(def) @@ -1082,7 +1082,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty .enumerate() .map(|(i, &arg)| ty::GenericParamDef { index: type_start + i as u32, - name: Symbol::intern(arg).as_interned_str(), + name: InternedString::intern(arg), def_id, pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { @@ -1097,7 +1097,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty params.extend(upvars.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| { ty::GenericParamDef { index: type_start + i, - name: Symbol::intern("").as_interned_str(), + name: InternedString::intern(""), def_id, pure_wrt_drop: false, kind: ty::GenericParamDefKind::Type { @@ -1404,7 +1404,13 @@ pub fn checked_type_of<'a, 'tcx>( if !fail { return None; } - bug!("unexpected const parent path def {:?}", x); + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent path def {:?}", x + ), + ); + tcx.types.err } } } @@ -1412,7 +1418,13 @@ pub fn checked_type_of<'a, 'tcx>( if !fail { return None; } - bug!("unexpected const parent path {:?}", x); + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent path {:?}", x + ), + ); + tcx.types.err } } } @@ -1421,7 +1433,13 @@ pub fn checked_type_of<'a, 'tcx>( if !fail { return None; } - bug!("unexpected const parent in type_of_def_id(): {:?}", x); + tcx.sess.delay_span_bug( + DUMMY_SP, + &format!( + "unexpected const parent in type_of_def_id(): {:?}", x + ), + ); + tcx.types.err } } } @@ -2382,7 +2400,7 @@ fn from_target_feature( tcx: TyCtxt<'_, '_, '_>, id: DefId, attr: &ast::Attribute, - whitelist: &FxHashMap>, + whitelist: &FxHashMap>, target_features: &mut Vec, ) { let list = match attr.meta_item_list() { @@ -2392,7 +2410,7 @@ fn from_target_feature( let rust_features = tcx.features(); for item in list { // Only `enable = ...` is accepted in the meta item list - if !item.check_name("enable") { + if !item.check_name(sym::enable) { let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \ currently"; tcx.sess.span_err(item.span(), &msg); @@ -2435,29 +2453,29 @@ fn from_target_feature( }; // Only allow features whose feature gates have been enabled - let allowed = match feature_gate.as_ref().map(|s| &**s) { - Some("arm_target_feature") => rust_features.arm_target_feature, - Some("aarch64_target_feature") => rust_features.aarch64_target_feature, - Some("hexagon_target_feature") => rust_features.hexagon_target_feature, - Some("powerpc_target_feature") => rust_features.powerpc_target_feature, - Some("mips_target_feature") => rust_features.mips_target_feature, - Some("avx512_target_feature") => rust_features.avx512_target_feature, - Some("mmx_target_feature") => rust_features.mmx_target_feature, - Some("sse4a_target_feature") => rust_features.sse4a_target_feature, - Some("tbm_target_feature") => rust_features.tbm_target_feature, - Some("wasm_target_feature") => rust_features.wasm_target_feature, - Some("cmpxchg16b_target_feature") => rust_features.cmpxchg16b_target_feature, - Some("adx_target_feature") => rust_features.adx_target_feature, - Some("movbe_target_feature") => rust_features.movbe_target_feature, - Some("rtm_target_feature") => rust_features.rtm_target_feature, - Some("f16c_target_feature") => rust_features.f16c_target_feature, + let allowed = match feature_gate.as_ref().map(|s| *s) { + Some(sym::arm_target_feature) => rust_features.arm_target_feature, + Some(sym::aarch64_target_feature) => rust_features.aarch64_target_feature, + Some(sym::hexagon_target_feature) => rust_features.hexagon_target_feature, + Some(sym::powerpc_target_feature) => rust_features.powerpc_target_feature, + Some(sym::mips_target_feature) => rust_features.mips_target_feature, + Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, + Some(sym::mmx_target_feature) => rust_features.mmx_target_feature, + Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, + Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, + Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, + Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature, + Some(sym::adx_target_feature) => rust_features.adx_target_feature, + Some(sym::movbe_target_feature) => rust_features.movbe_target_feature, + Some(sym::rtm_target_feature) => rust_features.rtm_target_feature, + Some(sym::f16c_target_feature) => rust_features.f16c_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; if !allowed && id.is_local() { feature_gate::emit_feature_err( &tcx.sess.parse_sess, - feature_gate.as_ref().unwrap(), + feature_gate.unwrap(), item.span(), feature_gate::GateIssue::Language, &format!("the target feature `{}` is currently unstable", feature), @@ -2512,13 +2530,13 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen let mut inline_span = None; for attr in attrs.iter() { - if attr.check_name("cold") { + if attr.check_name(sym::cold) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; - } else if attr.check_name("allocator") { + } else if attr.check_name(sym::allocator) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; - } else if attr.check_name("unwind") { + } else if attr.check_name(sym::unwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND; - } else if attr.check_name("ffi_returns_twice") { + } else if attr.check_name(sym::ffi_returns_twice) { if tcx.is_foreign_item(id) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; } else { @@ -2530,21 +2548,21 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen "`#[ffi_returns_twice]` may only be used on foreign functions" ).emit(); } - } else if attr.check_name("rustc_allocator_nounwind") { + } else if attr.check_name(sym::rustc_allocator_nounwind) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND; - } else if attr.check_name("naked") { + } else if attr.check_name(sym::naked) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; - } else if attr.check_name("no_mangle") { + } else if attr.check_name(sym::no_mangle) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; - } else if attr.check_name("rustc_std_internal_symbol") { + } else if attr.check_name(sym::rustc_std_internal_symbol) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; - } else if attr.check_name("no_debug") { + } else if attr.check_name(sym::no_debug) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_DEBUG; - } else if attr.check_name("used") { + } else if attr.check_name(sym::used) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; - } else if attr.check_name("thread_local") { + } else if attr.check_name(sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; - } else if attr.check_name("export_name") { + } else if attr.check_name(sym::export_name) { if let Some(s) = attr.value_str() { if s.as_str().contains("\0") { // `#[export_name = ...]` will be converted to a null-terminated string, @@ -2558,7 +2576,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen } codegen_fn_attrs.export_name = Some(s); } - } else if attr.check_name("target_feature") { + } else if attr.check_name(sym::target_feature) { if tcx.fn_sig(id).unsafety() == Unsafety::Normal { let msg = "#[target_feature(..)] can only be applied to \ `unsafe` function"; @@ -2571,11 +2589,11 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen &whitelist, &mut codegen_fn_attrs.target_features, ); - } else if attr.check_name("linkage") { + } else if attr.check_name(sym::linkage) { if let Some(val) = attr.value_str() { codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str())); } - } else if attr.check_name("link_section") { + } else if attr.check_name(sym::link_section) { if let Some(val) = attr.value_str() { if val.as_str().bytes().any(|b| b == 0) { let msg = format!( @@ -2588,13 +2606,13 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen codegen_fn_attrs.link_section = Some(val); } } - } else if attr.check_name("link_name") { + } else if attr.check_name(sym::link_name) { codegen_fn_attrs.link_name = attr.value_str(); } } codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if attr.path != "inline" { + if attr.path != sym::inline { return ia; } match attr.meta().map(|i| i.node) { @@ -2613,9 +2631,9 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen "expected one argument" ); InlineAttr::None - } else if list_contains_name(&items[..], "always") { + } else if list_contains_name(&items[..], sym::always) { InlineAttr::Always - } else if list_contains_name(&items[..], "never") { + } else if list_contains_name(&items[..], sym::never) { InlineAttr::Never } else { span_err!( @@ -2634,7 +2652,7 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen }); codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { - if attr.path != "optimize" { + if attr.path != sym::optimize { return ia; } let err = |sp, s| span_err!(tcx.sess.diagnostic(), sp, E0722, "{}", s); @@ -2649,9 +2667,9 @@ fn codegen_fn_attrs<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> Codegen if items.len() != 1 { err(attr.span, "expected one argument"); OptimizeAttr::None - } else if list_contains_name(&items[..], "size") { + } else if list_contains_name(&items[..], sym::size) { OptimizeAttr::Size - } else if list_contains_name(&items[..], "speed") { + } else if list_contains_name(&items[..], sym::speed) { OptimizeAttr::Speed } else { err(items[0].span(), "invalid argument"); diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index e3e2fe7106a0..a6b5b99982ec 100644 --- a/src/librustc_typeck/outlives/mod.rs +++ b/src/librustc_typeck/outlives/mod.rs @@ -5,6 +5,7 @@ use rustc::ty::query::Providers; use rustc::ty::subst::UnpackedKind; use rustc::ty::{self, CratePredicatesMap, TyCtxt}; use rustc_data_structures::sync::Lrc; +use syntax::symbol::sym; mod explicit; mod implicit_infer; @@ -40,7 +41,7 @@ fn inferred_outlives_of<'a, 'tcx>( .map(|p| *p) .unwrap_or(&[]); - if tcx.has_attr(item_def_id, "rustc_outlives") { + if tcx.has_attr(item_def_id, sym::rustc_outlives) { let mut pred: Vec = predicates .iter() .map(|out_pred| match out_pred { diff --git a/src/librustc_typeck/outlives/test.rs b/src/librustc_typeck/outlives/test.rs index e10c83612071..54fd4fad1d19 100644 --- a/src/librustc_typeck/outlives/test.rs +++ b/src/librustc_typeck/outlives/test.rs @@ -1,6 +1,7 @@ use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ty::TyCtxt; +use syntax::symbol::sym; pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.hir() @@ -18,7 +19,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> { // For unit testing: check for a special "rustc_outlives" // attribute and report an error with various results if found. - if self.tcx.has_attr(item_def_id, "rustc_outlives") { + if self.tcx.has_attr(item_def_id, sym::rustc_outlives) { let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id); span_err!( self.tcx.sess, diff --git a/src/librustc_typeck/variance/test.rs b/src/librustc_typeck/variance/test.rs index d04b1b276a2c..b5195826b863 100644 --- a/src/librustc_typeck/variance/test.rs +++ b/src/librustc_typeck/variance/test.rs @@ -1,6 +1,7 @@ use rustc::hir; use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::ty::TyCtxt; +use syntax::symbol::sym; pub fn test_variance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { tcx.hir().krate().visit_all_item_likes(&mut VarianceTest { tcx }); @@ -16,7 +17,7 @@ impl<'a, 'tcx> ItemLikeVisitor<'tcx> for VarianceTest<'a, 'tcx> { // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. - if self.tcx.has_attr(item_def_id, "rustc_variance") { + if self.tcx.has_attr(item_def_id, sym::rustc_variance) { let variances_of = self.tcx.variances_of(item_def_id); span_err!(self.tcx.sess, item.span, diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index 69445451503c..61399e0568cb 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -7,7 +7,7 @@ use std::mem; use std::fmt::{self, Write}; use std::ops; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::ast::{MetaItem, MetaItemKind, NestedMetaItem, LitKind}; use syntax::parse::ParseSess; use syntax::feature_gate::Features; @@ -186,7 +186,7 @@ impl Cfg { fn should_use_with_in_description(&self) -> bool { match *self { - Cfg::Cfg(ref name, _) if name == &"target_feature" => true, + Cfg::Cfg(name, _) if name == sym::target_feature => true, _ => false, } } @@ -338,7 +338,6 @@ impl<'a> fmt::Display for Html<'a> { ("debug_assertions", None) => "debug-assertions enabled", ("target_os", Some(os)) => match &*os.as_str() { "android" => "Android", - "bitrig" => "Bitrig", "dragonfly" => "DragonFly BSD", "emscripten" => "Emscripten", "freebsd" => "FreeBSD", @@ -414,10 +413,11 @@ impl<'a> fmt::Display for Html<'a> { mod test { use super::Cfg; - use syntax::symbol::Symbol; - use syntax::ast::*; - use syntax::source_map::dummy_spanned; use syntax_pos::DUMMY_SP; + use syntax::ast::*; + use syntax::attr; + use syntax::source_map::dummy_spanned; + use syntax::symbol::Symbol; use syntax::with_globals; fn word_cfg(s: &str) -> Cfg { @@ -592,14 +592,10 @@ mod test { let mi = dummy_meta_item_word("all"); assert_eq!(Cfg::parse(&mi), Ok(word_cfg("all"))); - let mi = MetaItem { - path: Path::from_ident(Ident::from_str("all")), - node: MetaItemKind::NameValue(dummy_spanned(LitKind::Str( - Symbol::intern("done"), - StrStyle::Cooked, - ))), - span: DUMMY_SP, - }; + let mi = attr::mk_name_value_item_str( + Ident::from_str("all"), + dummy_spanned(Symbol::intern("done")) + ); assert_eq!(Cfg::parse(&mi), Ok(name_value_cfg("all", "done"))); let mi = dummy_meta_item_list!(all, [a, b]); @@ -627,11 +623,12 @@ mod test { #[test] fn test_parse_err() { with_globals(|| { - let mi = MetaItem { - path: Path::from_ident(Ident::from_str("foo")), - node: MetaItemKind::NameValue(dummy_spanned(LitKind::Bool(false))), - span: DUMMY_SP, - }; + let mi = attr::mk_name_value_item( + DUMMY_SP, + Ident::from_str("foo"), + LitKind::Bool(false), + DUMMY_SP, + ); assert!(Cfg::parse(&mi).is_err()); let mi = dummy_meta_item_list!(not, [a, b]); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index d9d6b8e07e99..15108a7dbb91 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -4,6 +4,7 @@ use std::iter::once; use syntax::ast; use syntax::ext::base::{MacroKind, SyntaxExtension}; +use syntax::symbol::sym; use syntax_pos::Span; use rustc::hir; @@ -186,7 +187,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let generics = (cx.tcx.generics_of(did), &predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); - let is_spotlight = load_attrs(cx, did).has_doc_flag("spotlight"); + let is_spotlight = load_attrs(cx, did).has_doc_flag(sym::spotlight); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { auto: auto_trait, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3a260db80652..e434623d4a12 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -32,6 +32,7 @@ use syntax::ext::base::MacroKind; use syntax::source_map::{dummy_spanned, Spanned}; use syntax::ptr::P; use syntax::symbol::keywords::{self, Keyword}; +use syntax::symbol::{Symbol, sym}; use syntax::symbol::InternedString; use syntax_pos::{self, Pos, FileName}; @@ -170,7 +171,7 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { // `compiler_builtins` should be masked too, but we can't apply // `#[doc(masked)]` to the injected `extern crate` because it's unstable. if it.is_extern_crate() - && (it.attrs.has_doc_flag("masked") + && (it.attrs.has_doc_flag(sym::masked) || self.cx.tcx.is_compiler_builtins(it.def_id.krate)) { masked_crates.insert(it.def_id.krate); @@ -261,9 +262,9 @@ impl Clean for CrateNum { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = cx.tcx.get_attrs(def_id).clean(cx); let mut prim = None; - for attr in attrs.lists("doc") { + for attr in attrs.lists(sym::doc) { if let Some(v) = attr.value_str() { - if attr.check_name("primitive") { + if attr.check_name(sym::primitive) { prim = PrimitiveType::from_str(&v.as_str()); if prim.is_some() { break; @@ -305,9 +306,9 @@ impl Clean for CrateNum { if let Res::Def(DefKind::Mod, def_id) = res { let attrs = cx.tcx.get_attrs(def_id).clean(cx); let mut keyword = None; - for attr in attrs.lists("doc") { + for attr in attrs.lists(sym::doc) { if let Some(v) = attr.value_str() { - if attr.check_name("keyword") { + if attr.check_name(sym::keyword) { keyword = Keyword::from_str(&v.as_str()).ok() .map(|x| x.name().to_string()); if keyword.is_some() { @@ -501,7 +502,7 @@ impl Item { pub fn is_non_exhaustive(&self) -> bool { self.attrs.other_attrs.iter() - .any(|a| a.check_name("non_exhaustive")) + .any(|a| a.check_name(sym::non_exhaustive)) } /// Returns a documentation-level item type from the item. @@ -669,7 +670,7 @@ impl Clean for doctree::Module { pub struct ListAttributesIter<'a> { attrs: slice::Iter<'a, ast::Attribute>, current_list: vec::IntoIter, - name: &'a str + name: Symbol, } impl<'a> Iterator for ListAttributesIter<'a> { @@ -702,11 +703,11 @@ impl<'a> Iterator for ListAttributesIter<'a> { pub trait AttributesExt { /// Finds an attribute as List and returns the list of attributes nested inside. - fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a>; + fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a>; } impl AttributesExt for [ast::Attribute] { - fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { + fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> { ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), @@ -717,11 +718,11 @@ impl AttributesExt for [ast::Attribute] { pub trait NestedAttributesExt { /// Returns `true` if the attribute list contains a specific `Word` - fn has_word(self, word: &str) -> bool; + fn has_word(self, word: Symbol) -> bool; } impl> NestedAttributesExt for I { - fn has_word(self, word: &str) -> bool { + fn has_word(self, word: Symbol) -> bool { self.into_iter().any(|attr| attr.is_word() && attr.check_name(word)) } } @@ -803,7 +804,7 @@ impl Attributes { if let ast::MetaItemKind::List(ref nmis) = mi.node { if nmis.len() == 1 { if let MetaItem(ref cfg_mi) = nmis[0] { - if cfg_mi.check_name("cfg") { + if cfg_mi.check_name(sym::cfg) { if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.node { if cfg_nmis.len() == 1 { if let MetaItem(ref content_mi) = cfg_nmis[0] { @@ -827,7 +828,7 @@ impl Attributes { { mi.meta_item_list().and_then(|list| { for meta in list { - if meta.check_name("include") { + if meta.check_name(sym::include) { // the actual compiled `#[doc(include="filename")]` gets expanded to // `#[doc(include(file="filename", contents="file contents")]` so we need to // look for that instead @@ -836,11 +837,11 @@ impl Attributes { let mut contents: Option = None; for it in list { - if it.check_name("file") { + if it.check_name(sym::file) { if let Some(name) = it.value_str() { filename = Some(name.to_string()); } - } else if it.check_name("contents") { + } else if it.check_name(sym::contents) { if let Some(docs) = it.value_str() { contents = Some(docs.to_string()); } @@ -860,9 +861,9 @@ impl Attributes { }) } - pub fn has_doc_flag(&self, flag: &str) -> bool { + pub fn has_doc_flag(&self, flag: Symbol) -> bool { for attr in &self.other_attrs { - if !attr.check_name("doc") { continue; } + if !attr.check_name(sym::doc) { continue; } if let Some(items) = attr.meta_item_list() { if items.iter().filter_map(|i| i.meta_item()).any(|it| it.check_name(flag)) { @@ -883,7 +884,7 @@ impl Attributes { let other_attrs = attrs.iter().filter_map(|attr| { attr.with_desugared_doc(|attr| { - if attr.check_name("doc") { + if attr.check_name(sym::doc) { if let Some(mi) = attr.meta() { if let Some(value) = mi.value_str() { // Extracted #[doc = "..."] @@ -925,11 +926,12 @@ impl Attributes { // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well - for attr in attrs.lists("target_feature") { - if attr.check_name("enable") { + for attr in attrs.lists(sym::target_feature) { + if attr.check_name(sym::enable) { if let Some(feat) = attr.value_str() { - let meta = attr::mk_name_value_item_str(Ident::from_str("target_feature"), - dummy_spanned(feat)); + let meta = attr::mk_name_value_item_str( + Ident::with_empty_ctxt(sym::target_feature), + dummy_spanned(feat)); if let Ok(feat_cfg) = Cfg::parse(&meta) { cfg &= feat_cfg; } @@ -938,7 +940,7 @@ impl Attributes { } let inner_docs = attrs.iter() - .filter(|a| a.check_name("doc")) + .filter(|a| a.check_name(sym::doc)) .next() .map_or(true, |a| a.style == AttrStyle::Inner); @@ -1039,7 +1041,7 @@ impl Hash for Attributes { } impl AttributesExt for Attributes { - fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> { + fn lists<'a>(&'a self, name: Symbol) -> ListAttributesIter<'a> { self.other_attrs.lists(name) } } @@ -2133,7 +2135,7 @@ pub struct Trait { impl Clean for doctree::Trait { fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); - let is_spotlight = attrs.has_doc_flag("spotlight"); + let is_spotlight = attrs.has_doc_flag(sym::spotlight); Item { name: Some(self.name.clean(cx)), attrs: attrs, @@ -3147,7 +3149,10 @@ impl<'tcx> Clean for ty::Const<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> Constant { Constant { type_: self.ty.clean(cx), - expr: format!("{:?}", self.val), // FIXME(const_generics) + expr: match self.val { + ConstValue::Param(ty::ParamConst { name, .. }) => format!("{}", name), + e => format!("{:?}", e), // FIXME generic consts with expressions + }, } } } @@ -3403,6 +3408,7 @@ pub struct Span { pub locol: usize, pub hiline: usize, pub hicol: usize, + pub original: syntax_pos::Span, } impl Span { @@ -3411,8 +3417,13 @@ impl Span { filename: FileName::Anon(0), loline: 0, locol: 0, hiline: 0, hicol: 0, + original: syntax_pos::DUMMY_SP, } } + + pub fn span(&self) -> syntax_pos::Span { + self.original + } } impl Clean for syntax_pos::Span { @@ -3431,6 +3442,7 @@ impl Clean for syntax_pos::Span { locol: lo.col.to_usize(), hiline: hi.line, hicol: hi.col.to_usize(), + original: *self, } } } @@ -3893,8 +3905,8 @@ impl Clean> for doctree::ExternCrate { fn clean(&self, cx: &DocContext<'_>) -> Vec { let please_inline = self.vis.node.is_pub() && self.attrs.iter().any(|a| { - a.check_name("doc") && match a.meta_item_list() { - Some(l) => attr::list_contains_name(&l, "inline"), + a.check_name(sym::doc) && match a.meta_item_list() { + Some(l) => attr::list_contains_name(&l, sym::inline), None => false, } }); @@ -3935,15 +3947,15 @@ impl Clean> for doctree::Import { // #[doc(no_inline)] attribute is present. // Don't inline doc(hidden) imports so they can be stripped at a later stage. let mut denied = !self.vis.node.is_pub() || self.attrs.iter().any(|a| { - a.check_name("doc") && match a.meta_item_list() { - Some(l) => attr::list_contains_name(&l, "no_inline") || - attr::list_contains_name(&l, "hidden"), + a.check_name(sym::doc) && match a.meta_item_list() { + Some(l) => attr::list_contains_name(&l, sym::no_inline) || + attr::list_contains_name(&l, sym::hidden), None => false, } }); // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ - let please_inline = self.attrs.lists("doc").has_word("inline"); + let please_inline = self.attrs.lists(sym::doc).has_word(sym::inline); let path = self.path.clean(cx); let inner = if self.glob { if !denied { @@ -4382,7 +4394,7 @@ where // Start of code copied from rust-clippy -pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[&str]) -> Option { +pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[Symbol]) -> Option { let krate = tcx.hir().krate(); let mut items = krate.module.item_ids.clone(); let mut path_it = path.iter().peekable(); @@ -4407,7 +4419,7 @@ pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[&str]) -> Option, path: &[&str]) -> Option { +pub fn path_to_def(tcx: TyCtxt<'_, '_, '_>, path: &[Symbol]) -> Option { let crates = tcx.crates(); let krate = crates diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 72421c9decc6..6b490f730afa 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -13,7 +13,7 @@ use rustc::session::config::{nightly_options, build_codegen_options, build_debug use rustc::session::search_paths::SearchPath; use rustc_driver; use rustc_target::spec::TargetTriple; -use syntax::edition::Edition; +use syntax::edition::{Edition, DEFAULT_EDITION}; use crate::core::new_handler; use crate::externalfiles::ExternalHtml; @@ -386,6 +386,18 @@ impl Options { } } + let edition = if let Some(e) = matches.opt_str("edition") { + match e.parse() { + Ok(e) => e, + Err(_) => { + diag.struct_err("could not parse edition").emit(); + return Err(1); + } + } + } else { + DEFAULT_EDITION + }; + let mut id_map = html::markdown::IdMap::new(); id_map.populate(html::render::initial_ids()); let external_html = match ExternalHtml::load( @@ -393,20 +405,12 @@ impl Options { &matches.opt_strs("html-before-content"), &matches.opt_strs("html-after-content"), &matches.opt_strs("markdown-before-content"), - &matches.opt_strs("markdown-after-content"), &diag, &mut id_map) { + &matches.opt_strs("markdown-after-content"), + &diag, &mut id_map, edition) { Some(eh) => eh, None => return Err(3), }; - let edition = matches.opt_str("edition").unwrap_or("2015".to_string()); - let edition = match edition.parse() { - Ok(e) => e, - Err(_) => { - diag.struct_err("could not parse edition").emit(); - return Err(1); - } - }; - match matches.opt_str("r").as_ref().map(|s| &**s) { Some("rust") | None => {} Some(s) => { @@ -538,7 +542,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) "passes", ]; - for flag in deprecated_flags.into_iter() { + for flag in deprecated_flags.iter() { if matches.opt_present(flag) { let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated", flag)); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index e91e3a029dac..2a3bc5e99617 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -18,6 +18,7 @@ use rustc_target::spec::TargetTriple; use syntax::source_map; use syntax::feature_gate::UnstableFeatures; use syntax::json::JsonEmitter; +use syntax::symbol::sym; use errors; use errors::emitter::{Emitter, EmitterWriter}; use parking_lot::ReentrantMutex; @@ -142,7 +143,7 @@ impl<'tcx> DocContext<'tcx> { crate_num, DefId { krate: crate_num, - index: DefIndex::from_array_index(def_id.index.as_array_index() + 1), + index: DefIndex::from(def_id.index.index() + 1), }, ); @@ -367,9 +368,9 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt }; let send_trait = if crate_name == Some("core".to_string()) { - clean::path_to_def_local(tcx, &["marker", "Send"]) + clean::path_to_def_local(tcx, &[sym::marker, sym::Send]) } else { - clean::path_to_def(tcx, &["core", "marker", "Send"]) + clean::path_to_def(tcx, &[sym::core, sym::marker, sym::Send]) }; let mut renderinfo = RenderInfo::default(); @@ -415,24 +416,24 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt // Process all of the crate attributes, extracting plugin metadata along // with the passes which we are supposed to run. - for attr in krate.module.as_ref().unwrap().attrs.lists("doc") { + for attr in krate.module.as_ref().unwrap().attrs.lists(sym::doc) { let diag = ctxt.sess().diagnostic(); let name = attr.name_or_empty(); if attr.is_word() { - if name == "no_default_passes" { + if name == sym::no_default_passes { report_deprecated_attr("no_default_passes", diag); if default_passes == passes::DefaultPassOption::Default { default_passes = passes::DefaultPassOption::None; } } } else if let Some(value) = attr.value_str() { - let sink = match name.get() { - "passes" => { + let sink = match name { + sym::passes => { report_deprecated_attr("passes = \"...\"", diag); &mut manual_passes }, - "plugins" => { + sym::plugins => { report_deprecated_attr("plugins = \"...\"", diag); eprintln!("WARNING: #![doc(plugins = \"...\")] no longer functions; \ see CVE-2018-1000622"); @@ -445,7 +446,7 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt } } - if attr.is_word() && name == "document_private_items" { + if attr.is_word() && name == sym::document_private_items { if default_passes == passes::DefaultPassOption::Default { default_passes = passes::DefaultPassOption::Private; } diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 0378b12662da..d604ba11d418 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::str; use errors; use crate::syntax::feature_gate::UnstableFeatures; +use crate::syntax::edition::Edition; use crate::html::markdown::{IdMap, ErrorCodes, Markdown}; use std::cell::RefCell; @@ -23,7 +24,7 @@ pub struct ExternalHtml { impl ExternalHtml { pub fn load(in_header: &[String], before_content: &[String], after_content: &[String], md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler, - id_map: &mut IdMap) + id_map: &mut IdMap, edition: Edition) -> Option { let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); load_external_files(in_header, diag) @@ -34,7 +35,8 @@ impl ExternalHtml { .and_then(|(ih, bc)| load_external_files(md_before_content, diag) .map(|m_bc| (ih, - format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), codes)))) + format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), + codes, edition)))) ) .and_then(|(ih, bc)| load_external_files(after_content, diag) @@ -43,7 +45,8 @@ impl ExternalHtml { .and_then(|(ih, bc, ac)| load_external_files(md_after_content, diag) .map(|m_ac| (ih, bc, - format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), codes)))) + format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), + codes, edition)))) ) .map(|(ih, bc, ac)| ExternalHtml { diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3d8af7c7716b..2784d5b3e10a 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -262,9 +262,7 @@ impl fmt::Display for clean::Lifetime { impl fmt::Display for clean::Constant { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.expr, f)?; - f.write_str(": ")?; - fmt::Display::fmt(&self.type_, f) + fmt::Display::fmt(&self.expr, f) } } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index d66455f91ba1..5bb06516ac49 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -318,6 +318,8 @@ impl<'a> Classifier<'a> { // Number literals. token::Integer(..) | token::Float(..) => Class::Number, + + token::Bool(..) => panic!("literal token contains `Lit::Bool`"), } } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index acf019fd2254..ae0bd1aafa8f 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -182,14 +182,14 @@ pub fn render( let p = SlashChecker(&p); if layout.logo.is_empty() { format!("\ - logo", +
\ + logo
", path=p, static_root_path=static_root_path, suffix=page.resource_suffix) } else { format!("\ - logo", +
logo
", p, layout.logo) } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a3b041c6954c..12d10254c4d0 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -8,12 +8,16 @@ //! ``` //! #![feature(rustc_private)] //! +//! extern crate syntax; +//! +//! use syntax::edition::Edition; //! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes}; //! use std::cell::RefCell; //! //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); -//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), ErrorCodes::Yes)); +//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), +//! ErrorCodes::Yes, Edition::Edition2015)); //! // ... something using html //! ``` @@ -42,14 +46,21 @@ fn opts() -> Options { /// A unit struct which has the `fmt::Display` trait implemented. When /// formatted, this struct will emit the HTML corresponding to the rendered /// version of the contained markdown string. -/// The second parameter is a list of link replacements +/// +/// The second parameter is a list of link replacements. +/// +/// The third is the current list of used header IDs. +/// +/// The fourth is whether to allow the use of explicit error codes in doctest lang strings. +/// +/// The fifth is what default edition to use when parsing doctests (to add a `fn main`). pub struct Markdown<'a>( - pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes); + pub &'a str, pub &'a [(String, String)], pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition); /// A unit struct like `Markdown`, that renders the markdown with a /// table of contents. -pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes); +pub struct MarkdownWithToc<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition); /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags. -pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes); +pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition); /// A unit struct like `Markdown`, that renders only the first paragraph. pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]); @@ -146,13 +157,15 @@ thread_local!(pub static PLAYGROUND: RefCell, String)>> = struct CodeBlocks<'a, I: Iterator>> { inner: I, check_error_codes: ErrorCodes, + edition: Edition, } impl<'a, I: Iterator>> CodeBlocks<'a, I> { - fn new(iter: I, error_codes: ErrorCodes) -> Self { + fn new(iter: I, error_codes: ErrorCodes, edition: Edition) -> Self { CodeBlocks { inner: iter, check_error_codes: error_codes, + edition, } } } @@ -177,6 +190,9 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { return event; } + let explicit_edition = edition.is_some(); + let edition = edition.unwrap_or(self.edition); + let mut origtext = String::new(); for event in &mut self.inner { match event { @@ -202,22 +218,14 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { .collect::>>().join("\n"); let krate = krate.as_ref().map(|s| &**s); let (test, _) = test::make_test(&test, krate, false, - &Default::default()); + &Default::default(), edition); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; - let edition_string = if let Some(e @ Edition::Edition2018) = edition { - format!("&edition={}{}", e, - if channel == "&version=nightly" { "" } - else { "&version=nightly" }) - } else if let Some(e) = edition { - format!("&edition={}", e) - } else { - "".to_owned() - }; + let edition_string = format!("&edition={}", edition); // These characters don't need to be escaped in a URI. // FIXME: use a library function for percent encoding. @@ -247,8 +255,8 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { Some(("This example is not tested".to_owned(), "ignore")) } else if compile_fail { Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) - } else if let Some(e) = edition { - Some((format!("This code runs with edition {}", e), "edition")) + } else if explicit_edition { + Some((format!("This code runs with edition {}", edition), "edition")) } else { None }; @@ -259,7 +267,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { Some(&format!("rust-example-rendered{}", if ignore { " ignore" } else if compile_fail { " compile_fail" } - else if edition.is_some() { " edition " } + else if explicit_edition { " edition " } else { "" })), playground_button.as_ref().map(String::as_str), Some((s1.as_str(), s2)))); @@ -270,7 +278,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { Some(&format!("rust-example-rendered{}", if ignore { " ignore" } else if compile_fail { " compile_fail" } - else if edition.is_some() { " edition " } + else if explicit_edition { " edition " } else { "" })), playground_button.as_ref().map(String::as_str), None)); @@ -659,7 +667,7 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Markdown(md, links, ref ids, codes) = *self; + let Markdown(md, links, ref ids, codes, edition) = *self; let mut ids = ids.borrow_mut(); // This is actually common enough to special-case @@ -678,7 +686,7 @@ impl<'a> fmt::Display for Markdown<'a> { let p = HeadingLinks::new(p, None, &mut ids); let p = LinkReplacer::new(p, links); - let p = CodeBlocks::new(p, codes); + let p = CodeBlocks::new(p, codes, edition); let p = Footnotes::new(p); html::push_html(&mut s, p); @@ -688,7 +696,7 @@ impl<'a> fmt::Display for Markdown<'a> { impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let MarkdownWithToc(md, ref ids, codes) = *self; + let MarkdownWithToc(md, ref ids, codes, edition) = *self; let mut ids = ids.borrow_mut(); let p = Parser::new_ext(md, opts()); @@ -699,7 +707,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> { { let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); - let p = CodeBlocks::new(p, codes); + let p = CodeBlocks::new(p, codes, edition); let p = Footnotes::new(p); html::push_html(&mut s, p); } @@ -712,7 +720,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> { impl<'a> fmt::Display for MarkdownHtml<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let MarkdownHtml(md, ref ids, codes) = *self; + let MarkdownHtml(md, ref ids, codes, edition) = *self; let mut ids = ids.borrow_mut(); // This is actually common enough to special-case @@ -728,7 +736,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); - let p = CodeBlocks::new(p, codes); + let p = CodeBlocks::new(p, codes, edition); let p = Footnotes::new(p); html::push_html(&mut s, p); @@ -1046,7 +1054,7 @@ mod tests { use super::{ErrorCodes, LangString, Markdown, MarkdownHtml, IdMap}; use super::plain_summary_line; use std::cell::RefCell; - use syntax::edition::Edition; + use syntax::edition::{Edition, DEFAULT_EDITION}; #[test] fn test_lang_string_parse() { @@ -1098,7 +1106,8 @@ mod tests { fn test_header() { fn t(input: &str, expect: &str) { let mut map = IdMap::new(); - let output = Markdown(input, &[], RefCell::new(&mut map), ErrorCodes::Yes).to_string(); + let output = Markdown(input, &[], RefCell::new(&mut map), + ErrorCodes::Yes, DEFAULT_EDITION).to_string(); assert_eq!(output, expect, "original: {}", input); } @@ -1120,7 +1129,8 @@ mod tests { fn test_header_ids_multiple_blocks() { let mut map = IdMap::new(); fn t(map: &mut IdMap, input: &str, expect: &str) { - let output = Markdown(input, &[], RefCell::new(map), ErrorCodes::Yes).to_string(); + let output = Markdown(input, &[], RefCell::new(map), + ErrorCodes::Yes, DEFAULT_EDITION).to_string(); assert_eq!(output, expect, "original: {}", input); } @@ -1157,7 +1167,8 @@ mod tests { fn test_markdown_html_escape() { fn t(input: &str, expect: &str) { let mut idmap = IdMap::new(); - let output = MarkdownHtml(input, RefCell::new(&mut idmap), ErrorCodes::Yes).to_string(); + let output = MarkdownHtml(input, RefCell::new(&mut idmap), + ErrorCodes::Yes, DEFAULT_EDITION).to_string(); assert_eq!(output, expect, "original: {}", input); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 472192a64649..b628bd450d31 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -47,9 +47,11 @@ use std::rc::Rc; use errors; use serialize::json::{ToJson, Json, as_json}; use syntax::ast; +use syntax::edition::Edition; use syntax::ext::base::MacroKind; use syntax::source_map::FileName; use syntax::feature_gate::UnstableFeatures; +use syntax::symbol::{Symbol, sym}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; @@ -107,6 +109,8 @@ struct Context { /// publicly reused items to redirect to the right location. pub render_redirect_pages: bool, pub codes: ErrorCodes, + /// The default edition used to parse doctests. + pub edition: Edition, /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, pub shared: Arc, @@ -505,7 +509,7 @@ pub fn initial_ids() -> Vec { "methods", "deref-methods", "implementations", - ].into_iter().map(|id| (String::from(*id))).collect() + ].iter().map(|id| (String::from(*id))).collect() } /// Generates the documentation for `crate` into the directory `dst` @@ -513,7 +517,8 @@ pub fn run(mut krate: clean::Crate, options: RenderOptions, passes: FxHashSet, renderinfo: RenderInfo, - diag: &errors::Handler) -> Result<(), Error> { + diag: &errors::Handler, + edition: Edition) -> Result<(), Error> { // need to save a copy of the options for rendering the index page let md_opts = options.clone(); let RenderOptions { @@ -571,24 +576,24 @@ pub fn run(mut krate: clean::Crate, // Crawl the crate attributes looking for attributes which control how we're // going to emit HTML if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) { - for attr in attrs.lists("doc") { - match (attr.name_or_empty().get(), attr.value_str()) { - ("html_favicon_url", Some(s)) => { + for attr in attrs.lists(sym::doc) { + match (attr.name_or_empty(), attr.value_str()) { + (sym::html_favicon_url, Some(s)) => { scx.layout.favicon = s.to_string(); } - ("html_logo_url", Some(s)) => { + (sym::html_logo_url, Some(s)) => { scx.layout.logo = s.to_string(); } - ("html_playground_url", Some(s)) => { + (sym::html_playground_url, Some(s)) => { markdown::PLAYGROUND.with(|slot| { let name = krate.name.clone(); *slot.borrow_mut() = Some((Some(name), s.to_string())); }); } - ("issue_tracker_base_url", Some(s)) => { + (sym::issue_tracker_base_url, Some(s)) => { scx.issue_tracker_base_url = Some(s.to_string()); } - ("html_no_source", None) if attr.is_word() => { + (sym::html_no_source, None) if attr.is_word() => { scx.include_sources = false; } _ => {} @@ -603,6 +608,7 @@ pub fn run(mut krate: clean::Crate, dst, render_redirect_pages: false, codes: ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()), + edition, id_map: Rc::new(RefCell::new(id_map)), shared: Arc::new(scx), }; @@ -1127,7 +1133,7 @@ themePicker.onblur = handleThemeButtonsBlur; md_opts.output = cx.dst.clone(); md_opts.external_html = (*cx.shared).layout.external_html.clone(); - crate::markdown::render(index_page, md_opts, diag); + crate::markdown::render(index_page, md_opts, diag, cx.edition); } else { let dst = cx.dst.join("index.html"); let mut w = BufWriter::new(try_err!(File::create(&dst), &dst)); @@ -1388,8 +1394,8 @@ fn extern_location(e: &clean::ExternalCrate, extern_url: Option<&str>, dst: &Pat // Failing that, see if there's an attribute specifying where to find this // external crate - e.attrs.lists("doc") - .filter(|a| a.check_name("html_root_url")) + e.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::html_root_url)) .filter_map(|a| a.value_str()) .map(|url| { let mut url = url.to_string(); @@ -1779,8 +1785,8 @@ impl<'a> Cache { let path = self.paths.get(&item.def_id) .map(|p| p.0[..p.0.len() - 1].join("::")) .unwrap_or("std".to_owned()); - for alias in item.attrs.lists("doc") - .filter(|a| a.check_name("alias")) + for alias in item.attrs.lists(sym::doc) + .filter(|a| a.check_name(sym::alias)) .filter_map(|a| a.value_str() .map(|s| s.to_string().replace("\"", ""))) .filter(|v| !v.is_empty()) @@ -2552,7 +2558,7 @@ fn render_markdown(w: &mut fmt::Formatter<'_>, if is_hidden { " hidden" } else { "" }, prefix, Markdown(md_text, &links, RefCell::new(&mut ids), - cx.codes)) + cx.codes, cx.edition)) } fn document_short( @@ -2917,7 +2923,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { if let Some(note) = note { let mut ids = cx.id_map.borrow_mut(); - let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes); + let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes, cx.edition); message.push_str(&format!(": {}", html)); } stability.push(format!("
{}
", message)); @@ -2966,7 +2972,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { message = format!( "
{}{}
", message, - MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes) + MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition) ); } @@ -2991,7 +2997,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, c: &clean::Constant) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "{vis}const \
                {name}: {typ}
", vis = VisSpace(&it.visibility), @@ -3003,7 +3009,7 @@ fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, s: &clean::Static) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "{vis}static {mutability}\
                {name}: {typ}
", vis = VisSpace(&it.visibility), @@ -3026,7 +3032,7 @@ fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, f.generics ).len(); write!(w, "{}
", render_spotlight_traits(it)?)?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w,
            "{vis}{constness}{unsafety}{asyncness}{abi}fn \
            {name}{generics}{decl}{where_clause}
", @@ -3115,7 +3121,7 @@ fn item_trait( // Output the trait definition wrap_into_docblock(w, |w| { write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         write!(w, "{}{}{}trait {}{}{}",
                VisSpace(&it.visibility),
                UnsafetySpace(t.unsafety),
@@ -3378,8 +3384,10 @@ fn assoc_const(w: &mut fmt::Formatter<'_>,
                it: &clean::Item,
                ty: &clean::Type,
                _default: Option<&String>,
-               link: AssocItemLink<'_>) -> fmt::Result {
-    write!(w, "{}const {}: {}",
+               link: AssocItemLink<'_>,
+               extra: &str) -> fmt::Result {
+    write!(w, "{}{}const {}: {}",
+           extra,
            VisSpace(&it.visibility),
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap(),
@@ -3390,8 +3398,10 @@ fn assoc_const(w: &mut fmt::Formatter<'_>,
 fn assoc_type(w: &mut W, it: &clean::Item,
                              bounds: &[clean::GenericBound],
                              default: Option<&clean::Type>,
-                             link: AssocItemLink<'_>) -> fmt::Result {
-    write!(w, "type {}",
+                             link: AssocItemLink<'_>,
+                             extra: &str) -> fmt::Result {
+    write!(w, "{}type {}",
+           extra,
            naive_assoc_href(it, link),
            it.name.as_ref().unwrap())?;
     if !bounds.is_empty() {
@@ -3468,7 +3478,7 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>,
         } else {
             (0, true)
         };
-        render_attributes(w, meth)?;
+        render_attributes(w, meth, false)?;
         write!(w, "{}{}{}{}{}{}{}fn {name}\
                    {generics}{decl}{where_clause}",
                if parent == ItemType::Trait { "    " } else { "" },
@@ -3502,10 +3512,12 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>,
             method(w, item, m.header, &m.generics, &m.decl, link, parent)
         }
         clean::AssociatedConstItem(ref ty, ref default) => {
-            assoc_const(w, item, ty, default.as_ref(), link)
+            assoc_const(w, item, ty, default.as_ref(), link,
+                        if parent == ItemType::Trait { "    " } else { "" })
         }
         clean::AssociatedTypeItem(ref bounds, ref default) => {
-            assoc_type(w, item, bounds, default.as_ref(), link)
+            assoc_type(w, item, bounds, default.as_ref(), link,
+                       if parent == ItemType::Trait { "    " } else { "" })
         }
         _ => panic!("render_assoc_item called on non-associated-item")
     }
@@ -3515,7 +3527,7 @@ fn item_struct(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                s: &clean::Struct) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         render_struct(w,
                       it,
                       Some(&s.generics),
@@ -3566,7 +3578,7 @@ fn item_union(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
                s: &clean::Union) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         render_union(w,
                      it,
                      Some(&s.generics),
@@ -3611,7 +3623,7 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item,
              e: &clean::Enum) -> fmt::Result {
     wrap_into_docblock(w, |w| {
         write!(w, "
")?;
-        render_attributes(w, it)?;
+        render_attributes(w, it, true)?;
         write!(w, "{}enum {}{}{}",
                VisSpace(&it.visibility),
                it.name.as_ref().unwrap(),
@@ -3761,22 +3773,30 @@ fn render_attribute(attr: &ast::MetaItem) -> Option {
     }
 }
 
-const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
-    "export_name",
-    "lang",
-    "link_section",
-    "must_use",
-    "no_mangle",
-    "repr",
-    "unsafe_destructor_blind_to_params",
-    "non_exhaustive"
+const ATTRIBUTE_WHITELIST: &'static [Symbol] = &[
+    sym::export_name,
+    sym::lang,
+    sym::link_section,
+    sym::must_use,
+    sym::no_mangle,
+    sym::repr,
+    sym::unsafe_destructor_blind_to_params,
+    sym::non_exhaustive
 ];
 
-fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item) -> fmt::Result {
+// The `top` parameter is used when generating the item declaration to ensure it doesn't have a
+// left padding. For example:
+//
+// #[foo] <----- "top" attribute
+// struct Foo {
+//     #[bar] <---- not "top" attribute
+//     bar: usize,
+// }
+fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item, top: bool) -> fmt::Result {
     let mut attrs = String::new();
 
     for attr in &it.attrs.other_attrs {
-        if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty().get()) {
+        if !ATTRIBUTE_WHITELIST.contains(&attr.name_or_empty()) {
             continue;
         }
         if let Some(s) = render_attribute(&attr.meta().unwrap()) {
@@ -3784,7 +3804,8 @@ fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item) -> fmt::Result {
         }
     }
     if attrs.len() > 0 {
-        write!(w, "
{}
", &attrs)?; + write!(w, "
{}
", + if top { " top-attr" } else { "" }, &attrs)?; } Ok(()) } @@ -4117,7 +4138,8 @@ fn spotlight_decl(decl: &clean::FnDecl) -> Result { out.push_str(" "); assoc_type(&mut out, it, &[], Some(&tydef.type_), - AssocItemLink::GotoSource(t_did, &FxHashSet::default()))?; + AssocItemLink::GotoSource(t_did, &FxHashSet::default()), + "")?; out.push_str(";"); } } @@ -4157,7 +4179,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if let clean::TypedefItem(ref tydef, _) = it.inner { write!(w, " ")?; assoc_type(w, it, &vec![], Some(&tydef.type_), - AssocItemLink::Anchor(None))?; + AssocItemLink::Anchor(None), + "")?; write!(w, ";")?; } } @@ -4179,7 +4202,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}
", - Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), cx.codes))?; + Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), + cx.codes, cx.edition))?; } } @@ -4227,7 +4251,7 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; write!(w, "", ns_id)?; - assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id))?; + assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "")?; write!(w, "

")?; } clean::AssociatedConstItem(ref ty, ref default) => { @@ -4235,7 +4259,7 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; write!(w, "", ns_id)?; - assoc_const(w, item, ty, default.as_ref(), link.anchor(&id))?; + assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "")?; write!(w, "")?; render_stability_since_raw(w, item.stable_since(), outer_version)?; if let Some(l) = (Item { cx, item }).src_href() { @@ -4249,7 +4273,7 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class)?; write!(w, "", ns_id)?; - assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id))?; + assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "")?; write!(w, "

")?; } clean::StrippedItem(..) => return Ok(()), @@ -4337,7 +4361,7 @@ fn item_existential( t: &clean::Existential, ) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "existential type {}{}{where_clause}: {bounds};
", it.name.as_ref().unwrap(), t.generics, @@ -4356,7 +4380,7 @@ fn item_existential( fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, t: &clean::TraitAlias) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "trait {}{}{} = {};
", it.name.as_ref().unwrap(), t.generics, @@ -4375,7 +4399,7 @@ fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, t: &clean::Typedef) -> fmt::Result { write!(w, "
")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(w, "type {}{}{where_clause} = {type_};
", it.name.as_ref().unwrap(), t.generics, @@ -4393,7 +4417,7 @@ fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, fn item_foreign_type(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item) -> fmt::Result { writeln!(w, "
extern {{")?;
-    render_attributes(w, it)?;
+    render_attributes(w, it, false)?;
     write!(
         w,
         "    {}type {};\n}}
", diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 85ab0855f05e..72a01a49bc66 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2325,7 +2325,11 @@ if (!DOMTokenList.prototype.remove) { } var attributesToggle = createToggleWrapper(createSimpleToggle(false)); onEachLazy(main.getElementsByClassName("attributes"), function(i_e) { - i_e.parentNode.insertBefore(attributesToggle.cloneNode(true), i_e); + var attr_tog = attributesToggle.cloneNode(true); + if (hasClass(i_e, "top-attr") === true) { + addClass(attr_tog, "top-attr"); + } + i_e.parentNode.insertBefore(attr_tog, i_e); itemAttributesFunc(i_e); }); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 880b82433551..0493bf7c5c0f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -182,12 +182,25 @@ nav.sub { display: none !important; } -.sidebar img { +.logo-container { + height: 100px; + width: 100px; + position: relative; margin: 20px auto; display: block; margin-top: 10px; } +.logo-container > img { + max-width: 100px; + max-height: 100px; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + display: block; +} + .sidebar .location { border: 1px solid; font-size: 17px; @@ -658,18 +671,18 @@ a { transition: border-color 300ms ease; transition: border-radius 300ms ease-in-out; transition: box-shadow 300ms ease-in-out; - width: calc(100% - 32px); + width: 100%; } #crate-search + .search-input { border-radius: 0 1px 1px 0; + width: calc(100% - 32px); } .search-input:focus { border-radius: 2px; border: 0; outline: 0; - box-shadow: 0 0 8px #078dd8; } .search-results .desc { @@ -998,137 +1011,6 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { opacity: 1; } -/* Media Queries */ - -@media (max-width: 700px) { - body { - padding-top: 0px; - } - - .rustdoc > .sidebar { - height: 45px; - min-height: 40px; - margin: 0; - margin-left: -15px; - padding: 0 15px; - position: static; - z-index: 11; - } - - .sidebar > .location { - float: right; - margin: 0px; - margin-top: 2px; - padding: 3px 10px 1px 10px; - min-height: 39px; - background: inherit; - text-align: left; - font-size: 24px; - } - - .sidebar .location:empty { - padding: 0; - } - - .sidebar img { - width: 35px; - margin-top: 5px; - margin-bottom: 5px; - float: left; - margin-left: 50px; - } - - .sidebar-menu { - position: fixed; - z-index: 10; - font-size: 2rem; - cursor: pointer; - width: 45px; - left: 0; - text-align: center; - display: block; - border-bottom: 1px solid; - border-right: 1px solid; - height: 45px; - } - - .rustdoc.source > .sidebar > .sidebar-menu { - display: none; - } - - .sidebar-elems { - position: fixed; - z-index: 1; - left: 0; - top: 45px; - bottom: 0; - overflow-y: auto; - border-right: 1px solid; - display: none; - } - - .sidebar > .block.version { - border-bottom: none; - margin-top: 12px; - } - - nav.sub { - width: calc(100% - 32px); - float: right; - } - - .content { - margin-left: 0px; - } - - #main { - margin-top: 45px; - padding: 0; - } - - .content .in-band { - width: 100%; - } - - .content h4 > .out-of-band { - position: inherit; - } - - .toggle-wrapper > .collapse-toggle { - left: 0px; - } - - .toggle-wrapper { - height: 1.5em; - } - - #search { - margin-left: 0; - } - - .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant { - display: flex; - } - - .anchor { - display: none !important; - } - - h1.fqn { - overflow: initial; - } - - #main > .line-numbers { - margin-top: 0; - } -} - -@media print { - nav.sub, .content .out-of-band, .collapse-toggle { - display: none; - } -} - .information { position: absolute; left: -20px; @@ -1236,7 +1118,220 @@ h4 > .important-traits { margin: 5px 0; } +#sidebar-toggle { + position: fixed; + top: 30px; + left: 300px; + z-index: 10; + padding: 3px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + cursor: pointer; + font-weight: bold; + transition: left .5s; + font-size: 1.2em; + border: 1px solid; + border-left: 0; +} +#source-sidebar { + position: fixed; + top: 0; + bottom: 0; + left: 0; + width: 300px; + z-index: 1; + overflow: auto; + transition: left .5s; + border-right: 1px solid; +} +#source-sidebar > .title { + font-size: 1.5em; + text-align: center; + border-bottom: 1px solid; + margin-bottom: 6px; +} + +.theme-picker { + position: absolute; + left: 211px; + top: 19px; +} + +.theme-picker button { + outline: none; +} + +#settings-menu { + position: absolute; + right: 0; + top: 10px; + outline: none; +} + +#theme-picker, #settings-menu { + padding: 4px; + width: 27px; + height: 29px; + border: 1px solid; + border-radius: 3px; + cursor: pointer; +} + +#theme-choices { + display: none; + position: absolute; + left: 0; + top: 28px; + border: 1px solid; + border-radius: 3px; + z-index: 1; + cursor: pointer; +} + +#theme-choices > button { + border: none; + width: 100%; + padding: 4px; + text-align: center; + background: rgba(0,0,0,0); +} + +#theme-choices > button:not(:first-child) { + border-top: 1px solid; +} + +/* Media Queries */ + @media (max-width: 700px) { + body { + padding-top: 0px; + } + + .rustdoc > .sidebar { + height: 45px; + min-height: 40px; + margin: 0; + margin-left: -15px; + padding: 0 15px; + position: static; + z-index: 11; + } + + .sidebar > .location { + float: right; + margin: 0px; + margin-top: 2px; + padding: 3px 10px 1px 10px; + min-height: 39px; + background: inherit; + text-align: left; + font-size: 24px; + } + + .sidebar .location:empty { + padding: 0; + } + + .sidebar .logo-container { + width: 35px; + height: 35px; + margin-top: 5px; + margin-bottom: 5px; + float: left; + margin-left: 50px; + } + + .sidebar .logo-container > img { + max-width: 35px; + max-height: 35px; + } + + .sidebar-menu { + position: fixed; + z-index: 10; + font-size: 2rem; + cursor: pointer; + width: 45px; + left: 0; + text-align: center; + display: block; + border-bottom: 1px solid; + border-right: 1px solid; + height: 45px; + } + + .rustdoc.source > .sidebar > .sidebar-menu { + display: none; + } + + .sidebar-elems { + position: fixed; + z-index: 1; + left: 0; + top: 45px; + bottom: 0; + overflow-y: auto; + border-right: 1px solid; + display: none; + } + + .sidebar > .block.version { + border-bottom: none; + margin-top: 12px; + } + + nav.sub { + width: calc(100% - 32px); + float: right; + } + + .content { + margin-left: 0px; + } + + #main { + margin-top: 45px; + padding: 0; + } + + .content .in-band { + width: 100%; + } + + .content h4 > .out-of-band { + position: inherit; + } + + .toggle-wrapper > .collapse-toggle { + left: 0px; + } + + .toggle-wrapper { + height: 1.5em; + } + + #search { + margin-left: 0; + } + + .content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant { + display: flex; + } + + .anchor { + display: none !important; + } + + h1.fqn { + overflow: initial; + } + + .theme-picker { + left: 10px; + top: 54px; + z-index: 1; + } + h4 > .important-traits { position: absolute; left: -22px; @@ -1311,8 +1406,29 @@ h4 > .important-traits { #all-types { margin: 10px; } + + #sidebar-toggle { + top: 100px; + width: 30px; + font-size: 1.5rem; + text-align: center; + padding: 0; + } + + #source-sidebar { + z-index: 11; + } + + #main > .line-numbers { + margin-top: 0; + } } +@media print { + nav.sub, .content .out-of-band, .collapse-toggle { + display: none; + } +} @media (max-width: 416px) { #titles { @@ -1412,63 +1528,6 @@ kbd { cursor: default; } -.theme-picker { - position: absolute; - left: 211px; - top: 19px; -} - -.theme-picker button { - outline: none; -} - -#settings-menu { - position: absolute; - right: 0; - top: 10px; - outline: none; -} - -#theme-picker, #settings-menu { - padding: 4px; - width: 27px; - height: 29px; - border: 1px solid; - border-radius: 3px; - cursor: pointer; -} - -#theme-choices { - display: none; - position: absolute; - left: 0; - top: 28px; - border: 1px solid; - border-radius: 3px; - z-index: 1; - cursor: pointer; -} - -#theme-choices > button { - border: none; - width: 100%; - padding: 4px; - text-align: center; - background: rgba(0,0,0,0); -} - -#theme-choices > button:not(:first-child) { - border-top: 1px solid; -} - -@media (max-width: 700px) { - .theme-picker { - left: 10px; - top: 54px; - z-index: 1; - } -} - .hidden-by-impl-hider, .hidden-by-usual-hider { /* important because of conflicting rule for small screens */ @@ -1520,39 +1579,6 @@ kbd { margin-bottom: 1em; } -#sidebar-toggle { - position: fixed; - top: 30px; - left: 300px; - z-index: 10; - padding: 3px; - border-top-right-radius: 3px; - border-bottom-right-radius: 3px; - cursor: pointer; - font-weight: bold; - transition: left .5s; - font-size: 1.2em; - border: 1px solid; - border-left: 0; -} -#source-sidebar { - position: fixed; - top: 0; - bottom: 0; - left: 0; - width: 300px; - z-index: 1; - overflow: auto; - transition: left .5s; - border-right: 1px solid; -} -#source-sidebar > .title { - font-size: 1.5em; - text-align: center; - border-bottom: 1px solid; - margin-bottom: 6px; -} - div.children { padding-left: 27px; display: none; @@ -1587,10 +1613,10 @@ div.name.expand::before { } /* This part is to fix the "Expand attributes" part in the type declaration. */ -.type-decl > pre > :first-child { +.type-decl > pre > .toggle-wrapper.toggle-attributes.top-attr { margin-left: 0 !important; } -.type-decl > pre > :nth-child(2) { +.type-decl > pre > .docblock.attributes.top-attr { margin-left: 1.8em !important; } .type-decl > pre > .toggle-attributes { diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index f1255f522473..e44ae2ad10ce 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -164,20 +164,21 @@ a.test-arrow { color: #111; background-color: #f0f0f0; border-color: #000; + box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; } .search-input { color: #111; - box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; background-color: #f0f0f0; + box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent; } .search-input:focus { border-color: #008dfd; } -#crate-search + .search-input { - box-shadow: 1px 0 0 1px #000, 0 0 0 2px transparent; +#crate-search + .search-input:focus { + box-shadow: 0 0 8px 4px #078dd8; } .module-item .stab { diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index c052e6b37ade..4c37000dde2c 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -164,21 +164,21 @@ a.test-arrow { color: #555; background-color: white; border-color: #e0e0e0; - box-shadow: 0px 0 0 1px #e0e0e0, 0 0 0 2px transparent; + box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; } .search-input { color: #555; - box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; background-color: white; + box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent; } .search-input:focus { border-color: #66afe9; } -#crate-search + .search-input { - box-shadow: 1px 0 0 1px #e0e0e0, 0 0 0 2px transparent; +#crate-search + .search-input:focus { + box-shadow: 0 0 8px #078dd8; } .module-item .stab { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5b76f6861de7..f5061b671828 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -391,7 +391,10 @@ fn main_args(args: &[String]) -> i32 { match (options.should_test, options.markdown_input()) { (true, true) => return markdown::test(options, &diag), (true, false) => return test::run(options), - (false, true) => return markdown::render(options.input, options.render_options, &diag), + (false, true) => return markdown::render(options.input, + options.render_options, + &diag, + options.edition), (false, false) => {} } @@ -399,7 +402,8 @@ fn main_args(args: &[String]) -> i32 { // but we can't crates the Handler ahead of time because it's not Send let diag_opts = (options.error_format, options.debugging_options.treat_err_as_bug, - options.debugging_options.ui_testing); + options.debugging_options.ui_testing, + options.edition); let show_coverage = options.show_coverage; rust_input(options, move |out| { if show_coverage { @@ -410,7 +414,7 @@ fn main_args(args: &[String]) -> i32 { let Output { krate, passes, renderinfo, renderopts } = out; info!("going to format"); - let (error_format, treat_err_as_bug, ui_testing) = diag_opts; + let (error_format, treat_err_as_bug, ui_testing, edition) = diag_opts; let diag = core::new_handler(error_format, None, treat_err_as_bug, ui_testing); match html::render::run( krate, @@ -418,6 +422,7 @@ fn main_args(args: &[String]) -> i32 { passes.into_iter().collect(), renderinfo, &diag, + edition, ) { Ok(_) => rustc_driver::EXIT_SUCCESS, Err(e) => { diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index c496dde8426c..b0a37ea9c808 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -5,6 +5,7 @@ use std::cell::RefCell; use errors; use testing; +use syntax::edition::Edition; use syntax::source_map::DUMMY_SP; use syntax::feature_gate::UnstableFeatures; @@ -36,7 +37,12 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) { /// Render `input` (e.g., "foo.md") into an HTML file in `output` /// (e.g., output = "bar" => "bar/foo.html"). -pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> i32 { +pub fn render( + input: PathBuf, + options: RenderOptions, + diag: &errors::Handler, + edition: Edition +) -> i32 { let mut output = options.output; output.push(input.file_stem().unwrap()); output.set_extension("html"); @@ -76,9 +82,9 @@ pub fn render(input: PathBuf, options: RenderOptions, diag: &errors::Handler) -> let mut ids = IdMap::new(); let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); let text = if !options.markdown_no_toc { - MarkdownWithToc(text, RefCell::new(&mut ids), error_codes).to_string() + MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string() } else { - Markdown(text, &[], RefCell::new(&mut ids), error_codes).to_string() + Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string() }; let err = write!( diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index fe407fa24d93..4ee09f7096b6 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -5,6 +5,7 @@ use crate::passes::Pass; use syntax::attr; use syntax_pos::FileName; +use syntax::symbol::sym; use std::collections::BTreeMap; use std::ops; @@ -131,7 +132,7 @@ impl fold::DocFolder for CoverageCalculator { return Some(i); } clean::ImplItem(ref impl_) - if attr::contains_name(&i.attrs.other_attrs, "automatically_derived") + if attr::contains_name(&i.attrs.other_attrs, sym::automatically_derived) || impl_.synthetic || impl_.blanket_impl.is_some() => { // built-in derives get the `#[automatically_derived]` attribute, and diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index abf19a0a5efa..2c382a1c1759 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { // Try looking for methods and associated items. let mut split = path_str.rsplitn(2, "::"); let item_name = if let Some(first) = split.next() { - first + Symbol::intern(first) } else { return Err(()) }; @@ -321,7 +321,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) { res } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // This could just be a normal link or a broken link // we could potentially check if something is // "intra-doc-link-like" and warn in that case. @@ -332,7 +332,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Ok(res) = self.resolve(path_str, ns, ¤t_item, parent_node) { res } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // This could just be a normal link. continue; } @@ -357,7 +357,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }; if candidates.is_empty() { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); // this could just be a normal link continue; } @@ -368,7 +368,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } else { ambiguity_error( cx, - &item.attrs, + &item, path_str, &dox, link_range, @@ -381,7 +381,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { if let Some(res) = macro_resolve(cx, path_str) { (res, None) } else { - resolution_failure(cx, &item.attrs, path_str, &dox, link_range); + resolution_failure(cx, &item, path_str, &dox, link_range); continue } } @@ -452,16 +452,24 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { /// line containing the failure as a note as well. fn resolution_failure( cx: &DocContext<'_>, - attrs: &Attributes, + item: &Item, path_str: &str, dox: &str, link_range: Option>, ) { + let hir_id = match cx.as_local_hir_id(item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs); let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir::CRATE_HIR_ID, + hir_id, sp, &format!("`[{}]` cannot be resolved, ignoring it...", path_str), ); @@ -495,12 +503,20 @@ fn resolution_failure( fn ambiguity_error( cx: &DocContext<'_>, - attrs: &Attributes, + item: &Item, path_str: &str, dox: &str, link_range: Option>, candidates: PerNS>, ) { + let hir_id = match cx.as_local_hir_id(item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; + let attrs = &item.attrs; let sp = span_of_attrs(attrs); let mut msg = format!("`{}` is ", path_str); @@ -532,7 +548,7 @@ fn ambiguity_error( let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE, - hir::CRATE_HIR_ID, + hir_id, sp, &msg, ); diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 8d33cd72e29a..70cd4b72199b 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -5,6 +5,7 @@ use super::Pass; use rustc::util::nodemap::FxHashSet; use rustc::hir::def_id::DefId; +use syntax::symbol::sym; pub const COLLECT_TRAIT_IMPLS: Pass = Pass { name: "collect-trait-impls", @@ -68,7 +69,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { inline::build_impl(cx, def_id, &mut new_items); // FIXME(eddyb) is this `doc(hidden)` check needed? - if !cx.tcx.get_attrs(def_id).lists("doc").has_word("hidden") { + if !cx.tcx.get_attrs(def_id).lists(sym::doc).has_word(sym::hidden) { let self_ty = cx.tcx.type_of(def_id); let impls = get_auto_trait_and_blanket_impls(cx, self_ty, def_id); let mut renderinfo = cx.renderinfo.borrow_mut(); @@ -154,7 +155,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { fn fold_item(&mut self, i: Item) -> Option { if i.is_struct() || i.is_enum() || i.is_union() { // FIXME(eddyb) is this `doc(hidden)` check needed? - if !self.cx.tcx.get_attrs(i.def_id).lists("doc").has_word("hidden") { + if !self.cx.tcx.get_attrs(i.def_id).lists(sym::doc).has_word(sym::hidden) { self.impls.extend(get_auto_trait_and_blanket_impls( self.cx, self.cx.tcx.type_of(i.def_id), diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 99aca0634710..d9af33ac5b62 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,7 +1,6 @@ //! Contains information about "passes", used to modify crate information during the documentation //! process. -use rustc::hir; use rustc::hir::def_id::DefId; use rustc::lint as lint; use rustc::middle::privacy::AccessLevels; @@ -314,10 +313,13 @@ pub fn look_for_tests<'tcx>( item: &Item, check_missing_code: bool, ) { - if cx.as_local_hir_id(item.def_id).is_none() { - // If non-local, no need to check anything. - return; - } + let hir_id = match cx.as_local_hir_id(item.def_id) { + Some(hir_id) => hir_id, + None => { + // If non-local, no need to check anything. + return; + } + }; struct Tests { found_tests: usize, @@ -336,10 +338,11 @@ pub fn look_for_tests<'tcx>( find_testable_code(&dox, &mut tests, ErrorCodes::No); if check_missing_code == true && tests.found_tests == 0 { + let sp = span_of_attrs(&item.attrs).substitute_dummy(item.source.span()); let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::MISSING_DOC_CODE_EXAMPLES, - hir::CRATE_HIR_ID, - span_of_attrs(&item.attrs), + hir_id, + sp, "Missing code example in this documentation"); diag.emit(); } else if check_missing_code == false && @@ -347,7 +350,7 @@ pub fn look_for_tests<'tcx>( !cx.renderinfo.borrow().access_levels.is_doc_reachable(item.def_id) { let mut diag = cx.tcx.struct_span_lint_hir( lint::builtin::PRIVATE_DOC_TESTS, - hir::CRATE_HIR_ID, + hir_id, span_of_attrs(&item.attrs), "Documentation test in private item"); diag.emit(); diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 240299c212ab..da8977544f64 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -1,5 +1,6 @@ use rustc::util::nodemap::DefIdSet; use std::mem; +use syntax::symbol::sym; use crate::clean::{self, AttributesExt, NestedAttributesExt}; use crate::clean::Item; @@ -37,7 +38,7 @@ struct Stripper<'a> { impl<'a> DocFolder for Stripper<'a> { fn fold_item(&mut self, i: Item) -> Option { - if i.attrs.lists("doc").has_word("hidden") { + if i.attrs.lists(sym::doc).has_word(sym::hidden) { debug!("strip_hidden: stripping {} {:?}", i.type_(), i.name); // use a dedicated hidden item for given item type if any match i.inner { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 5c0a4da1cd7e..0cc99da64079 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -11,10 +11,6 @@ use syntax::ast; use syntax::source_map::SourceMap; use syntax::edition::Edition; use syntax::feature_gate::UnstableFeatures; -use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; -use tempfile::Builder as TempFileBuilder; -use testing; - use std::env; use std::io::prelude::*; use std::io; @@ -23,6 +19,10 @@ use std::path::PathBuf; use std::process::Command; use std::str; use std::sync::{Arc, Mutex}; +use syntax::symbol::sym; +use syntax_pos::{BytePos, DUMMY_SP, Pos, Span, FileName}; +use tempfile::Builder as TempFileBuilder; +use testing; use crate::clean::Attributes; use crate::config::Options; @@ -137,17 +137,17 @@ fn scrape_test_config(krate: &::rustc::hir::Crate) -> TestOptions { }; let test_attrs: Vec<_> = krate.attrs.iter() - .filter(|a| a.check_name("doc")) + .filter(|a| a.check_name(sym::doc)) .flat_map(|a| a.meta_item_list().unwrap_or_else(Vec::new)) - .filter(|a| a.check_name("test")) + .filter(|a| a.check_name(sym::test)) .collect(); let attrs = test_attrs.iter().flat_map(|a| a.meta_item_list().unwrap_or(&[])); for attr in attrs { - if attr.check_name("no_crate_inject") { + if attr.check_name(sym::no_crate_inject) { opts.no_crate_inject = true; } - if attr.check_name("attr") { + if attr.check_name(sym::attr) { if let Some(l) = attr.meta_item_list() { for item in l { opts.attrs.push(pprust::meta_list_item_to_string(item)); @@ -167,7 +167,7 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, maybe_sysroot: Option, linker: Option, edition: Edition, persist_doctests: Option) { let (test, line_offset) = match panic::catch_unwind(|| { - make_test(test, Some(cratename), as_test_harness, opts) + make_test(test, Some(cratename), as_test_harness, opts, edition) }) { Ok((test, line_offset)) => (test, line_offset), Err(cause) if cause.is::() => { @@ -356,7 +356,8 @@ fn run_test(test: &str, cratename: &str, filename: &FileName, line: usize, pub fn make_test(s: &str, cratename: Option<&str>, dont_insert_main: bool, - opts: &TestOptions) + opts: &TestOptions, + edition: Edition) -> (String, usize) { let (crate_attrs, everything_else, crates) = partition_source(s); let everything_else = everything_else.trim(); @@ -390,6 +391,8 @@ pub fn make_test(s: &str, use errors::emitter::EmitterWriter; use errors::Handler; + syntax::ext::hygiene::set_default_edition(edition); + let filename = FileName::anon_source_code(s); let source = crates + &everything_else; @@ -397,6 +400,7 @@ pub fn make_test(s: &str, // send all the errors that libsyntax emits directly into a `Sink` instead of stderr. let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = EmitterWriter::new(box io::sink(), None, false, false, false); + // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser let handler = Handler::with_emitter(false, None, box emitter); let sess = ParseSess::with_span_handler(handler, cm); @@ -880,6 +884,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> { #[cfg(test)] mod tests { use super::{TestOptions, make_test}; + use syntax::edition::DEFAULT_EDITION; #[test] fn make_test_basic() { @@ -892,7 +897,7 @@ mod tests { fn main() { assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, None, false, &opts); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -908,7 +913,7 @@ assert_eq!(2+2, 4); fn main() { assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -927,7 +932,7 @@ fn main() { use asdf::qwop; assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 3)); } @@ -949,7 +954,7 @@ fn main() { use asdf::qwop; assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -968,7 +973,7 @@ fn main() { use std::*; assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("std"), false, &opts); + let output = make_test(input, Some("std"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -988,7 +993,7 @@ fn main() { use asdf::qwop; assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -1006,7 +1011,7 @@ fn main() { use asdf::qwop; assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -1026,7 +1031,7 @@ fn main() { use asdf::qwop; assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 3)); // Adding more will also bump the returned line offset. @@ -1039,7 +1044,7 @@ fn main() { use asdf::qwop; assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 4)); } @@ -1057,7 +1062,7 @@ assert_eq!(2+2, 4);"; fn main() { assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, None, false, &opts); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -1074,7 +1079,7 @@ assert_eq!(2+2, 4); fn main() { assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, None, false, &opts); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 1)); } @@ -1091,7 +1096,7 @@ assert_eq!(2+2, 4);"; fn main() { assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, None, false, &opts); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); } @@ -1106,7 +1111,7 @@ assert_eq!(2+2, 4);"; "#![allow(unused)] //Ceci n'est pas une `fn main` assert_eq!(2+2, 4);".to_string(); - let output = make_test(input, None, true, &opts); + let output = make_test(input, None, true, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 1)); } @@ -1121,7 +1126,7 @@ assert_eq!(2+2, 4);".to_string(); "fn main() { assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, None, false, &opts); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 1)); } @@ -1140,7 +1145,7 @@ fn main() { assert_eq!(2+2, 4); }".to_string(); - let output = make_test(input, None, false, &opts); + let output = make_test(input, None, false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 2)); let input = @@ -1155,7 +1160,7 @@ fn main() { assert_eq!(asdf::foo, 4); }".to_string(); - let output = make_test(input, Some("asdf"), false, &opts); + let output = make_test(input, Some("asdf"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 3)); } @@ -1174,7 +1179,7 @@ test_wrapper! { fn main() {} }".to_string(); - let output = make_test(input, Some("my_crate"), false, &opts); + let output = make_test(input, Some("my_crate"), false, &opts, DEFAULT_EDITION); assert_eq!(output, (expected, 1)); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 94d2d7ffdb8c..eb9de43e3886 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -10,6 +10,7 @@ use syntax::ast; use syntax::attr; use syntax::ext::base::MacroKind; use syntax::source_map::Spanned; +use syntax::symbol::sym; use syntax_pos::{self, Span}; use std::mem; @@ -165,11 +166,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { body: hir::BodyId) { debug!("Visiting fn"); let macro_kind = item.attrs.iter().filter_map(|a| { - if a.check_name("proc_macro") { + if a.check_name(sym::proc_macro) { Some(MacroKind::Bang) - } else if a.check_name("proc_macro_derive") { + } else if a.check_name(sym::proc_macro_derive) { Some(MacroKind::Derive) - } else if a.check_name("proc_macro_attribute") { + } else if a.check_name(sym::proc_macro_attribute) { Some(MacroKind::Attr) } else { None @@ -178,7 +179,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { match macro_kind { Some(kind) => { let name = if kind == MacroKind::Derive { - item.attrs.lists("proc_macro_derive") + item.attrs.lists(sym::proc_macro_derive) .filter_map(|mi| mi.ident()) .next() .expect("proc-macro derives require a name") @@ -188,8 +189,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; let mut helpers = Vec::new(); - for mi in item.attrs.lists("proc_macro_derive") { - if !mi.check_name("attributes") { + for mi in item.attrs.lists(sym::proc_macro_derive) { + if !mi.check_name(sym::attributes) { continue; } @@ -274,7 +275,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { fn inherits_doc_hidden(cx: &core::DocContext<'_>, mut node: hir::HirId) -> bool { while let Some(id) = cx.tcx.hir().get_enclosing_scope(node) { node = id; - if cx.tcx.hir().attrs_by_hir_id(node).lists("doc").has_word("hidden") { + if cx.tcx.hir().attrs_by_hir_id(node) + .lists(sym::doc).has_word(sym::hidden) { return true; } if node == hir::CRATE_HIR_ID { @@ -295,8 +297,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let use_attrs = tcx.hir().attrs_by_hir_id(id); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. - let is_no_inline = use_attrs.lists("doc").has_word("no_inline") || - use_attrs.lists("doc").has_word("hidden"); + let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) || + use_attrs.lists(sym::doc).has_word(sym::hidden); // For cross-crate impl inlining we need to know whether items are // reachable in documentation -- a previously nonreachable item can be @@ -304,7 +306,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // (this is done here because we need to know this upfront). if !res_did.is_local() && !is_no_inline { let attrs = clean::inline::load_attrs(self.cx, res_did); - let self_is_hidden = attrs.lists("doc").has_word("hidden"); + let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden); match res { Res::Def(DefKind::Trait, did) | Res::Def(DefKind::Struct, did) | @@ -432,8 +434,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { if item.vis.node.is_pub() && self.inside_public_path { let please_inline = item.attrs.iter().any(|item| { match item.meta_item_list() { - Some(ref list) if item.check_name("doc") => { - list.iter().any(|i| i.check_name("inline")) + Some(ref list) if item.check_name(sym::doc) => { + list.iter().any(|i| i.check_name(sym::inline)) } _ => false, } diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 326c9a10f7df..2547e3a06e9e 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -3,6 +3,7 @@ use rustc::hir::def::{Res, DefKind}; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty::Visibility; use rustc::util::nodemap::FxHashSet; +use syntax::symbol::sym; use std::cell::RefMut; @@ -42,7 +43,7 @@ impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> { // Updates node level and returns the updated level fn update(&mut self, did: DefId, level: Option) -> Option { - let is_hidden = self.cx.tcx.get_attrs(did).lists("doc").has_word("hidden"); + let is_hidden = self.cx.tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden); let old_level = self.access_levels.map.get(&did).cloned(); // Accessibility levels can only grow diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index ad5d62f667ac..55e8b39974e0 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -3,7 +3,7 @@ authors = ["The Rust Project Developers"] name = "std" version = "0.0.0" build = "build.rs" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" description = "The Rust Standard Library" edition = "2018" @@ -19,7 +19,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } core = { path = "../libcore" } libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.12" } +compiler_builtins = { version = "0.1.14" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } hashbrown = { version = "0.3.0", features = ['rustc-dep-of-std'] } @@ -54,7 +54,7 @@ default = ["compiler_builtins_c", "std_detect_file_io", "std_detect_dlsym_getaux backtrace = ["backtrace-sys"] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] -compiler_builtins_c = ["compiler_builtins/c"] +compiler_builtins_c = ["alloc/compiler-builtins-c"] llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs index 4241f47b661d..ff52974775b0 100644 --- a/src/libstd/alloc.rs +++ b/src/libstd/alloc.rs @@ -173,6 +173,9 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); /// about the allocation that failed. /// /// The allocation error hook is a global resource. +/// +/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html +/// [`take_alloc_error_hook`]: fn.take_alloc_error_hook.html #[unstable(feature = "alloc_error_hook", issue = "51245")] pub fn set_alloc_error_hook(hook: fn(Layout)) { HOOK.store(hook as *mut (), Ordering::SeqCst); @@ -183,6 +186,8 @@ pub fn set_alloc_error_hook(hook: fn(Layout)) { /// *See also the function [`set_alloc_error_hook`].* /// /// If no custom hook is registered, the default hook will be returned. +/// +/// [`set_alloc_error_hook`]: fn.set_alloc_error_hook.html #[unstable(feature = "alloc_error_hook", issue = "51245")] pub fn take_alloc_error_hook() -> fn(Layout) { let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst); diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 726c27321538..7a6c97ebaa22 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -20,8 +20,7 @@ fn main() { } else if target.contains("netbsd") { println!("cargo:rustc-link-lib=pthread"); println!("cargo:rustc-link-lib=rt"); - } else if target.contains("dragonfly") || target.contains("bitrig") || - target.contains("openbsd") { + } else if target.contains("dragonfly") || target.contains("openbsd") { println!("cargo:rustc-link-lib=pthread"); } else if target.contains("solaris") { println!("cargo:rustc-link-lib=socket"); diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index f9fb392f9f52..5a2fe2b244f5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1225,11 +1225,13 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { /// /// This is a lower-level version of [`Entry`]. /// -/// This `enum` is constructed from the [`raw_entry`] method on [`HashMap`]. +/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], +/// then calling one of the methods of that [`RawEntryBuilderMut`]. /// /// [`HashMap`]: struct.HashMap.html /// [`Entry`]: enum.Entry.html -/// [`raw_entry`]: struct.HashMap.html#method.raw_entry +/// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut +/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html #[unstable(feature = "hash_raw_entry", issue = "56167")] pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// An occupied entry. @@ -2492,7 +2494,10 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { - /// Creates a new `DefaultHasher` using [`new`][DefaultHasher::new]. + // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link + // resolution failure when re-exporting libstd items. When #56922 fixed, + // link `new` to [DefaultHasher::new] again. + /// Creates a new `DefaultHasher` using `new`. /// See its documentation for more. fn default() -> DefaultHasher { DefaultHasher::new() diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b56a27c80bc8..403914c07078 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -618,6 +618,62 @@ impl HashSet self.map.get_key_value(value).map(|(k, _)| k) } + /// Inserts the given `value` into the set if it is not present, then + /// returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert_eq!(set.len(), 3); + /// assert_eq!(set.get_or_insert(2), &2); + /// assert_eq!(set.get_or_insert(100), &100); + /// assert_eq!(set.len(), 4); // 100 was inserted + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get_or_insert(&mut self, value: T) -> &T { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0 + } + + /// Inserts a value computed from `f` into the set if the given `value` is + /// not present, then returns a reference to the value in the set. + /// + /// # Examples + /// + /// ``` + /// #![feature(hash_set_entry)] + /// + /// use std::collections::HashSet; + /// + /// let mut set: HashSet = ["cat", "dog", "horse"] + /// .iter().map(|&pet| pet.to_owned()).collect(); + /// + /// assert_eq!(set.len(), 3); + /// for &pet in &["cat", "dog", "fish"] { + /// let value = set.get_or_insert_with(pet, str::to_owned); + /// assert_eq!(value, pet); + /// } + /// assert_eq!(set.len(), 4); // a new "fish" was inserted + /// ``` + #[inline] + #[unstable(feature = "hash_set_entry", issue = "60896")] + pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + where T: Borrow, + Q: Hash + Eq, + F: FnOnce(&Q) -> T + { + // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with + // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. + self.map.raw_entry_mut().from_key(value).or_insert_with(|| (f(value), ())).0 + } + /// Returns `true` if `self` has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. /// diff --git a/src/libstd/env.rs b/src/libstd/env.rs index c0d0c23e4696..260624a8bd85 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -746,6 +746,10 @@ impl Iterator for Args { self.inner.next().map(|s| s.into_string().unwrap()) } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "env", since = "1.0.0")] @@ -781,6 +785,8 @@ impl Iterator for ArgsOs { type Item = OsString; fn next(&mut self) -> Option { self.inner.next() } fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } #[stable(feature = "env", since = "1.0.0")] @@ -845,7 +851,6 @@ pub mod consts { /// - ios /// - freebsd /// - dragonfly - /// - bitrig /// - netbsd /// - openbsd /// - solaris diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 081fff0562b1..aeb822fa99e6 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -197,16 +197,29 @@ pub trait Error: Debug + Display { fn source(&self) -> Option<&(dyn Error + 'static)> { None } /// Gets the `TypeId` of `self` - #[stable(feature = "error_type_id", since = "1.34.0")] - fn type_id(&self) -> TypeId where Self: 'static { + #[doc(hidden)] + #[unstable(feature = "error_type_id", + reason = "this is memory unsafe to override in user code", + issue = "60784")] + fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static { TypeId::of::() } } +mod private { + // This is a hack to prevent `type_id` from being overridden by `Error` + // implementations, since that can enable unsound downcasting. + #[unstable(feature = "error_type_id", issue = "60784")] + #[derive(Debug)] + pub struct Internal; +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -244,6 +257,8 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box From for Box for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -318,6 +335,8 @@ impl From for Box { impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -339,6 +358,8 @@ impl From for Box { impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -359,6 +380,8 @@ impl<'a> From<&str> for Box { impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. /// + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -378,6 +401,9 @@ impl From<&str> for Box { impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -399,6 +425,9 @@ impl<'a, 'b> From> for Box { impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. /// + /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Error`]: ../error/trait.Error.html + /// /// # Examples /// /// ``` @@ -572,7 +601,7 @@ impl dyn Error + 'static { let t = TypeId::of::(); // Get TypeId of the type in the trait object - let boxed = self.type_id(); + let boxed = self.type_id(private::Internal); // Compare both TypeIds on equality t == boxed diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index f93583dff818..5c6c43017cf6 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -43,7 +43,9 @@ use crate::sys; /// `CString` implements a [`as_ptr`] method through the [`Deref`] /// trait. This method will give you a `*const c_char` which you can /// feed directly to extern functions that expect a nul-terminated -/// string, like C's `strdup()`. +/// string, like C's `strdup()`. Notice that [`as_ptr`] returns a +/// read-only pointer; if the C code writes to it, that causes +/// undefined behavior. /// /// # Extracting a slice of the whole C string /// @@ -61,7 +63,7 @@ use crate::sys; /// /// Once you have the kind of slice you need (with or without a nul /// terminator), you can call the slice's own -/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to +/// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to /// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// @@ -1043,6 +1045,9 @@ impl CStr { /// /// **WARNING** /// + /// The returned pointer is read-only; writing to it (including passing it + /// to C code that writes to it) causes undefined behavior. + /// /// It is your responsibility to make sure that the underlying memory is not /// freed too early. For example, the following code will cause undefined /// behavior when `ptr` is used inside the `unsafe` block: diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 13aee783750f..c7c5849a00fa 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -351,6 +351,8 @@ impl From for OsString { /// Converts a [`String`] into a [`OsString`]. /// /// The conversion copies the data, and includes an allocation on the heap. + /// + /// [`OsString`]: ../../std/ffi/struct.OsString.html fn from(s: String) -> OsString { OsString { inner: Buf::from_string(s) } } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 991b45fd4a2e..616b5eb836ff 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -1812,6 +1812,8 @@ pub fn canonicalize>(path: P) -> io::Result { /// function.) /// * `path` already exists. /// +/// [`create_dir_all`]: fn.create_dir_all.html +/// /// # Examples /// /// ```no_run diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 5be2687d8f5f..e309f81192cf 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -754,7 +754,7 @@ impl fmt::Display for IntoInnerError { /// completed, rather than the entire buffer at once. Enter `LineWriter`. It /// does exactly that. /// -/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the +/// Like [`BufWriter`][bufwriter], a `LineWriter`’s buffer will also be flushed when the /// `LineWriter` goes out of scope or when its internal buffer is full. /// /// [bufwriter]: struct.BufWriter.html diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 8fea6251e652..917199f8ea8d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1579,18 +1579,13 @@ pub trait BufRead: Read { /// let stdin = io::stdin(); /// let mut stdin = stdin.lock(); /// - /// // we can't have two `&mut` references to `stdin`, so use a block - /// // to end the borrow early. - /// let length = { - /// let buffer = stdin.fill_buf().unwrap(); + /// let buffer = stdin.fill_buf().unwrap(); /// - /// // work with buffer - /// println!("{:?}", buffer); - /// - /// buffer.len() - /// }; + /// // work with buffer + /// println!("{:?}", buffer); /// /// // ensure the bytes we worked with aren't returned again later + /// let length = buffer.len(); /// stdin.consume(length); /// ``` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/keyword_docs.rs b/src/libstd/keyword_docs.rs index ffe50f11e8a5..d133c2f5cb11 100644 --- a/src/libstd/keyword_docs.rs +++ b/src/libstd/keyword_docs.rs @@ -1,6 +1,6 @@ #[doc(keyword = "as")] // -/// The keyword for casting a value to a type. +/// Cast between types, or rename an import. /// /// `as` is most commonly used to turn primitive types into other primitive types, but it has other /// uses that include turning pointers into addresses, addresses into pointers, and pointers into @@ -29,9 +29,18 @@ /// [`crate`]: keyword.crate.html mod as_keyword { } +#[doc(keyword = "break")] +// +/// Exit early from a loop. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod break_keyword { } + #[doc(keyword = "const")] // -/// The keyword for defining constants. +/// Compile-time constants and deterministic functions. /// /// Sometimes a certain value is used many times throughout a program, and it can become /// inconvenient to copy it over and over. What's more, it's not always possible or desirable to @@ -83,9 +92,18 @@ mod as_keyword { } /// [Reference]: ../reference/items/constant-items.html mod const_keyword { } +#[doc(keyword = "continue")] +// +/// Skip to the next iteration of a loop. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod continue_keyword { } + #[doc(keyword = "crate")] // -/// The `crate` keyword. +/// A Rust binary or library. /// /// The primary use of the `crate` keyword is as a part of `extern crate` declarations, which are /// used to specify a dependency on a crate external to the one it's declared in. Crates are the @@ -116,14 +134,24 @@ mod const_keyword { } /// [Reference]: ../reference/items/extern-crates.html mod crate_keyword { } +#[doc(keyword = "else")] +// +/// What to do when an [`if`] condition does not hold. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`if`]: keyword.if.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod else_keyword { } + #[doc(keyword = "enum")] // -/// For defining enumerations. +/// A type that can be any one of several variants. /// /// Enums in Rust are similar to those of other compiled languages like C, but have important /// differences that make them considerably more powerful. What Rust calls enums are more commonly -/// known as [Algebraic Data Types] if you're coming from a functional programming background. The -/// important detail is that each enum variant can have data to go along with it. +/// known as [Algebraic Data Types][ADT] if you're coming from a functional programming background. +/// The important detail is that each enum variant can have data to go along with it. /// /// ```rust /// # struct Coord; @@ -166,7 +194,7 @@ mod crate_keyword { } /// /// For more information, take a look at the [Rust Book] or the [Reference] /// -/// [Algebraic Data Types]: https://en.wikipedia.org/wiki/Algebraic_data_type +/// [ADT]: https://en.wikipedia.org/wiki/Algebraic_data_type /// [`Option`]: option/enum.Option.html /// [Rust Book]: ../book/ch06-01-defining-an-enum.html /// [Reference]: ../reference/items/enumerations.html @@ -174,7 +202,7 @@ mod enum_keyword { } #[doc(keyword = "extern")] // -/// For external connections in Rust code. +/// Link to or import external code. /// /// The `extern` keyword is used in two places in Rust. One is in conjunction with the [`crate`] /// keyword to make your Rust code aware of other Rust crates in your project, i.e., `extern crate @@ -214,9 +242,19 @@ mod enum_keyword { } /// [Reference]: ../reference/items/external-blocks.html mod extern_keyword { } +#[doc(keyword = "false")] +// +/// A value of type [`bool`] representing logical **false**. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`bool`]: primitive.bool.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod false_keyword { } + #[doc(keyword = "fn")] // -/// The keyword for defining functions. +/// A function or function pointer. /// /// Functions are the primary way code is executed within Rust. Function blocks, usually just /// called functions, can be defined in a variety of different places and be assigned many @@ -283,7 +321,8 @@ mod fn_keyword { } #[doc(keyword = "for")] // -/// The `for` keyword. +/// Iteration with [`in`], trait implementation with [`impl`], or [higher-ranked trait bounds] +/// (`for<'a>`). /// /// The `for` keyword is used in many syntactic locations: /// @@ -350,6 +389,7 @@ mod fn_keyword { } /// /// For more information on for-loops, see the [Rust book] or the [Reference]. /// +/// [`in`]: keyword.in.html /// [`impl`]: keyword.impl.html /// [higher-ranked trait bounds]: ../reference/trait-bounds.html#higher-ranked-trait-bounds /// [`IntoIterator`]: iter/trait.IntoIterator.html @@ -360,7 +400,7 @@ mod for_keyword { } #[doc(keyword = "if")] // -/// If statements and expressions. +/// Evaluate a block if a condition holds. /// /// `if` is a familiar construct to most programmers, and is the main way you'll often do logic in /// your code. However, unlike in most languages, `if` blocks can also act as expressions. @@ -434,7 +474,7 @@ mod if_keyword { } #[doc(keyword = "impl")] // -/// The implementation-defining keyword. +/// Implement some functionality for a type. /// /// The `impl` keyword is primarily used to define implementations on types. Inherent /// implementations are standalone, while trait implementations are used to implement traits for @@ -495,9 +535,19 @@ mod if_keyword { } /// [book2]: ../book/ch10-02-traits.html#returning-types-that-implement-traits mod impl_keyword { } +#[doc(keyword = "in")] +// +/// Iterate over a series of values with [`for`]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`for`]: keyword.for.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod in_keyword { } + #[doc(keyword = "let")] // -/// The variable binding keyword. +/// Bind a value to a variable. /// /// The primary use for the `let` keyword is in `let` statements, which are used to introduce a new /// set of variables into the current scope, as given by a pattern. @@ -560,7 +610,7 @@ mod let_keyword { } #[doc(keyword = "loop")] // -/// The loop-defining keyword. +/// Loop indefinitely. /// /// `loop` is used to define the simplest kind of loop supported in Rust. It runs the code inside /// it until the code uses `break` or the program exits. @@ -603,9 +653,104 @@ mod let_keyword { } /// [Reference]: ../reference/expressions/loop-expr.html mod loop_keyword { } +#[doc(keyword = "match")] +// +/// Control flow based on pattern matching. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod match_keyword { } + +#[doc(keyword = "mod")] +// +/// Organize code into [modules]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [modules]: ../reference/items/modules.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod mod_keyword { } + +#[doc(keyword = "move")] +// +/// Capture a [closure]'s environment by value. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [closure]: ../book/second-edition/ch13-01-closures.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod move_keyword { } + +#[doc(keyword = "mut")] +// +/// A mutable binding, reference, or pointer. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod mut_keyword { } + +#[doc(keyword = "pub")] +// +/// Make an item visible to others. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod pub_keyword { } + +#[doc(keyword = "ref")] +// +/// Bind by reference during pattern matching. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod ref_keyword { } + +#[doc(keyword = "return")] +// +/// Return a value from a function. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod return_keyword { } + +#[doc(keyword = "self")] +// +/// The receiver of a method, or the current module. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod self_keyword { } + +#[doc(keyword = "Self")] +// +/// The implementing type within a [`trait`] or [`impl`] block, or the current type within a type +/// definition. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`impl`]: keyword.impl.html +/// [`trait`]: keyword.trait.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod self_upper_keyword { } + +#[doc(keyword = "static")] +// +/// A place that is valid for the duration of a program. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod static_keyword { } + #[doc(keyword = "struct")] // -/// The keyword used to define structs. +/// A type that is composed of other types. /// /// Structs in Rust come in three flavors: Structs with named fields, tuple structs, and unit /// structs. @@ -710,3 +855,122 @@ mod loop_keyword { } /// [book]: ../book/ch05-01-defining-structs.html /// [reference]: ../reference/items/structs.html mod struct_keyword { } + +#[doc(keyword = "super")] +// +/// The parent of the current [module]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [module]: ../reference/items/modules.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod super_keyword { } + +#[doc(keyword = "trait")] +// +/// A common interface for a class of types. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod trait_keyword { } + +#[doc(keyword = "true")] +// +/// A value of type [`bool`] representing logical **true**. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`bool`]: primitive.bool.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod true_keyword { } + +#[doc(keyword = "type")] +// +/// Define an alias for an existing type. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod type_keyword { } + +#[doc(keyword = "unsafe")] +// +/// Code or interfaces whose [memory safety] cannot be verified by the type system. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [memory safety]: ../book/ch19-01-unsafe-rust.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod unsafe_keyword { } + +#[doc(keyword = "use")] +// +/// Import or rename items from other crates or modules. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod use_keyword { } + +#[doc(keyword = "where")] +// +/// Add constraints that must be upheld to use an item. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod where_keyword { } + +#[doc(keyword = "while")] +// +/// Loop while a condition is upheld. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod while_keyword { } + +// 2018 Edition keywords + +#[unstable(feature = "async_await", issue = "50547")] +#[doc(keyword = "async")] +// +/// Return a [`Future`] instead of blocking the current thread. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`Future`]: ./future/trait.Future.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod async_keyword { } + +#[unstable(feature = "async_await", issue = "50547")] +#[doc(keyword = "await")] +// +/// Suspend execution until the result of a [`Future`] is ready. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [`Future`]: ./future/trait.Future.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod await_keyword { } + +#[doc(keyword = "dyn")] +// +/// Name the type of a [trait object]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [trait object]: ../book/ch17-02-trait-objects.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod dyn_keyword { } + +#[doc(keyword = "union")] +// +/// The [Rust equivalent of a C-style union][union]. +/// +/// The documentation for this keyword is [not yet complete]. Pull requests welcome! +/// +/// [union]: ../reference/items/unions.html +/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601 +mod union_keyword { } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 3976f2344e24..e044b46e0d07 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -223,6 +223,7 @@ #![cfg_attr(all(target_vendor = "fortanix", target_env = "sgx"), feature(global_asm, slice_index_methods, decl_macro, coerce_unsized, sgx_platform, ptr_wrapping_offset_from))] +#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))] // std is implemented with unstable features, many of which are internal // compiler details that will never be stable @@ -271,7 +272,6 @@ #![feature(libc)] #![feature(link_args)] #![feature(linkage)] -#![feature(maybe_uninit)] #![feature(needs_panic_runtime)] #![feature(never_type)] #![feature(nll)] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 03aebeda47c4..9af7bba97aa5 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -357,61 +357,6 @@ macro_rules! dbg { }; } -/// Selects the first successful receive event from a number of receivers. -/// -/// This macro is used to wait for the first event to occur on a number of -/// receivers. It places no restrictions on the types of receivers given to -/// this macro, this can be viewed as a heterogeneous select. -/// -/// # Examples -/// -/// ``` -/// #![feature(mpsc_select)] -/// -/// use std::thread; -/// use std::sync::mpsc; -/// -/// // two placeholder functions for now -/// fn long_running_thread() {} -/// fn calculate_the_answer() -> u32 { 42 } -/// -/// let (tx1, rx1) = mpsc::channel(); -/// let (tx2, rx2) = mpsc::channel(); -/// -/// thread::spawn(move|| { long_running_thread(); tx1.send(()).unwrap(); }); -/// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); }); -/// -/// select! { -/// _ = rx1.recv() => println!("the long running thread finished first"), -/// answer = rx2.recv() => { -/// println!("the answer was: {}", answer.unwrap()); -/// } -/// } -/// # drop(rx1.recv()); -/// # drop(rx2.recv()); -/// ``` -/// -/// For more information about select, see the `std::sync::mpsc::Select` structure. -#[macro_export] -#[unstable(feature = "mpsc_select", issue = "27800")] -#[rustc_deprecated(since = "1.32.0", - reason = "channel selection will be removed in a future release")] -macro_rules! select { - ( - $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ - ) => ({ - use $crate::sync::mpsc::Select; - let sel = Select::new(); - $( let mut $rx = sel.handle(&$rx); )+ - unsafe { - $( $rx.add(); )+ - } - let ret = sel.wait(); - $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ - { unreachable!() } - }) -} - #[cfg(test)] macro_rules! assert_approx_eq { ($a:expr, $b:expr) => ({ diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index ec54d8a042a3..ca86a175058b 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -546,6 +546,9 @@ impl FromInner for SocketAddrV6 { #[stable(feature = "ip_from_ip", since = "1.16.0")] impl From for SocketAddr { /// Converts a [`SocketAddrV4`] into a [`SocketAddr::V4`]. + /// + /// [`SocketAddrV4`]: ../../std/net/struct.SocketAddrV4.html + /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4 fn from(sock4: SocketAddrV4) -> SocketAddr { SocketAddr::V4(sock4) } @@ -554,6 +557,9 @@ impl From for SocketAddr { #[stable(feature = "ip_from_ip", since = "1.16.0")] impl From for SocketAddr { /// Converts a [`SocketAddrV6`] into a [`SocketAddr::V6`]. + /// + /// [`SocketAddrV6`]: ../../std/net/struct.SocketAddrV6.html + /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6 fn from(sock6: SocketAddrV6) -> SocketAddr { SocketAddr::V6(sock6) } @@ -567,6 +573,13 @@ impl> From<(I, u16)> for SocketAddr { /// and creates a [`SocketAddr::V6`] for a [`IpAddr::V6`]. /// /// `u16` is treated as port of the newly created [`SocketAddr`]. + /// + /// [`IpAddr`]: ../../std/net/enum.IpAddr.html + /// [`IpAddr::V4`]: ../../std/net/enum.IpAddr.html#variant.V4 + /// [`IpAddr::V6`]: ../../std/net/enum.IpAddr.html#variant.V6 + /// [`SocketAddr`]: ../../std/net/enum.SocketAddr.html + /// [`SocketAddr::V4`]: ../../std/net/enum.SocketAddr.html#variant.V4 + /// [`SocketAddr::V6`]: ../../std/net/enum.SocketAddr.html#variant.V6 fn from(pieces: (I, u16)) -> SocketAddr { SocketAddr::new(pieces.0.into(), pieces.1) } @@ -974,9 +987,9 @@ mod tests { // s has been moved into the tsa call } - // FIXME: figure out why this fails on openbsd and bitrig and fix it + // FIXME: figure out why this fails on openbsd and fix it #[test] - #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))] + #[cfg(not(any(windows, target_os = "openbsd")))] fn to_socket_addr_str_bad() { assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err()); } diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 0460ac9d7535..cdffa390223a 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -1595,9 +1595,9 @@ mod tests { assert_eq!(format!("{:?}", stream), compare); } - // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code + // FIXME: re-enabled openbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 #[test] fn timeouts() { diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index d4187d2932b1..61d9149952ee 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -1024,9 +1024,9 @@ mod tests { assert_eq!(format!("{:?}", udpsock), compare); } - // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code + // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code // no longer has rounding errors. - #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)] + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)] #[test] fn timeouts() { let addr = next_test_ip4(); diff --git a/src/libstd/os/bitrig/fs.rs b/src/libstd/os/bitrig/fs.rs deleted file mode 100644 index b5c6903c4104..000000000000 --- a/src/libstd/os/bitrig/fs.rs +++ /dev/null @@ -1,138 +0,0 @@ -#![stable(feature = "metadata_ext", since = "1.1.0")] - -use crate::fs::Metadata; -use crate::sys_common::AsInner; - -#[allow(deprecated)] -use crate::os::bitrig::raw; - -/// 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 - /// the raw information returned by the OS. - /// - /// The contents of the returned `stat` are **not** consistent across - /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the - /// cross-Unix abstractions contained within the raw stat. - #[stable(feature = "metadata_ext", since = "1.1.0")] - #[rustc_deprecated(since = "1.8.0", - reason = "deprecated in favor of the accessor \ - methods of this trait")] - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat; - - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_dev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ino(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mode(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_nlink(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_uid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gid(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_rdev(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_size(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_atime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_mtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_ctime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_birthtime_nsec(&self) -> i64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blksize(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_blocks(&self) -> u64; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_flags(&self) -> u32; - #[stable(feature = "metadata_ext2", since = "1.8.0")] - fn st_gen(&self) -> u32; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for Metadata { - #[allow(deprecated)] - fn as_raw_stat(&self) -> &raw::stat { - unsafe { - &*(self.as_inner().as_inner() as *const libc::stat - as *const raw::stat) - } - } - fn st_dev(&self) -> u64 { - self.as_inner().as_inner().st_dev as u64 - } - fn st_ino(&self) -> u64 { - self.as_inner().as_inner().st_ino as u64 - } - fn st_mode(&self) -> u32 { - self.as_inner().as_inner().st_mode as u32 - } - fn st_nlink(&self) -> u64 { - self.as_inner().as_inner().st_nlink as u64 - } - fn st_uid(&self) -> u32 { - self.as_inner().as_inner().st_uid as u32 - } - fn st_gid(&self) -> u32 { - self.as_inner().as_inner().st_gid as u32 - } - fn st_rdev(&self) -> u64 { - self.as_inner().as_inner().st_rdev as u64 - } - fn st_size(&self) -> u64 { - self.as_inner().as_inner().st_size as u64 - } - fn st_atime(&self) -> i64 { - self.as_inner().as_inner().st_atime as i64 - } - fn st_atime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_atime_nsec as i64 - } - fn st_mtime(&self) -> i64 { - self.as_inner().as_inner().st_mtime as i64 - } - fn st_mtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_mtime_nsec as i64 - } - fn st_ctime(&self) -> i64 { - self.as_inner().as_inner().st_ctime as i64 - } - fn st_ctime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_ctime_nsec as i64 - } - fn st_birthtime(&self) -> i64 { - self.as_inner().as_inner().st_birthtime as i64 - } - fn st_birthtime_nsec(&self) -> i64 { - self.as_inner().as_inner().st_birthtime_nsec as i64 - } - fn st_blksize(&self) -> u64 { - self.as_inner().as_inner().st_blksize as u64 - } - fn st_blocks(&self) -> u64 { - self.as_inner().as_inner().st_blocks as u64 - } - fn st_gen(&self) -> u32 { - self.as_inner().as_inner().st_gen as u32 - } - fn st_flags(&self) -> u32 { - self.as_inner().as_inner().st_flags as u32 - } -} diff --git a/src/libstd/os/bitrig/mod.rs b/src/libstd/os/bitrig/mod.rs deleted file mode 100644 index 0bc105bb2b40..000000000000 --- a/src/libstd/os/bitrig/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Bitrig-specific definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] - -pub mod raw; -pub mod fs; diff --git a/src/libstd/os/bitrig/raw.rs b/src/libstd/os/bitrig/raw.rs deleted file mode 100644 index c966d5a8e5b4..000000000000 --- a/src/libstd/os/bitrig/raw.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Bitrig-specific raw type definitions - -#![stable(feature = "raw_ext", since = "1.1.0")] -#![rustc_deprecated(since = "1.8.0", - reason = "these type aliases are no longer supported by \ - the standard library, the `libc` crate on \ - crates.io should be used instead for the correct \ - definitions")] -#![allow(deprecated)] - -use crate::os::raw::c_long; -use crate::os::unix::raw::{uid_t, gid_t}; - -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64; -#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64; - -#[stable(feature = "pthread_t", since = "1.8.0")] -pub type pthread_t = usize; - -#[repr(C)] -#[derive(Clone)] -#[stable(feature = "raw_ext", since = "1.1.0")] -pub struct stat { - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: i32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: u64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_flags: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gen: u32, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime: i64, - #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_birthtime_nsec: i64, -} diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index 7b56d6d62cf2..44cbc180b8b0 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -39,7 +39,6 @@ cfg_if! { } #[cfg(target_os = "android")] pub mod android; -#[cfg(target_os = "bitrig")] pub mod bitrig; #[cfg(target_os = "dragonfly")] pub mod dragonfly; #[cfg(target_os = "freebsd")] pub mod freebsd; #[cfg(target_os = "haiku")] pub mod haiku; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 126bc3754dab..59f9e439add2 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -888,6 +888,11 @@ impl<'a> Iterator for Iter<'a> { fn next(&mut self) -> Option<&'a OsStr> { self.inner.next().map(Component::as_os_str) } + + #[inline] + fn last(mut self) -> Option<&'a OsStr> { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -951,6 +956,11 @@ impl<'a> Iterator for Components<'a> { } None } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 04353fde1b4d..69ecd201063b 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -116,7 +116,6 @@ //! ``` #![stable(feature = "rust1", since = "1.0.0")] -#![allow(deprecated)] // for mpsc_select // A description of how Rust's channel implementation works // @@ -263,6 +262,8 @@ // believe that there is anything fundamental that needs to change about these // channels, however, in order to support a more efficient select(). // +// FIXME: Select is now removed, so these factors are ready to be cleaned up! +// // # Conclusion // // And now that you've seen all the races that I found and attempted to fix, @@ -275,18 +276,8 @@ use crate::mem; use crate::cell::UnsafeCell; use crate::time::{Duration, Instant}; -#[unstable(feature = "mpsc_select", issue = "27800")] -pub use self::select::{Select, Handle}; -use self::select::StartResult; -use self::select::StartResult::*; -use self::blocking::SignalToken; - -#[cfg(all(test, not(target_os = "emscripten")))] -mod select_tests; - mod blocking; mod oneshot; -mod select; mod shared; mod stream; mod sync; @@ -1514,78 +1505,6 @@ impl Receiver { } -impl select::Packet for Receiver { - fn can_recv(&self) -> bool { - loop { - let new_port = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.can_recv() { - Ok(ret) => return ret, - Err(upgrade) => upgrade, - } - } - Flavor::Stream(ref p) => { - match p.can_recv() { - Ok(ret) => return ret, - Err(upgrade) => upgrade, - } - } - Flavor::Shared(ref p) => return p.can_recv(), - Flavor::Sync(ref p) => return p.can_recv(), - }; - unsafe { - mem::swap(self.inner_mut(), - new_port.inner_mut()); - } - } - } - - fn start_selection(&self, mut token: SignalToken) -> StartResult { - loop { - let (t, new_port) = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => { - match p.start_selection(token) { - oneshot::SelSuccess => return Installed, - oneshot::SelCanceled => return Abort, - oneshot::SelUpgraded(t, rx) => (t, rx), - } - } - Flavor::Stream(ref p) => { - match p.start_selection(token) { - stream::SelSuccess => return Installed, - stream::SelCanceled => return Abort, - stream::SelUpgraded(t, rx) => (t, rx), - } - } - Flavor::Shared(ref p) => return p.start_selection(token), - Flavor::Sync(ref p) => return p.start_selection(token), - }; - token = t; - unsafe { - mem::swap(self.inner_mut(), new_port.inner_mut()); - } - } - } - - fn abort_selection(&self) -> bool { - let mut was_upgrade = false; - loop { - let result = match *unsafe { self.inner() } { - Flavor::Oneshot(ref p) => p.abort_selection(), - Flavor::Stream(ref p) => p.abort_selection(was_upgrade), - Flavor::Shared(ref p) => return p.abort_selection(was_upgrade), - Flavor::Sync(ref p) => return p.abort_selection(), - }; - let new_port = match result { Ok(b) => return b, Err(p) => p }; - was_upgrade = true; - unsafe { - mem::swap(self.inner_mut(), - new_port.inner_mut()); - } - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Iterator for Iter<'a, T> { type Item = T; diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 5c516d5de0f1..e7a5cc46b31a 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -24,7 +24,6 @@ pub use self::Failure::*; pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; use self::MyUpgrade::*; use crate::sync::mpsc::Receiver; @@ -66,12 +65,6 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { - SelCanceled, - SelUpgraded(SignalToken, Receiver), - SelSuccess, -} - enum MyUpgrade { NothingSent, SendUsed, @@ -264,71 +257,6 @@ impl Packet { // select implementation //////////////////////////////////////////////////////////////////////////// - // If Ok, the value is whether this port has data, if Err, then the upgraded - // port needs to be checked instead of this one. - pub fn can_recv(&self) -> Result> { - unsafe { - match self.state.load(Ordering::SeqCst) { - EMPTY => Ok(false), // Welp, we tried - DATA => Ok(true), // we have some un-acquired data - DISCONNECTED if (*self.data.get()).is_some() => Ok(true), // we have data - DISCONNECTED => { - match ptr::replace(self.upgrade.get(), SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => Err(upgrade), - - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { ptr::write(self.upgrade.get(), up); Ok(true) } - } - } - _ => unreachable!(), // we're the "one blocker" - } - } - } - - // Attempts to start selection on this port. This can either succeed, fail - // because there is data, or fail because there is an upgrade pending. - pub fn start_selection(&self, token: SignalToken) -> SelectionResult { - unsafe { - let ptr = token.cast_to_usize(); - match self.state.compare_and_swap(EMPTY, ptr, Ordering::SeqCst) { - EMPTY => SelSuccess, - DATA => { - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - DISCONNECTED if (*self.data.get()).is_some() => { - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - DISCONNECTED => { - match ptr::replace(self.upgrade.get(), SendUsed) { - // The other end sent us an upgrade, so we need to - // propagate upwards whether the upgrade can receive - // data - GoUp(upgrade) => { - SelUpgraded(SignalToken::cast_from_usize(ptr), upgrade) - } - - // If the other end disconnected without sending an - // upgrade, then we have data to receive (the channel is - // disconnected). - up => { - ptr::write(self.upgrade.get(), up); - drop(SignalToken::cast_from_usize(ptr)); - SelCanceled - } - } - } - _ => unreachable!(), // we're the "one blocker" - } - } - } - // Remove a previous selecting thread from this port. This ensures that the // blocked thread will no longer be visible to any other threads. // diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs deleted file mode 100644 index d1b5f2deccc1..000000000000 --- a/src/libstd/sync/mpsc/select.rs +++ /dev/null @@ -1,352 +0,0 @@ -//! Selection over an array of receivers -//! -//! This module contains the implementation machinery necessary for selecting -//! over a number of receivers. One large goal of this module is to provide an -//! efficient interface to selecting over any receiver of any type. -//! -//! This is achieved through an architecture of a "receiver set" in which -//! receivers are added to a set and then the entire set is waited on at once. -//! The set can be waited on multiple times to prevent re-adding each receiver -//! to the set. -//! -//! Usage of this module is currently encouraged to go through the use of the -//! `select!` macro. This macro allows naturally binding of variables to the -//! received values of receivers in a much more natural syntax then usage of the -//! `Select` structure directly. -//! -//! # Examples -//! -//! ```rust -//! #![feature(mpsc_select)] -//! -//! use std::sync::mpsc::channel; -//! -//! let (tx1, rx1) = channel(); -//! let (tx2, rx2) = channel(); -//! -//! tx1.send(1).unwrap(); -//! tx2.send(2).unwrap(); -//! -//! select! { -//! val = rx1.recv() => { -//! assert_eq!(val.unwrap(), 1); -//! }, -//! val = rx2.recv() => { -//! assert_eq!(val.unwrap(), 2); -//! } -//! } -//! ``` - -#![allow(dead_code)] -#![unstable(feature = "mpsc_select", - reason = "This implementation, while likely sufficient, is unsafe and \ - likely to be error prone. At some point in the future this \ - module will be removed.", - issue = "27800")] -#![rustc_deprecated(since = "1.32.0", - reason = "channel selection will be removed in a future release")] - -use core::cell::{Cell, UnsafeCell}; -use core::marker; -use core::ptr; -use core::usize; - -use crate::fmt; -use crate::sync::mpsc::{Receiver, RecvError}; -use crate::sync::mpsc::blocking::{self, SignalToken}; - -/// The "receiver set" of the select interface. This structure is used to manage -/// a set of receivers which are being selected over. -pub struct Select { - inner: UnsafeCell, - next_id: Cell, -} - -struct SelectInner { - head: *mut Handle<'static, ()>, - tail: *mut Handle<'static, ()>, -} - -impl !marker::Send for Select {} - -/// A handle to a receiver which is currently a member of a `Select` set of -/// receivers. This handle is used to keep the receiver in the set as well as -/// interact with the underlying receiver. -pub struct Handle<'rx, T:Send+'rx> { - /// The ID of this handle, used to compare against the return value of - /// `Select::wait()`. - id: usize, - selector: *mut SelectInner, - next: *mut Handle<'static, ()>, - prev: *mut Handle<'static, ()>, - added: bool, - packet: &'rx (dyn Packet+'rx), - - // due to our fun transmutes, we be sure to place this at the end. (nothing - // previous relies on T) - rx: &'rx Receiver, -} - -struct Packets { cur: *mut Handle<'static, ()> } - -#[doc(hidden)] -#[derive(PartialEq, Eq)] -pub enum StartResult { - Installed, - Abort, -} - -#[doc(hidden)] -pub trait Packet { - fn can_recv(&self) -> bool; - fn start_selection(&self, token: SignalToken) -> StartResult; - fn abort_selection(&self) -> bool; -} - -impl Select { - /// Creates a new selection structure. This set is initially empty. - /// - /// Usage of this struct directly can sometimes be burdensome, and usage is much easier through - /// the `select!` macro. - /// - /// # Examples - /// - /// ``` - /// #![feature(mpsc_select)] - /// - /// use std::sync::mpsc::Select; - /// - /// let select = Select::new(); - /// ``` - pub fn new() -> Select { - Select { - inner: UnsafeCell::new(SelectInner { - head: ptr::null_mut(), - tail: ptr::null_mut(), - }), - next_id: Cell::new(1), - } - } - - /// Creates a new handle into this receiver set for a new receiver. Note - /// that this does *not* add the receiver to the receiver set, for that you - /// must call the `add` method on the handle itself. - pub fn handle<'a, T: Send>(&'a self, rx: &'a Receiver) -> Handle<'a, T> { - let id = self.next_id.get(); - self.next_id.set(id + 1); - Handle { - id, - selector: self.inner.get(), - next: ptr::null_mut(), - prev: ptr::null_mut(), - added: false, - rx, - packet: rx, - } - } - - /// Waits for an event on this receiver set. The returned value is *not* an - /// index, but rather an ID. This ID can be queried against any active - /// `Handle` structures (each one has an `id` method). The handle with - /// the matching `id` will have some sort of event available on it. The - /// event could either be that data is available or the corresponding - /// channel has been closed. - pub fn wait(&self) -> usize { - self.wait2(true) - } - - /// Helper method for skipping the preflight checks during testing - pub(super) fn wait2(&self, do_preflight_checks: bool) -> usize { - // Note that this is currently an inefficient implementation. We in - // theory have knowledge about all receivers in the set ahead of time, - // so this method shouldn't really have to iterate over all of them yet - // again. The idea with this "receiver set" interface is to get the - // interface right this time around, and later this implementation can - // be optimized. - // - // This implementation can be summarized by: - // - // fn select(receivers) { - // if any receiver ready { return ready index } - // deschedule { - // block on all receivers - // } - // unblock on all receivers - // return ready index - // } - // - // Most notably, the iterations over all of the receivers shouldn't be - // necessary. - unsafe { - // Stage 1: preflight checks. Look for any packets ready to receive - if do_preflight_checks { - for handle in self.iter() { - if (*handle).packet.can_recv() { - return (*handle).id(); - } - } - } - - // Stage 2: begin the blocking process - // - // Create a number of signal tokens, and install each one - // sequentially until one fails. If one fails, then abort the - // selection on the already-installed tokens. - let (wait_token, signal_token) = blocking::tokens(); - for (i, handle) in self.iter().enumerate() { - match (*handle).packet.start_selection(signal_token.clone()) { - StartResult::Installed => {} - StartResult::Abort => { - // Go back and abort the already-begun selections - for handle in self.iter().take(i) { - (*handle).packet.abort_selection(); - } - return (*handle).id; - } - } - } - - // Stage 3: no messages available, actually block - wait_token.wait(); - - // Stage 4: there *must* be message available; find it. - // - // Abort the selection process on each receiver. If the abort - // process returns `true`, then that means that the receiver is - // ready to receive some data. Note that this also means that the - // receiver may have yet to have fully read the `to_wake` field and - // woken us up (although the wakeup is guaranteed to fail). - // - // This situation happens in the window of where a sender invokes - // increment(), sees -1, and then decides to wake up the thread. After - // all this is done, the sending thread will set `selecting` to - // `false`. Until this is done, we cannot return. If we were to - // return, then a sender could wake up a receiver which has gone - // back to sleep after this call to `select`. - // - // Note that it is a "fairly small window" in which an increment() - // views that it should wake a thread up until the `selecting` bit - // is set to false. For now, the implementation currently just spins - // in a yield loop. This is very distasteful, but this - // implementation is already nowhere near what it should ideally be. - // A rewrite should focus on avoiding a yield loop, and for now this - // implementation is tying us over to a more efficient "don't - // iterate over everything every time" implementation. - let mut ready_id = usize::MAX; - for handle in self.iter() { - if (*handle).packet.abort_selection() { - ready_id = (*handle).id; - } - } - - // We must have found a ready receiver - assert!(ready_id != usize::MAX); - return ready_id; - } - } - - fn iter(&self) -> Packets { Packets { cur: unsafe { &*self.inner.get() }.head } } -} - -impl<'rx, T: Send> Handle<'rx, T> { - /// Retrieves the ID of this handle. - #[inline] - pub fn id(&self) -> usize { self.id } - - /// Blocks to receive a value on the underlying receiver, returning `Some` on - /// success or `None` if the channel disconnects. This function has the same - /// semantics as `Receiver.recv` - pub fn recv(&mut self) -> Result { self.rx.recv() } - - /// Adds this handle to the receiver set that the handle was created from. This - /// method can be called multiple times, but it has no effect if `add` was - /// called previously. - /// - /// This method is unsafe because it requires that the `Handle` is not moved - /// while it is added to the `Select` set. - pub unsafe fn add(&mut self) { - if self.added { return } - let selector = &mut *self.selector; - let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>; - - if selector.head.is_null() { - selector.head = me; - selector.tail = me; - } else { - (*me).prev = selector.tail; - assert!((*me).next.is_null()); - (*selector.tail).next = me; - selector.tail = me; - } - self.added = true; - } - - /// Removes this handle from the `Select` set. This method is unsafe because - /// it has no guarantee that the `Handle` was not moved since `add` was - /// called. - pub unsafe fn remove(&mut self) { - if !self.added { return } - - let selector = &mut *self.selector; - let me = self as *mut Handle<'rx, T> as *mut Handle<'static, ()>; - - if self.prev.is_null() { - assert_eq!(selector.head, me); - selector.head = self.next; - } else { - (*self.prev).next = self.next; - } - if self.next.is_null() { - assert_eq!(selector.tail, me); - selector.tail = self.prev; - } else { - (*self.next).prev = self.prev; - } - - self.next = ptr::null_mut(); - self.prev = ptr::null_mut(); - - self.added = false; - } -} - -impl Drop for Select { - fn drop(&mut self) { - unsafe { - assert!((&*self.inner.get()).head.is_null()); - assert!((&*self.inner.get()).tail.is_null()); - } - } -} - -impl Drop for Handle<'_, T> { - fn drop(&mut self) { - unsafe { self.remove() } - } -} - -impl Iterator for Packets { - type Item = *mut Handle<'static, ()>; - - fn next(&mut self) -> Option<*mut Handle<'static, ()>> { - if self.cur.is_null() { - None - } else { - let ret = Some(self.cur); - unsafe { self.cur = (*self.cur).next; } - ret - } - } -} - -impl fmt::Debug for Select { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Select").finish() - } -} - -impl fmt::Debug for Handle<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Handle").finish() - } -} diff --git a/src/libstd/sync/mpsc/select_tests.rs b/src/libstd/sync/mpsc/select_tests.rs deleted file mode 100644 index 18d93462c78d..000000000000 --- a/src/libstd/sync/mpsc/select_tests.rs +++ /dev/null @@ -1,413 +0,0 @@ -#![allow(unused_imports)] - -/// This file exists to hack around https://github.com/rust-lang/rust/issues/47238 - -use crate::thread; -use crate::sync::mpsc::*; - -// Don't use the libstd version so we can pull in the right Select structure -// (std::comm points at the wrong one) -macro_rules! select { - ( - $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ - ) => ({ - let sel = Select::new(); - $( let mut $rx = sel.handle(&$rx); )+ - unsafe { - $( $rx.add(); )+ - } - let ret = sel.wait(); - $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ - { unreachable!() } - }) -} - -#[test] -fn smoke() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - tx1.send(1).unwrap(); - select! { - foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); }, - _bar = rx2.recv() => { panic!() } - } - tx2.send(2).unwrap(); - select! { - _foo = rx1.recv() => { panic!() }, - bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) } - } - drop(tx1); - select! { - foo = rx1.recv() => { assert!(foo.is_err()); }, - _bar = rx2.recv() => { panic!() } - } - drop(tx2); - select! { - bar = rx2.recv() => { assert!(bar.is_err()); } - } -} - -#[test] -fn smoke2() { - let (_tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (_tx3, rx3) = channel::(); - let (_tx4, rx4) = channel::(); - let (tx5, rx5) = channel::(); - tx5.send(4).unwrap(); - select! { - _foo = rx1.recv() => { panic!("1") }, - _foo = rx2.recv() => { panic!("2") }, - _foo = rx3.recv() => { panic!("3") }, - _foo = rx4.recv() => { panic!("4") }, - foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); } - } -} - -#[test] -fn closed() { - let (_tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - drop(tx2); - - select! { - _a1 = rx1.recv() => { panic!() }, - a2 = rx2.recv() => { assert!(a2.is_err()); } - } -} - -#[test] -fn unblocks() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::(); - - let _t = thread::spawn(move|| { - for _ in 0..20 { thread::yield_now(); } - tx1.send(1).unwrap(); - rx3.recv().unwrap(); - for _ in 0..20 { thread::yield_now(); } - }); - - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - _b = rx2.recv() => { panic!() } - } - tx3.send(1).unwrap(); - select! { - a = rx1.recv() => { assert!(a.is_err()) }, - _b = rx2.recv() => { panic!() } - } -} - -#[test] -fn both_ready() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - for _ in 0..20 { thread::yield_now(); } - tx1.send(1).unwrap(); - tx2.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } - } - select! { - a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, - a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } - } - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty)); - tx3.send(()).unwrap(); -} - -#[test] -fn stress() { - const AMT: i32 = 10000; - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - for i in 0..AMT { - if i % 2 == 0 { - tx1.send(i).unwrap(); - } else { - tx2.send(i).unwrap(); - } - rx3.recv().unwrap(); - } - }); - - for i in 0..AMT { - select! { - i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); }, - i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); } - } - tx3.send(()).unwrap(); - } -} - -#[allow(unused_must_use)] -#[test] -fn cloning() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - rx3.recv().unwrap(); - tx1.clone(); - assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); - tx1.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - tx3.send(()).unwrap(); - select! { - _i1 = rx1.recv() => {}, - _i2 = rx2.recv() => panic!() - } - tx3.send(()).unwrap(); -} - -#[allow(unused_must_use)] -#[test] -fn cloning2() { - let (tx1, rx1) = channel::(); - let (_tx2, rx2) = channel::(); - let (tx3, rx3) = channel::<()>(); - - let _t = thread::spawn(move|| { - rx3.recv().unwrap(); - tx1.clone(); - assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); - tx1.send(2).unwrap(); - rx3.recv().unwrap(); - }); - - tx3.send(()).unwrap(); - select! { - _i1 = rx1.recv() => {}, - _i2 = rx2.recv() => panic!() - } - tx3.send(()).unwrap(); -} - -#[test] -fn cloning3() { - let (tx1, rx1) = channel::<()>(); - let (tx2, rx2) = channel::<()>(); - let (tx3, rx3) = channel::<()>(); - let _t = thread::spawn(move|| { - let s = Select::new(); - let mut h1 = s.handle(&rx1); - let mut h2 = s.handle(&rx2); - unsafe { h2.add(); } - unsafe { h1.add(); } - assert_eq!(s.wait(), h2.id()); - tx3.send(()).unwrap(); - }); - - for _ in 0..1000 { thread::yield_now(); } - drop(tx1.clone()); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); -} - -#[test] -fn preflight1() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } -} - -#[test] -fn preflight2() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } -} - -#[test] -fn preflight3() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - select! { - _n = rx.recv() => {} - } -} - -#[test] -fn preflight4() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight5() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight6() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight7() { - let (tx, rx) = channel::<()>(); - drop(tx); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight8() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - drop(tx); - rx.recv().unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn preflight9() { - let (tx, rx) = channel(); - drop(tx.clone()); - tx.send(()).unwrap(); - drop(tx); - rx.recv().unwrap(); - let s = Select::new(); - let mut h = s.handle(&rx); - unsafe { h.add(); } - assert_eq!(s.wait2(false), h.id()); -} - -#[test] -fn oneshot_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn stream_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - tx1.send(()).unwrap(); - tx1.send(()).unwrap(); - rx1.recv().unwrap(); - rx1.recv().unwrap(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn shared_data_waiting() { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - drop(tx1.clone()); - tx1.send(()).unwrap(); - rx1.recv().unwrap(); - let _t = thread::spawn(move|| { - select! { - _n = rx1.recv() => {} - } - tx2.send(()).unwrap(); - }); - - for _ in 0..100 { thread::yield_now() } - tx1.send(()).unwrap(); - rx2.recv().unwrap(); -} - -#[test] -fn sync1() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - select! { - n = rx.recv() => { assert_eq!(n.unwrap(), 1); } - } -} - -#[test] -fn sync2() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move|| { - for _ in 0..100 { thread::yield_now() } - tx.send(1).unwrap(); - }); - select! { - n = rx.recv() => { assert_eq!(n.unwrap(), 1); } - } -} - -#[test] -fn sync3() { - let (tx1, rx1) = sync_channel::(0); - let (tx2, rx2): (Sender, Receiver) = channel(); - let _t = thread::spawn(move|| { tx1.send(1).unwrap(); }); - let _t = thread::spawn(move|| { tx2.send(2).unwrap(); }); - select! { - n = rx1.recv() => { - let n = n.unwrap(); - assert_eq!(n, 1); - assert_eq!(rx2.recv().unwrap(), 2); - }, - n = rx2.recv() => { - let n = n.unwrap(); - assert_eq!(n, 2); - assert_eq!(rx1.recv().unwrap(), 1); - } - } -} diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index cc70a6203659..dbcdcdac9326 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -9,6 +9,7 @@ /// channels are quite similar, and this is no coincidence! pub use self::Failure::*; +use self::StartResult::*; use core::cmp; use core::intrinsics::abort; @@ -19,8 +20,6 @@ use crate::ptr; use crate::sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; use crate::sync::mpsc::blocking::{self, SignalToken}; use crate::sync::mpsc::mpsc_queue as mpsc; -use crate::sync::mpsc::select::StartResult::*; -use crate::sync::mpsc::select::StartResult; use crate::sync::{Mutex, MutexGuard}; use crate::thread; use crate::time::Instant; @@ -57,6 +56,12 @@ pub enum Failure { Disconnected, } +#[derive(PartialEq, Eq)] +enum StartResult { + Installed, + Abort, +} + impl Packet { // Creation of a packet *must* be followed by a call to postinit_lock // and later by inherit_blocker @@ -394,16 +399,6 @@ impl Packet { // select implementation //////////////////////////////////////////////////////////////////////////// - // Helper function for select, tests whether this port can receive without - // blocking (obviously not an atomic decision). - // - // This is different than the stream version because there's no need to peek - // at the queue, we can just look at the local count. - pub fn can_recv(&self) -> bool { - let cnt = self.cnt.load(Ordering::SeqCst); - cnt == DISCONNECTED || cnt - unsafe { *self.steals.get() } > 0 - } - // increment the count on the channel (used for selection) fn bump(&self, amt: isize) -> isize { match self.cnt.fetch_add(amt, Ordering::SeqCst) { @@ -415,22 +410,6 @@ impl Packet { } } - // Inserts the signal token for selection on this port, returning true if - // blocking should proceed. - // - // The code here is the same as in stream.rs, except that it doesn't need to - // peek at the channel to see if an upgrade is pending. - pub fn start_selection(&self, token: SignalToken) -> StartResult { - match self.decrement(token) { - Installed => Installed, - Abort => { - let prev = self.bump(1); - assert!(prev == DISCONNECTED || prev >= 0); - Abort - } - } - } - // Cancels a previous thread waiting on this port, returning whether there's // data on the port. // diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 7ae6f68b5145..408772827617 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -9,7 +9,6 @@ pub use self::Failure::*; pub use self::UpgradeResult::*; -pub use self::SelectionResult::*; use self::Message::*; use core::cmp; @@ -60,12 +59,6 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { - SelSuccess, - SelCanceled, - SelUpgraded(SignalToken, Receiver), -} - // Any message could contain an "upgrade request" to a new shared port, so the // internal queue it's a queue of T, but rather Message enum Message { @@ -338,27 +331,6 @@ impl Packet { // select implementation //////////////////////////////////////////////////////////////////////////// - // Tests to see whether this port can receive without blocking. If Ok is - // returned, then that's the answer. If Err is returned, then the returned - // port needs to be queried instead (an upgrade happened) - pub fn can_recv(&self) -> Result> { - // We peek at the queue to see if there's anything on it, and we use - // this return value to determine if we should pop from the queue and - // upgrade this channel immediately. If it looks like we've got an - // upgrade pending, then go through the whole recv rigamarole to update - // the internal state. - match self.queue.peek() { - Some(&mut GoUp(..)) => { - match self.recv(None) { - Err(Upgraded(port)) => Err(port), - _ => unreachable!(), - } - } - Some(..) => Ok(true), - None => Ok(false) - } - } - // increment the count on the channel (used for selection) fn bump(&self, amt: isize) -> isize { match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) { @@ -370,31 +342,6 @@ impl Packet { } } - // Attempts to start selecting on this port. Like a oneshot, this can fail - // immediately because of an upgrade. - pub fn start_selection(&self, token: SignalToken) -> SelectionResult { - match self.decrement(token) { - Ok(()) => SelSuccess, - Err(token) => { - let ret = match self.queue.peek() { - Some(&mut GoUp(..)) => { - match self.queue.pop() { - Some(GoUp(port)) => SelUpgraded(token, port), - _ => unreachable!(), - } - } - Some(..) => SelCanceled, - None => SelCanceled, - }; - // Undo our decrement above, and we should be guaranteed that the - // previous value is positive because we're not going to sleep - let prev = self.bump(1); - assert!(prev == DISCONNECTED || prev >= 0); - ret - } - } - } - // Removes a previous thread from being blocked in this port pub fn abort_selection(&self, was_upgrade: bool) -> Result> { diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index b2d9f4c6491e..3c4f8e077c92 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -33,7 +33,6 @@ use core::ptr; use crate::sync::atomic::{Ordering, AtomicUsize}; use crate::sync::mpsc::blocking::{self, WaitToken, SignalToken}; -use crate::sync::mpsc::select::StartResult::{self, Installed, Abort}; use crate::sync::{Mutex, MutexGuard}; use crate::time::Instant; @@ -406,42 +405,6 @@ impl Packet { while let Some(token) = queue.dequeue() { token.signal(); } waiter.map(|t| t.signal()); } - - //////////////////////////////////////////////////////////////////////////// - // select implementation - //////////////////////////////////////////////////////////////////////////// - - // If Ok, the value is whether this port has data, if Err, then the upgraded - // port needs to be checked instead of this one. - pub fn can_recv(&self) -> bool { - let guard = self.lock.lock().unwrap(); - guard.disconnected || guard.buf.size() > 0 - } - - // Attempts to start selection on this port. This can either succeed or fail - // because there is data waiting. - pub fn start_selection(&self, token: SignalToken) -> StartResult { - let mut guard = self.lock.lock().unwrap(); - if guard.disconnected || guard.buf.size() > 0 { - Abort - } else { - match mem::replace(&mut guard.blocker, BlockedReceiver(token)) { - NoneBlocked => {} - BlockedSender(..) => unreachable!(), - BlockedReceiver(..) => unreachable!(), - } - Installed - } - } - - // Remove a previous selecting thread from this port. This ensures that the - // blocked thread will no longer be visible to any other threads. - // - // The return value indicates whether there's data on this port. - pub fn abort_selection(&self) -> bool { - let mut guard = self.lock.lock().unwrap(); - abort_selection(&mut guard) - } } impl Drop for Packet { diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 11ac34fcb24f..87c2318a9377 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -376,6 +376,8 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex { impl From for Mutex { /// Creates a new mutex in an unlocked state ready for use. /// This is equivalent to [`Mutex::new`]. + /// + /// [`Mutex::new`]: ../../std/sync/struct.Mutex.html#method.new fn from(t: T) -> Self { Mutex::new(t) } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 1299a7440956..b1b56f321fc6 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -453,6 +453,8 @@ impl Default for RwLock { impl From for RwLock { /// Creates a new instance of an `RwLock` which is unlocked. /// This is equivalent to [`RwLock::new`]. + /// + /// [`RwLock::new`]: ../../std/sync/struct.RwLock.html#method.new fn from(t: T) -> Self { RwLock::new(t) } diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index 18de1096df2a..6ba947d4598b 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -35,6 +35,8 @@ impl Iterator for Args { type Item = OsString; fn next(&mut self) -> Option { self.iter.next() } fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } impl ExactSizeIterator for Args { @@ -49,7 +51,6 @@ impl DoubleEndedIterator for Args { target_os = "android", target_os = "freebsd", target_os = "dragonfly", - target_os = "bitrig", target_os = "netbsd", target_os = "openbsd", target_os = "solaris", diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs index f9592d5c45f9..891013406a16 100644 --- a/src/libstd/sys/unix/env.rs +++ b/src/libstd/sys/unix/env.rs @@ -53,17 +53,6 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } -#[cfg(target_os = "bitrig")] -pub mod os { - pub const FAMILY: &str = "unix"; - pub const OS: &str = "bitrig"; - pub const DLL_PREFIX: &str = "lib"; - pub const DLL_SUFFIX: &str = ".so"; - pub const DLL_EXTENSION: &str = "so"; - pub const EXE_SUFFIX: &str = ""; - pub const EXE_EXTENSION: &str = ""; -} - #[cfg(target_os = "netbsd")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 45a850aa4a85..3ccb0a1b1abc 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -32,12 +32,12 @@ use crate::sys_common::{self, AsInner, FromInner, IntoInner}; #[cfg(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig"))] + target_os = "haiku"))] use libc::MSG_NOSIGNAL; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig")))] + target_os = "haiku")))] const MSG_NOSIGNAL: libc::c_int = 0x0; fn sun_path_offset() -> usize { diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 22c05a72a91c..cc1f0790d433 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -147,8 +147,7 @@ impl FileAttr { })) } - #[cfg(any(target_os = "bitrig", - target_os = "freebsd", + #[cfg(any(target_os = "freebsd", target_os = "openbsd", target_os = "macos", target_os = "ios"))] @@ -159,8 +158,7 @@ impl FileAttr { })) } - #[cfg(not(any(target_os = "bitrig", - target_os = "freebsd", + #[cfg(not(any(target_os = "freebsd", target_os = "openbsd", target_os = "macos", target_os = "ios")))] @@ -355,7 +353,6 @@ impl DirEntry { #[cfg(any(target_os = "freebsd", target_os = "openbsd", - target_os = "bitrig", target_os = "netbsd", target_os = "dragonfly"))] pub fn ino(&self) -> u64 { @@ -367,8 +364,7 @@ impl DirEntry { target_os = "netbsd", target_os = "openbsd", target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig"))] + target_os = "dragonfly"))] fn name_bytes(&self) -> &[u8] { use crate::slice; unsafe { diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 90e26449ae28..c2b264ff8de1 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -5,7 +5,6 @@ use crate::io::ErrorKind; #[cfg(any(rustdoc, target_os = "linux"))] pub use crate::os::linux as platform; #[cfg(all(not(rustdoc), target_os = "android"))] pub use crate::os::android as platform; -#[cfg(all(not(rustdoc), target_os = "bitrig"))] pub use crate::os::bitrig as platform; #[cfg(all(not(rustdoc), target_os = "dragonfly"))] pub use crate::os::dragonfly as platform; #[cfg(all(not(rustdoc), target_os = "freebsd"))] pub use crate::os::freebsd as platform; #[cfg(all(not(rustdoc), target_os = "haiku"))] pub use crate::os::haiku as platform; diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 726b17969b7c..dad19eabf7db 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -33,8 +33,7 @@ extern { target_os = "fuchsia", target_os = "l4re"), link_name = "__errno_location")] - #[cfg_attr(any(target_os = "bitrig", - target_os = "netbsd", + #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "android", target_os = "hermit", @@ -257,7 +256,7 @@ pub fn current_exe() -> io::Result { sysctl().or_else(|_| procfs()) } -#[cfg(any(target_os = "bitrig", target_os = "openbsd"))] +#[cfg(target_os = "openbsd")] pub fn current_exe() -> io::Result { unsafe { let mut mib = [libc::CTL_KERN, diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index e923b9aa29b0..71c62461ee9c 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) { #[cfg(all(unix, not(target_os = "ios"), - not(all(target_os = "macos", miri)), not(target_os = "openbsd"), not(target_os = "freebsd"), not(target_os = "fuchsia")))] @@ -48,7 +47,12 @@ mod imp { let err = errno() as libc::c_int; if err == libc::EINTR { continue; - } else if err == libc::ENOSYS { + } else if err == libc::ENOSYS || err == libc::EPERM { + // Fall back to reading /dev/urandom if `getrandom` is not + // supported on the current kernel. + // + // Also fall back in case it is disabled by something like + // seccomp or inside of virtual machines. GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed); return false; } else if err == libc::EAGAIN { @@ -107,9 +111,7 @@ mod imp { // once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is // only used on iOS where direct access to `/dev/urandom` is blocked by the // sandbox. -// HACK: However, we do use this when running in Miri on macOS; intercepting this is much -// easier than intercepting accesses to /dev/urandom. -#[cfg(any(target_os = "ios", all(target_os = "macos", miri)))] +#[cfg(target_os = "ios")] mod imp { use crate::io; use crate::ptr; diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 561279e82785..fe1095fa0c2f 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -25,7 +25,6 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "bitrig", target_os = "dragonfly", target_os = "freebsd", target_os = "solaris", @@ -139,7 +138,6 @@ mod imp { #[cfg(any(target_os = "linux", target_os = "macos", - target_os = "bitrig", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", @@ -185,7 +183,6 @@ mod imp { #[cfg(not(any(target_os = "linux", target_os = "macos", - target_os = "bitrig", target_os = "dragonfly", target_os = "freebsd", target_os = "solaris", diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index f7d604ac4c8c..f4a1783ce890 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -99,7 +99,6 @@ impl Thread { #[cfg(any(target_os = "freebsd", target_os = "dragonfly", - target_os = "bitrig", target_os = "openbsd"))] pub fn set_name(name: &CStr) { unsafe { @@ -189,7 +188,6 @@ impl Drop for Thread { #[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))), not(target_os = "freebsd"), not(target_os = "macos"), - not(target_os = "bitrig"), not(all(target_os = "netbsd", not(target_vendor = "rumprun"))), not(target_os = "openbsd"), not(target_os = "solaris")))] @@ -205,7 +203,6 @@ pub mod guard { #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "freebsd", target_os = "macos", - target_os = "bitrig", all(target_os = "netbsd", not(target_vendor = "rumprun")), target_os = "openbsd", target_os = "solaris"))] @@ -236,16 +233,15 @@ pub mod guard { Some(stackaddr as *mut libc::c_void) } - #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] + #[cfg(target_os = "openbsd")] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut current_stack: libc::stack_t = crate::mem::zeroed(); assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(), &mut current_stack), 0); - let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE; let stackaddr = if libc::pthread_main_np() == 1 { // main thread - current_stack.ss_sp as usize - current_stack.ss_size + extra + current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE } else { // new thread current_stack.ss_sp as usize - current_stack.ss_size @@ -343,7 +339,6 @@ pub mod guard { } #[cfg(any(target_os = "macos", - target_os = "bitrig", target_os = "openbsd", target_os = "solaris"))] pub unsafe fn current() -> Option { diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs index b3c77b869956..6766099c1ece 100644 --- a/src/libstd/sys/wasm/args.rs +++ b/src/libstd/sys/wasm/args.rs @@ -37,6 +37,10 @@ impl Iterator for Args { fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } } impl ExactSizeIterator for Args { diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs index b04bb484eedb..744d7ec59d3a 100644 --- a/src/libstd/sys/windows/args.rs +++ b/src/libstd/sys/windows/args.rs @@ -181,6 +181,8 @@ impl Iterator for Args { type Item = OsString; fn next(&mut self) -> Option { self.parsed_args_list.next() } fn size_hint(&self) -> (usize, Option) { self.parsed_args_list.size_hint() } + #[inline] + fn last(mut self) -> Option { self.next_back() } } impl DoubleEndedIterator for Args { diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index cf1dc20b52fc..391f670346f2 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -37,12 +37,12 @@ use crate::sys::net::netc::IPV6_DROP_MEMBERSHIP; #[cfg(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig"))] + target_os = "haiku"))] use libc::MSG_NOSIGNAL; #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", - target_os = "haiku", target_os = "bitrig")))] + target_os = "haiku")))] const MSG_NOSIGNAL: c_int = 0x0; //////////////////////////////////////////////////////////////////////////////// diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index fce28ffd9c38..35de4f4008b6 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -443,6 +443,7 @@ impl Builder { /// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn /// [`io::Result`]: ../../std/io/type.Result.html /// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html + /// [`JoinHandle::join`]: ../../std/thread/struct.JoinHandle.html#method.join #[unstable(feature = "thread_spawn_unchecked", issue = "55132")] pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result> where F: FnOnce() -> T, F: Send + 'a, T: Send + 'a diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index af2302d24f52..a6bb47bef87e 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -6,6 +6,7 @@ pub use crate::symbol::{Ident, Symbol as Name}; pub use crate::util::parser::ExprPrecedence; use crate::ext::hygiene::{Mark, SyntaxContext}; +use crate::parse::token; use crate::print::pprust; use crate::ptr::P; use crate::source_map::{dummy_spanned, respan, Spanned}; @@ -15,7 +16,7 @@ use crate::ThinVec; use rustc_data_structures::indexed_vec::Idx; #[cfg(target_arch = "x86_64")] -use rustc_data_structures::static_assert; +use rustc_data_structures::static_assert_size; use rustc_target::spec::abi::Abi; use syntax_pos::{Span, DUMMY_SP}; @@ -71,21 +72,11 @@ pub struct Path { impl PartialEq for Path { fn eq(&self, symbol: &Symbol) -> bool { self.segments.len() == 1 && { - let name = self.segments[0].ident.name; - // Make sure these symbols are pure strings - debug_assert!(!symbol.is_gensymed()); - debug_assert!(!name.is_gensymed()); - name == *symbol + self.segments[0].ident.name == *symbol } } } -impl<'a> PartialEq<&'a str> for Path { - fn eq(&self, string: &&'a str) -> bool { - self.segments.len() == 1 && self.segments[0].ident.name == *string - } -} - impl fmt::Debug for Path { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "path({})", pprust::path_to_string(self)) @@ -969,7 +960,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_EXPR: std::mem::size_of::() == 96); +static_assert_size!(Expr, 96); impl Expr { /// Whether this expression would be valid somewhere that expects a value; for example, an `if` @@ -1350,8 +1341,19 @@ pub enum StrStyle { Raw(u16), } -/// A literal. -pub type Lit = Spanned; +/// An AST literal. +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct Lit { + /// The original literal token as written in source code. + pub token: token::Lit, + /// The original literal suffix as written in source code. + pub suffix: Option, + /// The "semantic" representation of the literal lowered from the original tokens. + /// Strings are unescaped, hexadecimal forms are eliminated, etc. + /// FIXME: Remove this and only create the semantic representation during lowering to HIR. + pub node: LitKind, + pub span: Span, +} #[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, Hash, PartialEq)] pub enum LitIntType { diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs index db821f4e5369..65ca96afab12 100644 --- a/src/libsyntax/attr/builtin.rs +++ b/src/libsyntax/attr/builtin.rs @@ -5,7 +5,7 @@ use crate::feature_gate::{Features, GatedCfg}; use crate::parse::ParseSess; use errors::{Applicability, Handler}; -use syntax_pos::{symbol::Symbol, Span}; +use syntax_pos::{symbol::Symbol, symbol::sym, Span}; use super::{mark_used, MetaItemKind}; @@ -80,13 +80,13 @@ pub enum UnwindAttr { /// Determine what `#[unwind]` attribute is present in `attrs`, if any. pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { attrs.iter().fold(None, |ia, attr| { - if attr.check_name("unwind") { + if attr.check_name(sym::unwind) { if let Some(meta) = attr.meta() { if let MetaItemKind::List(items) = meta.node { if items.len() == 1 { - if items[0].check_name("allowed") { + if items[0].check_name(sym::allowed) { return Some(UnwindAttr::Allowed); - } else if items[0].check_name("aborts") { + } else if items[0].check_name(sym::aborts) { return Some(UnwindAttr::Aborts); } } @@ -153,9 +153,9 @@ pub struct RustcDeprecation { /// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`. /// This will not perform any "sanity checks" on the form of the attributes. -pub fn contains_feature_attr(attrs: &[Attribute], feature_name: &str) -> bool { +pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool { attrs.iter().any(|item| { - item.check_name("feature") && + item.check_name(sym::feature) && item.meta_item_list().map(|list| { list.iter().any(|mi| mi.is_word() && mi.check_name(feature_name)) }).unwrap_or(false) @@ -185,12 +185,12 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, 'outer: for attr in attrs_iter { if ![ - "rustc_deprecated", - "rustc_const_unstable", - "unstable", - "stable", - "rustc_promotable", - "rustc_allow_const_fn_ptr", + sym::rustc_deprecated, + sym::rustc_const_unstable, + sym::unstable, + sym::stable, + sym::rustc_promotable, + sym::rustc_allow_const_fn_ptr, ].iter().any(|&s| attr.path == s) { continue // not a stability level } @@ -199,10 +199,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let meta = attr.meta(); - if attr.path == "rustc_promotable" { + if attr.path == sym::rustc_promotable { promotable = true; } - if attr.path == "rustc_allow_const_fn_ptr" { + if attr.path == sym::rustc_allow_const_fn_ptr { allow_const_fn_ptr = true; } // attributes with data @@ -229,10 +229,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, )+ for meta in metas { if let Some(mi) = meta.meta_item() { - match mi.name_or_empty().get() { + match mi.name_or_empty() { $( - stringify!($name) - => if !get(mi, &mut $name) { continue 'outer }, + sym::$name => if !get(mi, &mut $name) { continue 'outer }, )+ _ => { let expected = &[ $( stringify!($name) ),+ ]; @@ -259,8 +258,8 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } } - match meta.name_or_empty().get() { - "rustc_deprecated" => { + match meta.name_or_empty() { + sym::rustc_deprecated => { if rustc_depr.is_some() { span_err!(diagnostic, item_sp, E0540, "multiple rustc_deprecated attributes"); @@ -287,7 +286,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } } } - "rustc_const_unstable" => { + sym::rustc_const_unstable => { if rustc_const_unstable.is_some() { span_err!(diagnostic, item_sp, E0553, "multiple rustc_const_unstable attributes"); @@ -302,7 +301,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, continue } } - "unstable" => { + sym::unstable => { if stab.is_some() { handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels); break @@ -313,10 +312,10 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, let mut issue = None; for meta in metas { if let Some(mi) = meta.meta_item() { - match mi.name_or_empty().get() { - "feature" => if !get(mi, &mut feature) { continue 'outer }, - "reason" => if !get(mi, &mut reason) { continue 'outer }, - "issue" => if !get(mi, &mut issue) { continue 'outer }, + match mi.name_or_empty() { + sym::feature => if !get(mi, &mut feature) { continue 'outer }, + sym::reason => if !get(mi, &mut reason) { continue 'outer }, + sym::issue => if !get(mi, &mut issue) { continue 'outer }, _ => { handle_errors( sess, @@ -374,7 +373,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } } } - "stable" => { + sym::stable => { if stab.is_some() { handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels); break @@ -385,11 +384,9 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, for meta in metas { match meta { NestedMetaItem::MetaItem(mi) => { - match mi.name_or_empty().get() { - "feature" => - if !get(mi, &mut feature) { continue 'outer }, - "since" => - if !get(mi, &mut since) { continue 'outer }, + match mi.name_or_empty() { + sym::feature => if !get(mi, &mut feature) { continue 'outer }, + sym::since => if !get(mi, &mut since) { continue 'outer }, _ => { handle_errors( sess, @@ -482,7 +479,7 @@ fn find_stability_generic<'a, I>(sess: &ParseSess, } pub fn find_crate_name(attrs: &[Attribute]) -> Option { - super::first_attr_value_str_by_name(attrs, "crate_name") + super::first_attr_value_str_by_name(attrs, sym::crate_name) } /// Tests if a cfg-pattern matches the cfg set @@ -542,14 +539,14 @@ pub fn eval_condition(cfg: &ast::MetaItem, sess: &ParseSess, eval: &mut F) // The unwraps below may look dangerous, but we've already asserted // that they won't fail with the loop above. - match cfg.name_or_empty().get() { - "any" => mis.iter().any(|mi| { + match cfg.name_or_empty() { + sym::any => mis.iter().any(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), - "all" => mis.iter().all(|mi| { + sym::all => mis.iter().all(|mi| { eval_condition(mi.meta_item().unwrap(), sess, eval) }), - "not" => { + sym::not => { if mis.len() != 1 { span_err!(sess.span_diagnostic, cfg.span, E0536, "expected 1 cfg-pattern"); return false; @@ -593,7 +590,7 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, let diagnostic = &sess.span_diagnostic; 'outer: for attr in attrs_iter { - if !attr.check_name("deprecated") { + if !attr.check_name(sym::deprecated) { continue; } @@ -645,9 +642,9 @@ fn find_deprecation_generic<'a, I>(sess: &ParseSess, for meta in list { match meta { NestedMetaItem::MetaItem(mi) => { - match mi.name_or_empty().get() { - "since" => if !get(mi, &mut since) { continue 'outer }, - "note" => if !get(mi, &mut note) { continue 'outer }, + match mi.name_or_empty() { + sym::since => if !get(mi, &mut since) { continue 'outer }, + sym::note => if !get(mi, &mut note) { continue 'outer }, _ => { handle_errors( sess, @@ -721,7 +718,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { let mut acc = Vec::new(); let diagnostic = &sess.span_diagnostic; - if attr.path == "repr" { + if attr.path == sym::repr { if let Some(items) = attr.meta_item_list() { mark_used(attr); for item in items { @@ -739,11 +736,11 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { let mut recognised = false; if item.is_word() { - let hint = match item.name_or_empty().get() { - "C" => Some(ReprC), - "packed" => Some(ReprPacked(1)), - "simd" => Some(ReprSimd), - "transparent" => Some(ReprTransparent), + let hint = match item.name_or_empty() { + sym::C => Some(ReprC), + sym::packed => Some(ReprPacked(1)), + sym::simd => Some(ReprSimd), + sym::transparent => Some(ReprTransparent), name => int_type_of_word(name).map(ReprInt), }; @@ -770,14 +767,14 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { }; let mut literal_error = None; - if name == "align" { + if name == sym::align { recognised = true; match parse_alignment(&value.node) { Ok(literal) => acc.push(ReprAlign(literal)), Err(message) => literal_error = Some(message) }; } - else if name == "packed" { + else if name == sym::packed { recognised = true; match parse_alignment(&value.node) { Ok(literal) => acc.push(ReprPacked(literal)), @@ -790,7 +787,7 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { } } else { if let Some(meta_item) = item.meta_item() { - if meta_item.check_name("align") { + if meta_item.check_name(sym::align) { if let MetaItemKind::NameValue(ref value) = meta_item.node { recognised = true; let mut err = struct_span_err!(diagnostic, item.span(), E0693, @@ -830,22 +827,22 @@ pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec { acc } -fn int_type_of_word(s: &str) -> Option { +fn int_type_of_word(s: Symbol) -> Option { use IntType::*; match s { - "i8" => Some(SignedInt(ast::IntTy::I8)), - "u8" => Some(UnsignedInt(ast::UintTy::U8)), - "i16" => Some(SignedInt(ast::IntTy::I16)), - "u16" => Some(UnsignedInt(ast::UintTy::U16)), - "i32" => Some(SignedInt(ast::IntTy::I32)), - "u32" => Some(UnsignedInt(ast::UintTy::U32)), - "i64" => Some(SignedInt(ast::IntTy::I64)), - "u64" => Some(UnsignedInt(ast::UintTy::U64)), - "i128" => Some(SignedInt(ast::IntTy::I128)), - "u128" => Some(UnsignedInt(ast::UintTy::U128)), - "isize" => Some(SignedInt(ast::IntTy::Isize)), - "usize" => Some(UnsignedInt(ast::UintTy::Usize)), + sym::i8 => Some(SignedInt(ast::IntTy::I8)), + sym::u8 => Some(UnsignedInt(ast::UintTy::U8)), + sym::i16 => Some(SignedInt(ast::IntTy::I16)), + sym::u16 => Some(UnsignedInt(ast::UintTy::U16)), + sym::i32 => Some(SignedInt(ast::IntTy::I32)), + sym::u32 => Some(UnsignedInt(ast::UintTy::U32)), + sym::i64 => Some(SignedInt(ast::IntTy::I64)), + sym::u64 => Some(UnsignedInt(ast::UintTy::U64)), + sym::i128 => Some(SignedInt(ast::IntTy::I128)), + sym::u128 => Some(UnsignedInt(ast::UintTy::U128)), + sym::isize => Some(SignedInt(ast::IntTy::Isize)), + sym::usize => Some(UnsignedInt(ast::UintTy::Usize)), _ => None } } diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index e00f91e39528..592b40df1764 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -14,15 +14,15 @@ pub use StabilityLevel::*; use crate::ast; use crate::ast::{AttrId, Attribute, AttrStyle, Name, Ident, Path, PathSegment}; use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem}; -use crate::ast::{Lit, LitKind, Expr, ExprKind, Item, Local, Stmt, StmtKind, GenericParam}; +use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam}; use crate::mut_visit::visit_clobber; -use crate::source_map::{BytePos, Spanned, respan, dummy_spanned}; +use crate::source_map::{BytePos, Spanned, dummy_spanned}; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::parser::Parser; use crate::parse::{self, ParseSess, PResult}; use crate::parse::token::{self, Token}; use crate::ptr::P; -use crate::symbol::{keywords, LocalInternedString, Symbol}; +use crate::symbol::{keywords, Symbol, sym}; use crate::ThinVec; use crate::tokenstream::{TokenStream, TokenTree, DelimSpan}; use crate::GLOBALS; @@ -81,10 +81,7 @@ impl NestedMetaItem { } /// Returns `true` if this list item is a MetaItem with a name of `name`. - pub fn check_name(&self, name: T) -> bool - where - Path: PartialEq, - { + pub fn check_name(&self, name: Symbol) -> bool { self.meta_item().map_or(false, |meta_item| meta_item.check_name(name)) } @@ -92,8 +89,8 @@ impl NestedMetaItem { pub fn ident(&self) -> Option { self.meta_item().and_then(|meta_item| meta_item.ident()) } - pub fn name_or_empty(&self) -> LocalInternedString { - self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str() + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or(keywords::Invalid.ident()).name } /// Gets the string value if self is a MetaItem and the MetaItem is a @@ -154,10 +151,7 @@ impl Attribute { /// attribute is marked as used. /// /// To check the attribute name without marking it used, use the `path` field directly. - pub fn check_name(&self, name: T) -> bool - where - Path: PartialEq, - { + pub fn check_name(&self, name: Symbol) -> bool { let matches = self.path == name; if matches { mark_used(self); @@ -173,8 +167,8 @@ impl Attribute { None } } - pub fn name_or_empty(&self) -> LocalInternedString { - self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str() + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or(keywords::Invalid.ident()).name } pub fn value_str(&self) -> Option { @@ -211,8 +205,8 @@ impl MetaItem { None } } - pub fn name_or_empty(&self) -> LocalInternedString { - self.ident().unwrap_or(keywords::Invalid.ident()).name.as_str() + pub fn name_or_empty(&self) -> Symbol { + self.ident().unwrap_or(keywords::Invalid.ident()).name } // #[attribute(name = "value")] @@ -250,10 +244,7 @@ impl MetaItem { } } - pub fn check_name(&self, name: T) -> bool - where - Path: PartialEq, - { + pub fn check_name(&self, name: Symbol) -> bool { self.path == name } @@ -332,7 +323,7 @@ impl Attribute { if self.is_sugared_doc { let comment = self.value_str().unwrap(); let meta = mk_name_value_item_str( - Ident::from_str("doc"), + Ident::with_empty_ctxt(sym::doc), dummy_spanned(Symbol::intern(&strip_doc_comment_decoration(&comment.as_str())))); let mut attr = if self.style == ast::AttrStyle::Outer { mk_attr_outer(self.span, self.id, meta) @@ -350,12 +341,13 @@ impl Attribute { /* Constructors */ pub fn mk_name_value_item_str(ident: Ident, value: Spanned) -> MetaItem { - let value = respan(value.span, LitKind::Str(value.node, ast::StrStyle::Cooked)); - mk_name_value_item(ident.span.to(value.span), ident, value) + let lit_kind = LitKind::Str(value.node, ast::StrStyle::Cooked); + mk_name_value_item(ident.span.to(value.span), ident, lit_kind, value.span) } -pub fn mk_name_value_item(span: Span, ident: Ident, value: ast::Lit) -> MetaItem { - MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(value) } +pub fn mk_name_value_item(span: Span, ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem { + let lit = Lit::from_lit_kind(lit_kind, lit_span); + MetaItem { path: Path::from_ident(ident), span, node: MetaItemKind::NameValue(lit) } } pub fn mk_list_item(span: Span, ident: Ident, items: Vec) -> MetaItem { @@ -417,39 +409,40 @@ pub fn mk_spanned_attr_outer(sp: Span, id: AttrId, item: MetaItem) -> Attribute pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute { let style = doc_comment_style(&text.as_str()); - let lit = respan(span, LitKind::Str(text, ast::StrStyle::Cooked)); + let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked); + let lit = Lit::from_lit_kind(lit_kind, span); Attribute { id, style, - path: Path::from_ident(Ident::from_str("doc").with_span_pos(span)), + path: Path::from_ident(Ident::with_empty_ctxt(sym::doc).with_span_pos(span)), tokens: MetaItemKind::NameValue(lit).tokens(span), is_sugared_doc: true, span, } } -pub fn list_contains_name(items: &[NestedMetaItem], name: &str) -> bool { +pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { items.iter().any(|item| { item.check_name(name) }) } -pub fn contains_name(attrs: &[Attribute], name: &str) -> bool { +pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool { attrs.iter().any(|item| { item.check_name(name) }) } -pub fn find_by_name<'a>(attrs: &'a [Attribute], name: &str) -> Option<&'a Attribute> { +pub fn find_by_name<'a>(attrs: &'a [Attribute], name: Symbol) -> Option<&'a Attribute> { attrs.iter().find(|attr| attr.check_name(name)) } -pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: &'a str) +pub fn filter_by_name<'a>(attrs: &'a [Attribute], name: Symbol) -> impl Iterator { attrs.iter().filter(move |attr| attr.check_name(name)) } -pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option { +pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option { attrs.iter() .find(|at| at.check_name(name)) .and_then(|at| at.value_str()) @@ -561,8 +554,7 @@ impl MetaItemKind { Some(TokenTree::Token(_, token::Eq)) => { tokens.next(); return if let Some(TokenTree::Token(span, token)) = tokens.next() { - LitKind::from_token(token) - .map(|lit| MetaItemKind::NameValue(Spanned { node: lit, span: span })) + Lit::from_token(&token, span, None).map(MetaItemKind::NameValue) } else { None }; @@ -607,9 +599,9 @@ impl NestedMetaItem { where I: Iterator, { if let Some(TokenTree::Token(span, token)) = tokens.peek().cloned() { - if let Some(node) = LitKind::from_token(token) { + if let Some(lit) = Lit::from_token(&token, span, None) { tokens.next(); - return Some(NestedMetaItem::Literal(respan(span, node))); + return Some(NestedMetaItem::Literal(lit)); } } @@ -617,81 +609,6 @@ impl NestedMetaItem { } } -impl Lit { - crate fn tokens(&self) -> TokenStream { - TokenTree::Token(self.span, self.node.token()).into() - } -} - -impl LitKind { - fn token(&self) -> Token { - use std::ascii; - - match *self { - LitKind::Str(string, ast::StrStyle::Cooked) => { - let escaped = string.as_str().escape_default().to_string(); - Token::Literal(token::Lit::Str_(Symbol::intern(&escaped)), None) - } - LitKind::Str(string, ast::StrStyle::Raw(n)) => { - Token::Literal(token::Lit::StrRaw(string, n), None) - } - LitKind::ByteStr(ref bytes) => { - let string = bytes.iter().cloned().flat_map(ascii::escape_default) - .map(Into::::into).collect::(); - Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None) - } - LitKind::Byte(byte) => { - let string: String = ascii::escape_default(byte).map(Into::::into).collect(); - Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None) - } - LitKind::Char(ch) => { - let string: String = ch.escape_default().map(Into::::into).collect(); - Token::Literal(token::Lit::Char(Symbol::intern(&string)), None) - } - LitKind::Int(n, ty) => { - let suffix = match ty { - ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())), - ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())), - ast::LitIntType::Unsuffixed => None, - }; - Token::Literal(token::Lit::Integer(Symbol::intern(&n.to_string())), suffix) - } - LitKind::Float(symbol, ty) => { - Token::Literal(token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string()))) - } - LitKind::FloatUnsuffixed(symbol) => Token::Literal(token::Lit::Float(symbol), None), - LitKind::Bool(value) => Token::Ident(Ident::with_empty_ctxt(Symbol::intern(if value { - "true" - } else { - "false" - })), false), - LitKind::Err(val) => Token::Literal(token::Lit::Err(val), None), - } - } - - fn from_token(token: Token) -> Option { - match token { - Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)), - Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)), - Token::Interpolated(nt) => match *nt { - token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { - ExprKind::Lit(ref lit) => Some(lit.node.clone()), - _ => None, - }, - _ => None, - }, - Token::Literal(lit, suf) => { - let (suffix_illegal, result) = parse::lit_token(lit, suf, None); - if suffix_illegal && suf.is_some() { - return None; - } - result - } - _ => None, - } - } -} - pub trait HasAttrs: Sized { fn attrs(&self) -> &[ast::Attribute]; fn visit_attrs)>(&mut self, f: F); diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 18173628a260..c82936afa3d9 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -12,6 +12,7 @@ use crate::edition::Edition; use crate::mut_visit::*; use crate::parse::{token, ParseSess}; use crate::ptr::P; +use crate::symbol::sym; use crate::util::map_in_place::MapInPlace; use errors::Applicability; @@ -90,7 +91,7 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Vec { - if !attr.check_name("cfg_attr") { + if !attr.check_name(sym::cfg_attr) { return vec![attr]; } @@ -205,7 +206,7 @@ impl<'a> StripUnconfigured<'a> { pub fn maybe_emit_expr_attr_err(&self, attr: &ast::Attribute) { if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) { let mut err = feature_err(self.sess, - "stmt_expr_attributes", + sym::stmt_expr_attributes, attr.span, GateIssue::Language, EXPLAIN_STMT_ATTR_SYNTAX); @@ -285,9 +286,9 @@ impl<'a> StripUnconfigured<'a> { /// See issue #51279. pub fn disallow_cfg_on_generic_param(&mut self, param: &ast::GenericParam) { for attr in param.attrs() { - let offending_attr = if attr.check_name("cfg") { + let offending_attr = if attr.check_name(sym::cfg) { "cfg" - } else if attr.check_name("cfg_attr") { + } else if attr.check_name(sym::cfg_attr) { "cfg_attr" } else { continue; @@ -350,5 +351,5 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { } fn is_cfg(attr: &ast::Attribute) -> bool { - attr.check_name("cfg") + attr.check_name(sym::cfg) } diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index 21024eb41ef5..c988dc61bec4 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -7,7 +7,7 @@ use crate::ext::base::{ExtCtxt, MacEager, MacResult}; use crate::ext::build::AstBuilder; use crate::parse::token; use crate::ptr::P; -use crate::symbol::{keywords, Symbol}; +use crate::symbol::keywords; use crate::tokenstream::{TokenTree}; use smallvec::smallvec; @@ -121,13 +121,13 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt<'_>, let span = span.apply_mark(ecx.current_expansion.mark); - let sym = Ident::new(Symbol::gensym(&format!("__register_diagnostic_{}", code)), span); + let name = Ident::from_str_and_span(&format!("__register_diagnostic_{}", code), span).gensym(); MacEager::items(smallvec![ ecx.item_mod( span, span, - sym, + name, vec![], vec![], ) diff --git a/src/libsyntax/entry.rs b/src/libsyntax/entry.rs index 09e26e29d86a..0b6cf30bd27d 100644 --- a/src/libsyntax/entry.rs +++ b/src/libsyntax/entry.rs @@ -1,5 +1,6 @@ use crate::attr; use crate::ast::{Item, ItemKind}; +use crate::symbol::sym; pub enum EntryPointType { None, @@ -14,11 +15,11 @@ pub enum EntryPointType { pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType { match item.node { ItemKind::Fn(..) => { - if attr::contains_name(&item.attrs, "start") { + if attr::contains_name(&item.attrs, sym::start) { EntryPointType::Start - } else if attr::contains_name(&item.attrs, "main") { + } else if attr::contains_name(&item.attrs, sym::main) { EntryPointType::MainAttr - } else if item.ident.name == "main" { + } else if item.ident.name == sym::main { if depth == 1 { // This is a top-level function so can be 'main' EntryPointType::MainNamed diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index cc19acb61adc..0a88d2f8824d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,7 +10,7 @@ use crate::mut_visit::{self, MutVisitor}; use crate::parse::{self, parser, DirectoryOwnership}; use crate::parse::token; use crate::ptr::P; -use crate::symbol::{keywords, Ident, Symbol}; +use crate::symbol::{keywords, Ident, Symbol, sym}; use crate::ThinVec; use crate::tokenstream::{self, TokenStream}; @@ -871,7 +871,7 @@ impl<'a> ExtCtxt<'a> { let mut last_macro = None; loop { if ctxt.outer().expn_info().map_or(None, |info| { - if info.format.name() == "include" { + if info.format.name() == sym::include { // Stop going up the backtrace once include! is encountered return None; } diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 40dd187ed28a..d24106f697e1 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -697,8 +697,9 @@ impl<'a> AstBuilder for ExtCtxt<'a> { self.expr_struct(span, self.path_ident(span, id), fields) } - fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P { - self.expr(sp, ast::ExprKind::Lit(respan(sp, lit))) + fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P { + let lit = ast::Lit::from_lit_kind(lit_kind, span); + self.expr(span, ast::ExprKind::Lit(lit)) } fn expr_usize(&self, span: Span, i: usize) -> P { self.expr_lit(span, ast::LitKind::Int(i as u128, @@ -1164,10 +1165,10 @@ impl<'a> AstBuilder for ExtCtxt<'a> { attr::mk_list_item(sp, Ident::with_empty_ctxt(name).with_span_pos(sp), mis) } - fn meta_name_value(&self, sp: Span, name: ast::Name, value: ast::LitKind) + fn meta_name_value(&self, span: Span, name: ast::Name, lit_kind: ast::LitKind) -> ast::MetaItem { - attr::mk_name_value_item(sp, Ident::with_empty_ctxt(name).with_span_pos(sp), - respan(sp, value)) + attr::mk_name_value_item(span, Ident::with_empty_ctxt(name).with_span_pos(span), + lit_kind, span) } fn item_use(&self, sp: Span, diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 6df369133d01..a24e09f127ea 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -4,7 +4,7 @@ use crate::source_map::{hygiene, ExpnInfo, ExpnFormat}; use crate::ext::base::ExtCtxt; use crate::ext::build::AstBuilder; use crate::parse::parser::PathStyle; -use crate::symbol::Symbol; +use crate::symbol::{Symbol, sym}; use syntax_pos::Span; @@ -13,7 +13,7 @@ use rustc_data_structures::fx::FxHashSet; pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { let mut result = Vec::new(); attrs.retain(|attr| { - if attr.path != "derive" { + if attr.path != sym::derive { return true; } if !attr.is_meta_item_list() { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 82358679c0e8..019ebc8566ff 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -14,7 +14,7 @@ use crate::parse::token::{self, Token}; use crate::parse::parser::Parser; use crate::ptr::P; use crate::symbol::Symbol; -use crate::symbol::keywords; +use crate::symbol::{keywords, sym}; use crate::tokenstream::{TokenStream, TokenTree}; use crate::visit::{self, Visitor}; use crate::util::map_in_place::MapInPlace; @@ -356,7 +356,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), "derive") + let attr = attr::find_by_name(item.attrs(), sym::derive) .expect("`derive` attribute should exist"); let span = attr.span; let mut err = self.cx.mut_span_err(span, @@ -376,7 +376,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != "derive")); + item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); let mut item_with_markers = item.clone(); add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers); let derives = derives.entry(invoc.expansion_data.mark).or_default(); @@ -510,7 +510,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if invoc.fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern_enabled() { if let SyntaxExtension::NonMacroAttr { .. } = *ext {} else { - emit_feature_err(&self.cx.parse_sess, "macros_in_extern", + emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern, invoc.span(), GateIssue::Language, "macro invocations in `extern {}` blocks are experimental"); } @@ -636,7 +636,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Item(ref item) => { match item.node { ItemKind::Mod(_) if self.cx.ecfg.proc_macro_hygiene() => return, - ItemKind::Mod(_) => ("modules", "proc_macro_hygiene"), + ItemKind::Mod(_) => ("modules", sym::proc_macro_hygiene), _ => return, } } @@ -645,8 +645,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::ForeignItem(_) => return, Annotatable::Stmt(_) | Annotatable::Expr(_) if self.cx.ecfg.proc_macro_hygiene() => return, - Annotatable::Stmt(_) => ("statements", "proc_macro_hygiene"), - Annotatable::Expr(_) => ("expressions", "proc_macro_hygiene"), + Annotatable::Stmt(_) => ("statements", sym::proc_macro_hygiene), + Annotatable::Expr(_) => ("expressions", sym::proc_macro_hygiene), }; emit_feature_err( self.cx.parse_sess, @@ -681,7 +681,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { if let ast::ItemKind::MacroDef(_) = i.node { emit_feature_err( self.parse_sess, - "proc_macro_hygiene", + sym::proc_macro_hygiene, self.span, GateIssue::Language, "procedural macros cannot expand to macro definitions", @@ -724,13 +724,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // don't stability-check macros in the same crate // (the only time this is null is for syntax extensions registered as macros) if def_site_span.map_or(false, |def_span| !crate_span.contains(def_span)) - && !span.allows_unstable(&feature.as_str()) + && !span.allows_unstable(feature) && this.cx.ecfg.features.map_or(true, |feats| { // macro features will count as lib features !feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature) }) { let explain = format!("macro {}! is unstable", path); - emit_feature_err(this.cx.parse_sess, &*feature.as_str(), span, + emit_feature_err(this.cx.parse_sess, feature, span, GateIssue::Library(Some(issue)), &explain); this.cx.trace_macros_diag(); } @@ -885,7 +885,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } emit_feature_err( self.cx.parse_sess, - "proc_macro_hygiene", + sym::proc_macro_hygiene, span, GateIssue::Language, &format!("procedural macros cannot be expanded to {}", kind), @@ -1109,7 +1109,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { -> Option { let attr = attrs.iter() .position(|a| { - if a.path == "derive" { + if a.path == sym::derive { *after_derive = true; } !attr::is_known(a) && !is_builtin_attr(a) @@ -1117,8 +1117,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { .map(|i| attrs.remove(i)); if let Some(attr) = &attr { if !self.cx.ecfg.enable_custom_inner_attributes() && - attr.style == ast::AttrStyle::Inner && attr.path != "test" { - emit_feature_err(&self.cx.parse_sess, "custom_inner_attributes", + attr.style == ast::AttrStyle::Inner && attr.path != sym::test { + emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes, attr.span, GateIssue::Language, "non-builtin inner attributes are unstable"); } @@ -1167,7 +1167,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.check_attribute_inner(attr, features); // macros are expanded before any lint passes so this warning has to be hardcoded - if attr.path == "derive" { + if attr.path == sym::derive { self.cx.struct_span_warn(attr.span, "`#[derive]` does nothing on macro invocations") .note("this may become a hard error in a future release") .emit(); @@ -1352,7 +1352,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let inline_module = item.span.contains(inner) || inner.is_dummy(); if inline_module { - if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") { + if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, sym::path) { self.cx.current_expansion.directory_ownership = DirectoryOwnership::Owned { relative: None }; module.directory.push(&*path.as_str()); @@ -1485,19 +1485,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { fn visit_attribute(&mut self, at: &mut ast::Attribute) { // turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename", // contents="file contents")]` attributes - if !at.check_name("doc") { + if !at.check_name(sym::doc) { return noop_visit_attribute(at, self); } if let Some(list) = at.meta_item_list() { - if !list.iter().any(|it| it.check_name("include")) { + if !list.iter().any(|it| it.check_name(sym::include)) { return noop_visit_attribute(at, self); } let mut items = vec![]; for mut it in list { - if !it.check_name("include") { + if !it.check_name(sym::include) { items.push({ noop_visit_meta_list_item(&mut it, self); it }); continue; } @@ -1522,19 +1522,19 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { let include_info = vec![ ast::NestedMetaItem::MetaItem( attr::mk_name_value_item_str( - Ident::from_str("file"), + Ident::with_empty_ctxt(sym::file), dummy_spanned(file), ), ), ast::NestedMetaItem::MetaItem( attr::mk_name_value_item_str( - Ident::from_str("contents"), + Ident::with_empty_ctxt(sym::contents), dummy_spanned(src_interned), ), ), ]; - let include_ident = Ident::from_str("include"); + let include_ident = Ident::with_empty_ctxt(sym::include); let item = attr::mk_list_item(DUMMY_SP, include_ident, include_info); items.push(ast::NestedMetaItem::MetaItem(item)); } @@ -1600,7 +1600,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } } - let meta = attr::mk_list_item(DUMMY_SP, Ident::from_str("doc"), items); + let meta = attr::mk_list_item(DUMMY_SP, Ident::with_empty_ctxt(sym::doc), items); match at.style { ast::AttrStyle::Inner => *at = attr::mk_spanned_attr_inner(at.span, at.id, meta), ast::AttrStyle::Outer => *at = attr::mk_spanned_attr_outer(at.span, at.id, meta), diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 549de1628eb5..e1cb90d9e71d 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -4,7 +4,7 @@ use crate::ext::build::AstBuilder; use crate::parse::{self, token, DirectoryOwnership}; use crate::print::pprust; use crate::ptr::P; -use crate::symbol::Symbol; +use crate::symbol::{Symbol, sym}; use crate::tokenstream; use smallvec::SmallVec; @@ -44,7 +44,7 @@ pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTr /* __rust_unstable_column!(): expands to the current column number */ pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { - if sp.allows_unstable("__rust_unstable_column") { + if sp.allows_unstable(sym::__rust_unstable_column) { expand_column(cx, sp, tts) } else { cx.span_fatal(sp, "the __rust_unstable_column macro is unstable"); diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index a53cc2fe6617..672b7b428552 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -13,7 +13,7 @@ use crate::parse::{Directory, ParseSess}; use crate::parse::parser::Parser; use crate::parse::token::{self, NtTT}; use crate::parse::token::Token::*; -use crate::symbol::Symbol; +use crate::symbol::{Symbol, keywords, sym}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree}; use errors::FatalError; @@ -252,8 +252,8 @@ pub fn compile( def: &ast::Item, edition: Edition ) -> SyntaxExtension { - let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs")); - let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs")); + let lhs_nm = ast::Ident::from_str("lhs").gensym(); + let rhs_nm = ast::Ident::from_str("rhs").gensym(); // Parse the macro_rules! invocation let body = match def.node { @@ -376,7 +376,7 @@ pub fn compile( }); if body.legacy { - let allow_internal_unstable = attr::find_by_name(&def.attrs, "allow_internal_unstable") + let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable) .map(|attr| attr .meta_item_list() .map(|list| list.iter() @@ -399,11 +399,11 @@ pub fn compile( vec![Symbol::intern("allow_internal_unstable_backcompat_hack")].into() }) ); - let allow_internal_unsafe = attr::contains_name(&def.attrs, "allow_internal_unsafe"); + let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe); let mut local_inner_macros = false; - if let Some(macro_export) = attr::find_by_name(&def.attrs, "macro_export") { + if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) { if let Some(l) = macro_export.meta_item_list() { - local_inner_macros = attr::list_contains_name(&l, "local_inner_macros"); + local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros); } } @@ -426,7 +426,7 @@ pub fn compile( edition, } } else { - let is_transparent = attr::contains_name(&def.attrs, "rustc_transparent_macro"); + let is_transparent = attr::contains_name(&def.attrs, sym::rustc_transparent_macro); SyntaxExtension::DeclMacro { expander, @@ -467,7 +467,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool { TokenTree::Sequence(span, ref seq) => { if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| { match *seq_tt { - TokenTree::MetaVarDecl(_, _, id) => id.name == "vis", + TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis, TokenTree::Sequence(_, ref sub_seq) => sub_seq.op == quoted::KleeneOp::ZeroOrMore || sub_seq.op == quoted::KleeneOp::ZeroOrOne, @@ -1046,7 +1046,8 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { match *tok { TokenTree::Token(_, ref tok) => match *tok { FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes, - Ident(i, false) if i.name == "if" || i.name == "in" => IsInFollow::Yes, + Ident(i, false) if i.name == keywords::If.name() || + i.name == keywords::In.name() => IsInFollow::Yes, _ => IsInFollow::No(tokens), }, _ => IsInFollow::No(tokens), @@ -1063,10 +1064,12 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { OpenDelim(token::DelimToken::Bracket) | Comma | FatArrow | Colon | Eq | Gt | BinOp(token::Shr) | Semi | BinOp(token::Or) => IsInFollow::Yes, - Ident(i, false) if i.name == "as" || i.name == "where" => IsInFollow::Yes, + Ident(i, false) if i.name == keywords::As.name() || + i.name == keywords::Where.name() => IsInFollow::Yes, _ => IsInFollow::No(tokens), }, - TokenTree::MetaVarDecl(_, _, frag) if frag.name == "block" => IsInFollow::Yes, + TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block => + IsInFollow::Yes, _ => IsInFollow::No(tokens), } }, @@ -1089,16 +1092,18 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow { match *tok { TokenTree::Token(_, ref tok) => match *tok { Comma => IsInFollow::Yes, - Ident(i, is_raw) if is_raw || i.name != "priv" => IsInFollow::Yes, + Ident(i, is_raw) if is_raw || i.name != keywords::Priv.name() => + IsInFollow::Yes, ref tok => if tok.can_begin_type() { IsInFollow::Yes } else { IsInFollow::No(tokens) } }, - TokenTree::MetaVarDecl(_, _, frag) if frag.name == "ident" - || frag.name == "ty" - || frag.name == "path" => IsInFollow::Yes, + TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::ident + || frag.name == sym::ty + || frag.name == sym::path => + IsInFollow::Yes, _ => IsInFollow::No(tokens), } }, diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 0cefcf1ce034..e3586c1854c1 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -170,10 +170,9 @@ pub fn transcribe( } LockstepIterSize::Contradiction(ref msg) => { - // FIXME: this should be impossible. I (mark-i-m) believe it would - // represent a bug in the macro_parser. - // FIXME #2887 blame macro invoker instead - cx.span_fatal(seq.span(), &msg[..]); + // This should never happen because the macro parser should generate + // properly-sized matches for all meta-vars. + cx.span_bug(seq.span(), &msg[..]); } LockstepIterSize::Constraint(len, _) => { @@ -188,14 +187,13 @@ pub fn transcribe( // Is the repetition empty? if len == 0 { if seq.op == quoted::KleeneOp::OneOrMore { - // FIXME: this should be impossible because we check for this in - // macro_parser.rs - // FIXME #2887 blame invoker - cx.span_fatal(sp.entire(), "this must repeat at least once"); + // This should be impossible because the macro parser would not + // match the given macro arm. + cx.span_bug(sp.entire(), "this must repeat at least once"); } } else { // 0 is the initial counter (we have done 0 repretitions so far). `len` - // is the total number of reptitions we should generate. + // is the total number of reptitions we should generate. repeats.push((0, len)); // The first time we encounter the sequence we push it to the stack. It diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index c3bad3aba184..5b1a9bb739ff 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -22,13 +22,13 @@ use crate::source_map::Spanned; use crate::edition::{ALL_EDITIONS, Edition}; use crate::visit::{self, FnKind, Visitor}; use crate::parse::{token, ParseSess}; -use crate::symbol::Symbol; +use crate::symbol::{Symbol, keywords, sym}; use crate::tokenstream::TokenTree; use errors::{DiagnosticBuilder, Handler}; use rustc_data_structures::fx::FxHashMap; use rustc_target::spec::abi::Abi; -use syntax_pos::{Span, DUMMY_SP, symbols}; +use syntax_pos::{Span, DUMMY_SP}; use log::debug; use lazy_static::lazy_static; @@ -48,8 +48,8 @@ macro_rules! declare_features { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. const ACTIVE_FEATURES: - &[(&str, &str, Option, Option, fn(&mut Features, Span))] = - &[$((stringify!($feature), $ver, $issue, $edition, set!($feature))),+]; + &[(Symbol, &str, Option, Option, fn(&mut Features, Span))] = + &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+]; /// A set of features to be used by later passes. #[derive(Clone)] @@ -80,22 +80,22 @@ macro_rules! declare_features { ($((removed, $feature: ident, $ver: expr, $issue: expr, None, $reason: expr),)+) => { /// Represents unstable features which have since been removed (it was once Active) - const REMOVED_FEATURES: &[(&str, &str, Option, Option<&str>)] = &[ - $((stringify!($feature), $ver, $issue, $reason)),+ + const REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, $reason)),+ ]; }; ($((stable_removed, $feature: ident, $ver: expr, $issue: expr, None),)+) => { /// Represents stable features which have since been removed (it was once Accepted) - const STABLE_REMOVED_FEATURES: &[(&str, &str, Option, Option<&str>)] = &[ - $((stringify!($feature), $ver, $issue, None)),+ + const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, None)),+ ]; }; ($((accepted, $feature: ident, $ver: expr, $issue: expr, None),)+) => { /// Those language feature has since been Accepted (it was once Active) - const ACCEPTED_FEATURES: &[(&str, &str, Option, Option<&str>)] = &[ - $((stringify!($feature), $ver, $issue, None)),+ + const ACCEPTED_FEATURES: &[(Symbol, &str, Option, Option<&str>)] = &[ + $((sym::$feature, $ver, $issue, None)),+ ]; } } @@ -562,9 +562,10 @@ declare_features! ( // Some features are known to be incomplete and using them is likely to have // unanticipated results, such as compiler crashes. We warn the user about these // to alert them. -const INCOMPLETE_FEATURES: &[&str] = &[ - "generic_associated_types", - "const_generics" +const INCOMPLETE_FEATURES: &[Symbol] = &[ + sym::impl_trait_in_bindings, + sym::generic_associated_types, + sym::const_generics ]; declare_features! ( @@ -860,7 +861,7 @@ pub enum AttributeType { pub enum AttributeGate { /// Is gated by a given feature gate, reason /// and function to check if enabled - Gated(Stability, &'static str, &'static str, fn(&Features) -> bool), + Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), /// Ungated attribute, can be used on all release channels Ungated, @@ -962,232 +963,232 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Normal attributes ( - symbols::warn, + sym::warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated ), ( - symbols::allow, + sym::allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated ), ( - symbols::forbid, + sym::forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated ), ( - symbols::deny, + sym::deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated ), - (symbols::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), - (symbols::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), - (symbols::plugin_registrar, Normal, template!(Word), Ungated), + (sym::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated), + (sym::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated), + (sym::plugin_registrar, Normal, template!(Word), Ungated), - (symbols::cfg, Normal, template!(List: "predicate"), Ungated), - (symbols::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), - (symbols::main, Normal, template!(Word), Ungated), - (symbols::start, Normal, template!(Word), Ungated), - (symbols::repr, Normal, template!(List: "C, packed, ..."), Ungated), - (symbols::path, Normal, template!(NameValueStr: "file"), Ungated), - (symbols::automatically_derived, Normal, template!(Word), Ungated), - (symbols::no_mangle, Normal, template!(Word), Ungated), - (symbols::no_link, Normal, template!(Word), Ungated), - (symbols::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), + (sym::cfg, Normal, template!(List: "predicate"), Ungated), + (sym::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated), + (sym::main, Normal, template!(Word), Ungated), + (sym::start, Normal, template!(Word), Ungated), + (sym::repr, Normal, template!(List: "C, packed, ..."), Ungated), + (sym::path, Normal, template!(NameValueStr: "file"), Ungated), + (sym::automatically_derived, Normal, template!(Word), Ungated), + (sym::no_mangle, Whitelisted, template!(Word), Ungated), + (sym::no_link, Normal, template!(Word), Ungated), + (sym::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated), ( - symbols::should_panic, + sym::should_panic, Normal, template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), Ungated ), - (symbols::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), - (symbols::no_implicit_prelude, Normal, template!(Word), Ungated), - (symbols::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), - (symbols::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, - "link_args", + (sym::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated), + (sym::no_implicit_prelude, Normal, template!(Word), Ungated), + (sym::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated), + (sym::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable, + sym::link_args, "the `link_args` attribute is experimental and not \ portable across platforms, it is recommended to \ use `#[link(name = \"foo\")] instead", cfg_fn!(link_args))), - (symbols::macro_escape, Normal, template!(Word), Ungated), + (sym::macro_escape, Normal, template!(Word), Ungated), // RFC #1445. - (symbols::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, - "structural_match", + (sym::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::structural_match, "the semantics of constant patterns is \ not yet settled", cfg_fn!(structural_match))), // RFC #2008 - (symbols::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, - "non_exhaustive", + (sym::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::non_exhaustive, "non exhaustive is an experimental feature", cfg_fn!(non_exhaustive))), // RFC #1268 - (symbols::marker, Normal, template!(Word), Gated(Stability::Unstable, - "marker_trait_attr", + (sym::marker, Normal, template!(Word), Gated(Stability::Unstable, + sym::marker_trait_attr, "marker traits is an experimental feature", cfg_fn!(marker_trait_attr))), - (symbols::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, - "plugin", + (sym::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable, + sym::plugin, "compiler plugins are experimental \ and possibly buggy", cfg_fn!(plugin))), - (symbols::no_std, CrateLevel, template!(Word), Ungated), - (symbols::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, - "no_core", + (sym::no_std, CrateLevel, template!(Word), Ungated), + (sym::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable, + sym::no_core, "no_core is experimental", cfg_fn!(no_core))), - (symbols::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, - "lang_items", + (sym::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable, + sym::lang_items, "language items are subject to change", cfg_fn!(lang_items))), - (symbols::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), + (sym::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."), Gated(Stability::Unstable, - "linkage", + sym::linkage, "the `linkage` attribute is experimental \ and not portable across platforms", cfg_fn!(linkage))), - (symbols::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, - "thread_local", + (sym::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::thread_local, "`#[thread_local]` is an experimental feature, and does \ not currently handle destructors", cfg_fn!(thread_local))), - (symbols::rustc_on_unimplemented, Whitelisted, template!(List: + (sym::rustc_on_unimplemented, Whitelisted, template!(List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, NameValueStr: "message"), Gated(Stability::Unstable, - "on_unimplemented", + sym::on_unimplemented, "the `#[rustc_on_unimplemented]` attribute \ is an experimental feature", cfg_fn!(on_unimplemented))), - (symbols::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), + (sym::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#), Gated(Stability::Unstable, - "rustc_const_unstable", + sym::rustc_const_unstable, "the `#[rustc_const_unstable]` attribute \ is an internal feature", cfg_fn!(rustc_const_unstable))), - (symbols::global_allocator, Normal, template!(Word), Ungated), - (symbols::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, - "allocator_internals", + (sym::global_allocator, Normal, template!(Word), Ungated), + (sym::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::allocator_internals, "the `#[default_lib_allocator]` \ attribute is an experimental feature", cfg_fn!(allocator_internals))), - (symbols::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, - "allocator_internals", + (sym::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable, + sym::allocator_internals, "the `#[needs_allocator]` \ attribute is an experimental \ feature", cfg_fn!(allocator_internals))), - (symbols::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - "panic_runtime", + (sym::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::panic_runtime, "the `#[panic_runtime]` attribute is \ an experimental feature", cfg_fn!(panic_runtime))), - (symbols::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - "needs_panic_runtime", + (sym::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::needs_panic_runtime, "the `#[needs_panic_runtime]` \ attribute is an experimental \ feature", cfg_fn!(needs_panic_runtime))), - (symbols::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_outlives]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_variance]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_layout, Normal, template!(List: "field1, field2, ..."), + (sym::rustc_layout, Normal, template!(List: "field1, field2, ..."), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_layout]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), + (sym::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_layout_scalar_valid_range_start]` attribute \ is just used to enable niche optimizations in libcore \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), + (sym::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_layout_scalar_valid_range_end]` attribute \ is just used to enable niche optimizations in libcore \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_regions]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_error]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), + (sym::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), + (sym::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_if_this_changed]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", + (sym::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_dirty]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", + (sym::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_clean]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), ( - symbols::rustc_partition_reused, + sym::rustc_partition_reused, Whitelisted, template!(List: r#"cfg = "...", module = "...""#), Gated( Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "this attribute \ is just used for rustc unit tests \ and will never be stable", @@ -1195,53 +1196,53 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ) ), ( - symbols::rustc_partition_codegened, + sym::rustc_partition_codegened, Whitelisted, template!(List: r#"cfg = "...", module = "...""#), Gated( Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs), ) ), - (symbols::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", + (sym::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...", kind = "...""#), Gated(Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "this attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "internal rustc attributes will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_mir]` attribute \ is just used for rustc unit tests \ and will never be stable", cfg_fn!(rustc_attrs))), ( - symbols::rustc_inherit_overflow_checks, + sym::rustc_inherit_overflow_checks, Whitelisted, template!(Word), Gated( Stability::Unstable, - "rustc_attrs", + sym::rustc_attrs, "the `#[rustc_inherit_overflow_checks]` \ attribute is just used to control \ overflow checking behavior of several \ @@ -1251,71 +1252,71 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ) ), - (symbols::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_dump_program_clauses]` \ attribute is just used for rustc unit \ tests and will never be stable", cfg_fn!(rustc_attrs))), - (symbols::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "the `#[rustc_test_marker]` attribute \ is used internally to track tests", cfg_fn!(rustc_attrs))), - (symbols::rustc_transparent_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_transparent_macro, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "used internally for testing macro hygiene", cfg_fn!(rustc_attrs))), - (symbols::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, - "compiler_builtins", + (sym::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::compiler_builtins, "the `#[compiler_builtins]` attribute is used to \ identify the `compiler_builtins` crate which \ contains compiler-rt intrinsics and will never be \ stable", cfg_fn!(compiler_builtins))), - (symbols::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - "sanitizer_runtime", + (sym::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::sanitizer_runtime, "the `#[sanitizer_runtime]` attribute is used to \ identify crates that contain the runtime of a \ sanitizer and will never be stable", cfg_fn!(sanitizer_runtime))), - (symbols::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, - "profiler_runtime", + (sym::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::profiler_runtime, "the `#[profiler_runtime]` attribute is used to \ identify the `profiler_builtins` crate which \ contains the profiler runtime and will never be \ stable", cfg_fn!(profiler_runtime))), - (symbols::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), + (sym::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."), Gated(Stability::Unstable, - "allow_internal_unstable", + sym::allow_internal_unstable, EXPLAIN_ALLOW_INTERNAL_UNSTABLE, cfg_fn!(allow_internal_unstable))), - (symbols::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, - "allow_internal_unsafe", + (sym::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable, + sym::allow_internal_unsafe, EXPLAIN_ALLOW_INTERNAL_UNSAFE, cfg_fn!(allow_internal_unsafe))), - (symbols::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, - "fundamental", + (sym::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::fundamental, "the `#[fundamental]` attribute \ is an experimental feature", cfg_fn!(fundamental))), - (symbols::proc_macro_derive, Normal, template!(List: "TraitName, \ + (sym::proc_macro_derive, Normal, template!(List: "TraitName, \ /*opt*/ attributes(name1, name2, ...)"), Ungated), - (symbols::rustc_copy_clone_marker, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_copy_clone_marker, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "internal implementation detail", cfg_fn!(rustc_attrs))), // FIXME: #14408 whitelist docs since rustdoc looks at them ( - symbols::doc, + sym::doc, Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string"), Ungated @@ -1323,94 +1324,94 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // FIXME: #14406 these are processed in codegen, which happens after the // lint pass - (symbols::cold, Whitelisted, template!(Word), Ungated), - (symbols::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, - "naked_functions", + (sym::cold, Whitelisted, template!(Word), Ungated), + (sym::naked, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::naked_functions, "the `#[naked]` attribute \ is an experimental feature", cfg_fn!(naked_functions))), - (symbols::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, - "ffi_returns_twice", + (sym::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::ffi_returns_twice, "the `#[ffi_returns_twice]` attribute \ is an experimental feature", cfg_fn!(ffi_returns_twice))), - (symbols::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), - (symbols::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (symbols::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), - (symbols::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", + (sym::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated), + (sym::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::inline, Whitelisted, template!(Word, List: "always|never"), Ungated), + (sym::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ cfg = "...""#), Ungated), - (symbols::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), - (symbols::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), - (symbols::no_builtins, Whitelisted, template!(Word), Ungated), - (symbols::no_debug, Whitelisted, template!(Word), Gated( + (sym::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated), + (sym::no_builtins, Whitelisted, template!(Word), Ungated), + (sym::no_debug, Whitelisted, template!(Word), Gated( Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None), - "no_debug", + sym::no_debug, "the `#[no_debug]` attribute was an experimental feature that has been \ deprecated due to lack of demand", cfg_fn!(no_debug))), ( - symbols::omit_gdb_pretty_printer_section, + sym::omit_gdb_pretty_printer_section, Whitelisted, template!(Word), Gated( Stability::Unstable, - "omit_gdb_pretty_printer_section", + sym::omit_gdb_pretty_printer_section, "the `#[omit_gdb_pretty_printer_section]` \ attribute is just used for the Rust test \ suite", cfg_fn!(omit_gdb_pretty_printer_section) ) ), - (symbols::unsafe_destructor_blind_to_params, + (sym::unsafe_destructor_blind_to_params, Normal, template!(Word), Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761", Some("replace this attribute with `#[may_dangle]`")), - "dropck_parametricity", + sym::dropck_parametricity, "unsafe_destructor_blind_to_params has been replaced by \ may_dangle and will be removed in the future", cfg_fn!(dropck_parametricity))), - (symbols::may_dangle, + (sym::may_dangle, Normal, template!(Word), Gated(Stability::Unstable, - "dropck_eyepatch", + sym::dropck_eyepatch, "may_dangle has unstable semantics and may be removed in the future", cfg_fn!(dropck_eyepatch))), - (symbols::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, - "unwind_attributes", + (sym::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable, + sym::unwind_attributes, "#[unwind] is experimental", cfg_fn!(unwind_attributes))), - (symbols::used, Whitelisted, template!(Word), Ungated), + (sym::used, Whitelisted, template!(Word), Ungated), // used in resolve - (symbols::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, - "prelude_import", + (sym::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::prelude_import, "`#[prelude_import]` is for use by rustc only", cfg_fn!(prelude_import))), // FIXME: #14407 these are only looked at on-demand so we can't // guarantee they'll have already been checked ( - symbols::rustc_deprecated, + sym::rustc_deprecated, Whitelisted, template!(List: r#"since = "version", reason = "...""#), Ungated ), - (symbols::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), + (sym::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated), ( - symbols::stable, + sym::stable, Whitelisted, template!(List: r#"feature = "name", since = "version""#), Ungated ), ( - symbols::unstable, + sym::unstable, Whitelisted, template!(List: r#"feature = "name", reason = "...", issue = "N""#), Ungated ), - (symbols::deprecated, + (sym::deprecated, Normal, template!( Word, @@ -1420,70 +1421,71 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ Ungated ), - (symbols::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, - "unboxed_closures", + (sym::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable, + sym::unboxed_closures, "unboxed_closures are still evolving", cfg_fn!(unboxed_closures))), - (symbols::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), + (sym::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated), - (symbols::proc_macro_attribute, Normal, template!(Word), Ungated), - (symbols::proc_macro, Normal, template!(Word), Ungated), + (sym::proc_macro_attribute, Normal, template!(Word), Ungated), + (sym::proc_macro, Normal, template!(Word), Ungated), - (symbols::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "used internally by rustc", cfg_fn!(rustc_attrs))), - (symbols::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, - "allow_fail", + (sym::allow_fail, Normal, template!(Word), Gated(Stability::Unstable, + sym::allow_fail, "allow_fail attribute is currently unstable", cfg_fn!(allow_fail))), - (symbols::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "this is an internal attribute that will \ never be stable", cfg_fn!(rustc_attrs))), // whitelists "identity-like" conversion methods to suggest on type mismatch - (symbols::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, - "rustc_attrs", + (sym::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable, + sym::rustc_attrs, "this is an internal attribute that will \ never be stable", cfg_fn!(rustc_attrs))), ( - symbols::rustc_args_required_const, + sym::rustc_args_required_const, Whitelisted, template!(List: "N"), - Gated(Stability::Unstable, "rustc_attrs", "never will be stable", cfg_fn!(rustc_attrs)) + Gated(Stability::Unstable, sym::rustc_attrs, "never will be stable", + cfg_fn!(rustc_attrs)) ), // RFC 2070 - (symbols::panic_handler, Normal, template!(Word), Ungated), + (sym::panic_handler, Normal, template!(Word), Ungated), - (symbols::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, - "alloc_error_handler", + (sym::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable, + sym::alloc_error_handler, "#[alloc_error_handler] is an unstable feature", cfg_fn!(alloc_error_handler))), // RFC 2412 - (symbols::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, - "optimize_attribute", + (sym::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable, + sym::optimize_attribute, "#[optimize] attribute is an unstable feature", cfg_fn!(optimize_attribute))), // Crate level attributes - (symbols::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), - (symbols::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), - (symbols::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), - (symbols::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), - (symbols::no_start, CrateLevel, template!(Word), Ungated), - (symbols::no_main, CrateLevel, template!(Word), Ungated), - (symbols::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (symbols::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), - (symbols::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, - "custom_test_frameworks", + (sym::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated), + (sym::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated), + (sym::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated), + (sym::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated), + (sym::no_start, CrateLevel, template!(Word), Ungated), + (sym::no_main, CrateLevel, template!(Word), Ungated), + (sym::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), + (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated), + (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable, + sym::custom_test_frameworks, EXPLAIN_CUSTOM_TEST_FRAMEWORKS, cfg_fn!(custom_test_frameworks))), ]; @@ -1503,11 +1505,11 @@ lazy_static! { } // cfg(...)'s that are feature gated -const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[ +const GATED_CFGS: &[(Symbol, Symbol, fn(&Features) -> bool)] = &[ // (name in cfg, feature, function to check if the feature is enabled) - ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), - ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), - ("rustdoc", "doc_cfg", cfg_fn!(doc_cfg)), + (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), + (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + (sym::rustdoc, sym::doc_cfg, cfg_fn!(doc_cfg)), ]; #[derive(Debug)] @@ -1540,7 +1542,7 @@ impl GatedCfg { struct Context<'a> { features: &'a Features, parse_sess: &'a ParseSess, - plugin_attributes: &'a [(String, AttributeType)], + plugin_attributes: &'a [(Symbol, AttributeType)], } macro_rules! gate_feature_fn { @@ -1559,11 +1561,11 @@ macro_rules! gate_feature_fn { macro_rules! gate_feature { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => { gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - stringify!($feature), $explain, GateStrength::Hard) + sym::$feature, $explain, GateStrength::Hard) }; ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => { gate_feature_fn!($cx, |x:&Features| x.$feature, $span, - stringify!($feature), $explain, $level) + sym::$feature, $explain, $level) }; } @@ -1582,9 +1584,9 @@ impl<'a> Context<'a> { self, has_feature, attr.span, name, desc, GateStrength::Hard ); } - } else if name == symbols::doc { + } else if name == sym::doc { if let Some(content) = attr.meta_item_list() { - if content.iter().any(|c| c.check_name(symbols::include)) { + if content.iter().any(|c| c.check_name(sym::include)) { gate_feature!(self, external_doc, attr.span, "#[doc(include = \"...\")] is experimental" ); @@ -1594,8 +1596,8 @@ impl<'a> Context<'a> { debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage); return; } - for &(ref n, ref ty) in self.plugin_attributes { - if attr.path == &**n { + for &(n, ty) in self.plugin_attributes { + if attr.path == n { // Plugins can't gate attributes, so we don't check for it // unlike the code above; we only use this loop to // short-circuit to avoid the checks below. @@ -1604,7 +1606,7 @@ impl<'a> Context<'a> { } } if !attr::is_known(attr) { - if attr.name_or_empty().starts_with("rustc_") { + if attr.name_or_empty().as_str().starts_with("rustc_") { let msg = "unless otherwise specified, attributes with the prefix `rustc_` \ are reserved for internal compiler diagnostics"; gate_feature!(self, rustc_attrs, attr.span, msg); @@ -1629,7 +1631,7 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: ); } -fn find_lang_feature_issue(feature: &str) -> Option { +fn find_lang_feature_issue(feature: Symbol) -> Option { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { let issue = info.2; // FIXME (#28244): enforce that active features have issue numbers @@ -1661,7 +1663,7 @@ pub enum GateStrength { pub fn emit_feature_err( sess: &ParseSess, - feature: &str, + feature: Symbol, span: Span, issue: GateIssue, explain: &str, @@ -1671,7 +1673,7 @@ pub fn emit_feature_err( pub fn feature_err<'a>( sess: &'a ParseSess, - feature: &str, + feature: Symbol, span: Span, issue: GateIssue, explain: &str, @@ -1681,7 +1683,7 @@ pub fn feature_err<'a>( fn leveled_feature_err<'a>( sess: &'a ParseSess, - feature: &str, + feature: Symbol, span: Span, issue: GateIssue, explain: &str, @@ -1769,13 +1771,13 @@ struct PostExpansionVisitor<'a> { macro_rules! gate_feature_post { ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {{ let (cx, span) = ($cx, $span); - if !span.allows_unstable(stringify!($feature)) { + if !span.allows_unstable(sym::$feature) { gate_feature!(cx.context, $feature, span, $explain) } }}; ($cx: expr, $feature: ident, $span: expr, $explain: expr, $level: expr) => {{ let (cx, span) = ($cx, $span); - if !span.allows_unstable(stringify!($feature)) { + if !span.allows_unstable(sym::$feature) { gate_feature!(cx.context, $feature, span, $explain, $level) } }} @@ -1841,11 +1843,11 @@ impl<'a> PostExpansionVisitor<'a> { template: AttributeTemplate) { // Some special attributes like `cfg` must be checked // before the generic check, so we skip them here. - let should_skip = |name| name == symbols::cfg; + let should_skip = |name| name == sym::cfg; // Some of previously accepted forms were used in practice, // report them as warnings for now. - let should_warn = |name| name == symbols::doc || name == symbols::ignore || - name == symbols::inline || name == symbols::link; + let should_warn = |name| name == sym::doc || name == sym::ignore || + name == sym::inline || name == sym::link; match attr.parse_meta(self.context.parse_sess) { Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) { @@ -1893,25 +1895,25 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { // check for gated attributes self.context.check_attribute(attr, attr_info, false); - if attr.check_name(symbols::doc) { + if attr.check_name(sym::doc) { if let Some(content) = attr.meta_item_list() { - if content.len() == 1 && content[0].check_name(symbols::cfg) { + if content.len() == 1 && content[0].check_name(sym::cfg) { gate_feature_post!(&self, doc_cfg, attr.span, "#[doc(cfg(...))] is experimental" ); - } else if content.iter().any(|c| c.check_name(symbols::masked)) { + } else if content.iter().any(|c| c.check_name(sym::masked)) { gate_feature_post!(&self, doc_masked, attr.span, "#[doc(masked)] is experimental" ); - } else if content.iter().any(|c| c.check_name(symbols::spotlight)) { + } else if content.iter().any(|c| c.check_name(sym::spotlight)) { gate_feature_post!(&self, doc_spotlight, attr.span, "#[doc(spotlight)] is experimental" ); - } else if content.iter().any(|c| c.check_name(symbols::alias)) { + } else if content.iter().any(|c| c.check_name(sym::alias)) { gate_feature_post!(&self, doc_alias, attr.span, "#[doc(alias = \"...\")] is experimental" ); - } else if content.iter().any(|c| c.check_name(symbols::keyword)) { + } else if content.iter().any(|c| c.check_name(sym::keyword)) { gate_feature_post!(&self, doc_keyword, attr.span, "#[doc(keyword = \"...\")] is experimental" ); @@ -1946,7 +1948,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { fn visit_item(&mut self, i: &'a ast::Item) { match i.node { ast::ItemKind::Const(_,_) => { - if i.ident.name == "_" { + if i.ident.name == keywords::Underscore.name() { gate_feature_post!(&self, underscore_const_names, i.span, "naming constants with `_` is unstable"); } @@ -1957,17 +1959,17 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs[..], "plugin_registrar") { + if attr::contains_name(&i.attrs[..], sym::plugin_registrar) { gate_feature_post!(&self, plugin_registrar, i.span, "compiler plugins are experimental and possibly buggy"); } - if attr::contains_name(&i.attrs[..], "start") { + if attr::contains_name(&i.attrs[..], sym::start) { gate_feature_post!(&self, start, i.span, "a #[start] function is an experimental \ feature whose signature may change \ over time"); } - if attr::contains_name(&i.attrs[..], "main") { + if attr::contains_name(&i.attrs[..], sym::main) { gate_feature_post!(&self, main, i.span, "declaration of a nonstandard #[main] \ function may change over time, for now \ @@ -1976,9 +1978,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Struct(..) => { - for attr in attr::filter_by_name(&i.attrs[..], "repr") { + for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(symbols::simd) { + if item.check_name(sym::simd) { gate_feature_post!(&self, repr_simd, attr.span, "SIMD types are experimental and possibly buggy"); } @@ -1987,9 +1989,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } ast::ItemKind::Enum(..) => { - for attr in attr::filter_by_name(&i.attrs[..], "repr") { + for attr in attr::filter_by_name(&i.attrs[..], sym::repr) { for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.check_name(symbols::align) { + if item.check_name(sym::align) { gate_feature_post!(&self, repr_align_enum, attr.span, "`#[repr(align(x))]` on enums is experimental"); } @@ -2051,7 +2053,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { match i.node { ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => { - let link_name = attr::first_attr_value_str_by_name(&i.attrs, "link_name"); + let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name); let links_to_llvm = match link_name { Some(val) => val.as_str().starts_with("llvm."), _ => false @@ -2303,7 +2305,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], if edition <= crate_edition { // The `crate_edition` implies its respective umbrella feature-gate // (i.e., `#![feature(rust_20XX_preview)]` isn't needed on edition 20XX). - edition_enabled_features.insert(Symbol::intern(edition.feature_name()), edition); + edition_enabled_features.insert(edition.feature_name(), edition); } } @@ -2311,7 +2313,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], if let Some(f_edition) = f_edition { if f_edition <= crate_edition { set(&mut features, DUMMY_SP); - edition_enabled_features.insert(Symbol::intern(name), crate_edition); + edition_enabled_features.insert(name, crate_edition); } } } @@ -2319,7 +2321,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], // Process the edition umbrella feature-gates first, to ensure // `edition_enabled_features` is completed before it's queried. for attr in krate_attrs { - if !attr.check_name(symbols::feature) { + if !attr.check_name(sym::feature) { continue } @@ -2355,7 +2357,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], // FIXME(Manishearth) there is currently no way to set // lib features by edition set(&mut features, DUMMY_SP); - edition_enabled_features.insert(Symbol::intern(name), *edition); + edition_enabled_features.insert(name, *edition); } } } @@ -2364,7 +2366,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], } for attr in krate_attrs { - if !attr.check_name(symbols::feature) { + if !attr.check_name(sym::feature) { continue } @@ -2438,7 +2440,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute], pub fn check_crate(krate: &ast::Crate, sess: &ParseSess, features: &Features, - plugin_attributes: &[(String, AttributeType)], + plugin_attributes: &[(Symbol, AttributeType)], unstable: UnstableFeatures) { maybe_stage_features(&sess.span_diagnostic, krate, unstable); let ctx = Context { @@ -2496,7 +2498,7 @@ fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, }; if !allow_features { for attr in &krate.attrs { - if attr.check_name(symbols::feature) { + if attr.check_name(sym::feature) { let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)"); span_err!(span_handler, attr.span, E0554, "#![feature] may not be used on the {} release channel", diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 6eb8b1b5004c..f587e63e12b9 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -663,7 +663,6 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtMeta(meta) => vis.visit_meta_item(meta), token::NtPath(path) => vis.visit_path(path), token::NtTT(tt) => vis.visit_tt(tt), - token::NtArm(arm) => vis.visit_arm(arm), token::NtImplItem(item) => visit_clobber(item, |item| { // See reasoning above. @@ -676,9 +675,6 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: vis.flat_map_trait_item(item) .expect_one("expected visitor to produce exactly one item") }), - token::NtGenerics(generics) => vis.visit_generics(generics), - token::NtWhereClause(where_clause) => vis.visit_where_clause(where_clause), - token::NtArg(arg) => vis.visit_arg(arg), token::NtVis(visib) => vis.visit_vis(visib), token::NtForeignItem(item) => visit_clobber(item, |item| { diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index b4103440e357..dfd6f451c28d 100644 --- a/src/libsyntax/parse/classify.rs +++ b/src/libsyntax/parse/classify.rs @@ -25,16 +25,3 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool { _ => true, } } - -/// this statement requires a semicolon after it. -/// note that in one case (`stmt_semi`), we've already -/// seen the semicolon, and thus don't need another. -pub fn stmt_ends_with_semi(stmt: &ast::StmtKind) -> bool { - match *stmt { - ast::StmtKind::Local(_) => true, - ast::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(e), - ast::StmtKind::Item(_) | - ast::StmtKind::Semi(..) | - ast::StmtKind::Mac(..) => false, - } -} diff --git a/src/libsyntax/parse/diagnostics.rs b/src/libsyntax/parse/diagnostics.rs index 32e1ee94f0df..1a2393be806d 100644 --- a/src/libsyntax/parse/diagnostics.rs +++ b/src/libsyntax/parse/diagnostics.rs @@ -1,14 +1,16 @@ use crate::ast; -use crate::ast::{Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind}; -use crate::parse::parser::PathStyle; +use crate::ast::{BlockCheckMode, Expr, ExprKind, Item, ItemKind, Pat, PatKind, QSelf, Ty, TyKind}; +use crate::parse::parser::{BlockMode, PathStyle, TokenType, SemiColonMode}; use crate::parse::token; use crate::parse::PResult; use crate::parse::Parser; use crate::print::pprust; use crate::ptr::P; +use crate::symbol::keywords; use crate::ThinVec; -use errors::Applicability; +use errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; +use log::debug; pub trait RecoverQPath: Sized + 'static { const PATH_STYLE: PathStyle = PathStyle::Expr; @@ -223,4 +225,300 @@ impl<'a> Parser<'a> { false } } + + /// Consume alternative await syntaxes like `await `, `await? `, `await()` + /// and `await { }`. + crate fn parse_incorrect_await_syntax( + &mut self, + lo: Span, + await_sp: Span, + ) -> PResult<'a, (Span, ExprKind)> { + let is_question = self.eat(&token::Question); // Handle `await? `. + let expr = if self.token == token::OpenDelim(token::Brace) { + // Handle `await { }`. + // This needs to be handled separatedly from the next arm to avoid + // interpreting `await { }?` as `?.await`. + self.parse_block_expr( + None, + self.span, + BlockCheckMode::Default, + ThinVec::new(), + ) + } else { + self.parse_expr() + }.map_err(|mut err| { + err.span_label(await_sp, "while parsing this incorrect await expression"); + err + })?; + let expr_str = self.sess.source_map().span_to_snippet(expr.span) + .unwrap_or_else(|_| pprust::expr_to_string(&expr)); + let suggestion = format!("{}.await{}", expr_str, if is_question { "?" } else { "" }); + let sp = lo.to(expr.span); + let app = match expr.node { + ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` + _ => Applicability::MachineApplicable, + }; + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion(sp, "`await` is a postfix operation", suggestion, app) + .emit(); + Ok((sp, ExprKind::Await(ast::AwaitOrigin::FieldLike, expr))) + } + + /// If encountering `future.await()`, consume and emit error. + crate fn recover_from_await_method_call(&mut self) { + if self.token == token::OpenDelim(token::Paren) && + self.look_ahead(1, |t| t == &token::CloseDelim(token::Paren)) + { + // future.await() + let lo = self.span; + self.bump(); // ( + let sp = lo.to(self.span); + self.bump(); // ) + self.struct_span_err(sp, "incorrect use of `await`") + .span_suggestion( + sp, + "`await` is not a method call, remove the parentheses", + String::new(), + Applicability::MachineApplicable, + ).emit() + } + } + + crate fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool { + self.token.is_ident() && + if let ast::ExprKind::Path(..) = node { true } else { false } && + !self.token.is_reserved_ident() && // v `foo:bar(baz)` + self.look_ahead(1, |t| t == &token::OpenDelim(token::Paren)) || + self.look_ahead(1, |t| t == &token::Lt) && // `foo:bar, + lhs_span: Span, + cur_op_span: Span, + next_sp: Span, + maybe_path: bool, + ) { + err.span_label(self.span, "expecting a type here because of type ascription"); + let cm = self.sess.source_map(); + let next_pos = cm.lookup_char_pos(next_sp.lo()); + let op_pos = cm.lookup_char_pos(cur_op_span.hi()); + if op_pos.line != next_pos.line { + err.span_suggestion( + cur_op_span, + "try using a semicolon", + ";".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + if maybe_path { + err.span_suggestion( + cur_op_span, + "maybe you meant to write a path separator here", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + } else { + err.note("type ascription is a nightly-only feature that lets \ + you annotate an expression with a type: `: `") + .span_note( + lhs_span, + "this expression expects an ascribed type after the colon", + ) + .help("this might be indicative of a syntax error elsewhere"); + } + } + } + + crate fn recover_seq_parse_error( + &mut self, + delim: token::DelimToken, + lo: Span, + result: PResult<'a, P>, + ) -> P { + match result { + Ok(x) => x, + Err(mut err) => { + err.emit(); + // recover from parse error + self.consume_block(delim); + self.mk_expr(lo.to(self.prev_span), ExprKind::Err, ThinVec::new()) + } + } + } + + crate fn recover_closing_delimiter( + &mut self, + tokens: &[token::Token], + mut err: DiagnosticBuilder<'a>, + ) -> PResult<'a, bool> { + let mut pos = None; + // we want to use the last closing delim that would apply + for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { + if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) + && Some(self.span) > unmatched.unclosed_span + { + pos = Some(i); + } + } + match pos { + Some(pos) => { + // Recover and assume that the detected unclosed delimiter was meant for + // this location. Emit the diagnostic and act as if the delimiter was + // present for the parser's sake. + + // Don't attempt to recover from this unclosed delimiter more than once. + let unmatched = self.unclosed_delims.remove(pos); + let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); + + // We want to suggest the inclusion of the closing delimiter where it makes + // the most sense, which is immediately after the last token: + // + // {foo(bar {}} + // - ^ + // | | + // | help: `)` may belong here (FIXME: #58270) + // | + // unclosed delimiter + if let Some(sp) = unmatched.unclosed_span { + err.span_label(sp, "unclosed delimiter"); + } + err.span_suggestion_short( + self.sess.source_map().next_point(self.prev_span), + &format!("{} may belong here", delim.to_string()), + delim.to_string(), + Applicability::MaybeIncorrect, + ); + err.emit(); + self.expected_tokens.clear(); // reduce errors + Ok(true) + } + _ => Err(err), + } + } + + /// Recover from `pub` keyword in places where it seems _reasonable_ but isn't valid. + crate fn eat_bad_pub(&mut self) { + if self.token.is_keyword(keywords::Pub) { + match self.parse_visibility(false) { + Ok(vis) => { + self.diagnostic() + .struct_span_err(vis.span, "unnecessary visibility qualifier") + .span_label(vis.span, "`pub` not permitted here") + .emit(); + } + Err(mut err) => err.emit(), + } + } + } + + // Eat tokens until we can be relatively sure we reached the end of the + // statement. This is something of a best-effort heuristic. + // + // We terminate when we find an unmatched `}` (without consuming it). + crate fn recover_stmt(&mut self) { + self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore) + } + + // If `break_on_semi` is `Break`, then we will stop consuming tokens after + // finding (and consuming) a `;` outside of `{}` or `[]` (note that this is + // approximate - it can mean we break too early due to macros, but that + // should only lead to sub-optimal recovery, not inaccurate parsing). + // + // If `break_on_block` is `Break`, then we will stop consuming tokens + // after finding (and consuming) a brace-delimited block. + crate fn recover_stmt_(&mut self, break_on_semi: SemiColonMode, break_on_block: BlockMode) { + let mut brace_depth = 0; + let mut bracket_depth = 0; + let mut in_block = false; + debug!("recover_stmt_ enter loop (semi={:?}, block={:?})", + break_on_semi, break_on_block); + loop { + debug!("recover_stmt_ loop {:?}", self.token); + match self.token { + token::OpenDelim(token::DelimToken::Brace) => { + brace_depth += 1; + self.bump(); + if break_on_block == BlockMode::Break && + brace_depth == 1 && + bracket_depth == 0 { + in_block = true; + } + } + token::OpenDelim(token::DelimToken::Bracket) => { + bracket_depth += 1; + self.bump(); + } + token::CloseDelim(token::DelimToken::Brace) => { + if brace_depth == 0 { + debug!("recover_stmt_ return - close delim {:?}", self.token); + break; + } + brace_depth -= 1; + self.bump(); + if in_block && bracket_depth == 0 && brace_depth == 0 { + debug!("recover_stmt_ return - block end {:?}", self.token); + break; + } + } + token::CloseDelim(token::DelimToken::Bracket) => { + bracket_depth -= 1; + if bracket_depth < 0 { + bracket_depth = 0; + } + self.bump(); + } + token::Eof => { + debug!("recover_stmt_ return - Eof"); + break; + } + token::Semi => { + self.bump(); + if break_on_semi == SemiColonMode::Break && + brace_depth == 0 && + bracket_depth == 0 { + debug!("recover_stmt_ return - Semi"); + break; + } + } + token::Comma if break_on_semi == SemiColonMode::Comma && + brace_depth == 0 && + bracket_depth == 0 => + { + debug!("recover_stmt_ return - Semi"); + break; + } + _ => { + self.bump() + } + } + } + } + + crate fn consume_block(&mut self, delim: token::DelimToken) { + let mut brace_depth = 0; + loop { + if self.eat(&token::OpenDelim(delim)) { + brace_depth += 1; + } else if self.eat(&token::CloseDelim(delim)) { + if brace_depth == 0 { + return; + } else { + brace_depth -= 1; + continue; + } + } else if self.token == token::Eof || self.eat(&token::CloseDelim(token::NoDelim)) { + return; + } else { + self.bump(); + } + } + } + } diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 74fff3324eac..97d3fc002e9b 100644 --- a/src/libsyntax/parse/lexer/comments.rs +++ b/src/libsyntax/parse/lexer/comments.rs @@ -3,8 +3,7 @@ pub use CommentStyle::*; use crate::ast; use crate::source_map::SourceMap; use crate::parse::lexer::{is_block_doc_comment, is_pattern_whitespace}; -use crate::parse::lexer::{self, ParseSess, StringReader, TokenAndSpan}; -use crate::print::pprust; +use crate::parse::lexer::{self, ParseSess, StringReader}; use syntax_pos::{BytePos, CharPos, Pos, FileName}; use log::debug; @@ -339,16 +338,9 @@ fn consume_comment(rdr: &mut StringReader<'_>, debug!("<<< consume comment"); } -#[derive(Clone)] -pub struct Literal { - pub lit: String, - pub pos: BytePos, -} - // it appears this function is called only from pprust... that's // probably not a good thing. -pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) - -> (Vec, Vec) +pub fn gather_comments(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) -> Vec { let mut src = String::new(); srdr.read_to_string(&mut src).unwrap(); @@ -357,7 +349,6 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut let mut rdr = lexer::StringReader::new_raw(sess, source_file, None); let mut comments: Vec = Vec::new(); - let mut literals: Vec = Vec::new(); let mut code_to_the_left = false; // Only code let mut anything_to_the_left = false; // Code or comments @@ -382,26 +373,12 @@ pub fn gather_comments_and_literals(sess: &ParseSess, path: FileName, srdr: &mut } } - let bstart = rdr.pos; rdr.next_token(); - // discard, and look ahead; we're working with internal state - let TokenAndSpan { tok, sp } = rdr.peek(); - if tok.is_lit() { - rdr.with_str_from(bstart, |s| { - debug!("tok lit: {}", s); - literals.push(Literal { - lit: s.to_string(), - pos: sp.lo(), - }); - }) - } else { - debug!("tok: {}", pprust::token_to_string(&tok)); - } code_to_the_left = true; anything_to_the_left = true; } - (comments, literals) + comments } #[cfg(test)] diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 2882acb0e780..47da3ee6a6c7 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -62,19 +62,7 @@ pub struct StringReader<'a> { // cache a direct reference to the source text, so that we don't have to // retrieve it via `self.source_file.src.as_ref().unwrap()` all the time. src: Lrc, - token: token::Token, - span: Span, - /// The raw source span which *does not* take `override_span` into account - span_src_raw: Span, - /// Stack of open delimiters and their spans. Used for error message. - open_braces: Vec<(token::DelimToken, Span)>, - crate unmatched_braces: Vec, - /// The type and spans for all braces - /// - /// Used only for error recovery when arriving to EOF with mismatched braces. - matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, - crate override_span: Option, - last_unclosed_found_span: Option, + override_span: Option, } impl<'a> StringReader<'a> { @@ -121,8 +109,6 @@ impl<'a> StringReader<'a> { sp: self.peek_span, }; self.advance_token()?; - self.span_src_raw = self.peek_span_src_raw; - Ok(ret_val) } @@ -159,9 +145,6 @@ impl<'a> StringReader<'a> { } } - self.token = t.tok.clone(); - self.span = t.sp; - Ok(t) } @@ -251,29 +234,10 @@ impl<'a> StringReader<'a> { peek_span_src_raw: syntax_pos::DUMMY_SP, src, fatal_errs: Vec::new(), - token: token::Eof, - span: syntax_pos::DUMMY_SP, - span_src_raw: syntax_pos::DUMMY_SP, - open_braces: Vec::new(), - unmatched_braces: Vec::new(), - matching_delim_spans: Vec::new(), override_span, - last_unclosed_found_span: None, } } - pub fn new(sess: &'a ParseSess, - source_file: Lrc, - override_span: Option) -> Self { - let mut sr = StringReader::new_raw(sess, source_file, override_span); - if sr.advance_token().is_err() { - sr.emit_fatal_errors(); - FatalError.raise(); - } - - sr - } - pub fn new_or_buffered_errs(sess: &'a ParseSess, source_file: Lrc, override_span: Option) -> Result> { @@ -1627,7 +1591,12 @@ mod tests { teststr: String) -> StringReader<'a> { let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr); - StringReader::new(sess, sf, None) + let mut sr = StringReader::new_raw(sess, sf, None); + if sr.advance_token().is_err() { + sr.emit_fatal_errors(); + FatalError.raise(); + } + sr } #[test] diff --git a/src/libsyntax/parse/lexer/tokentrees.rs b/src/libsyntax/parse/lexer/tokentrees.rs index 0db36c84cdfe..4bfc5bb16c0b 100644 --- a/src/libsyntax/parse/lexer/tokentrees.rs +++ b/src/libsyntax/parse/lexer/tokentrees.rs @@ -1,13 +1,46 @@ +use syntax_pos::Span; + use crate::print::pprust::token_to_string; use crate::parse::lexer::{StringReader, UnmatchedBrace}; use crate::parse::{token, PResult}; use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint}; impl<'a> StringReader<'a> { + crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { + let mut tt_reader = TokenTreesReader { + string_reader: self, + token: token::Eof, + span: syntax_pos::DUMMY_SP, + open_braces: Vec::new(), + unmatched_braces: Vec::new(), + matching_delim_spans: Vec::new(), + last_unclosed_found_span: None, + }; + let res = tt_reader.parse_all_token_trees(); + (res, tt_reader.unmatched_braces) + } +} + +struct TokenTreesReader<'a> { + string_reader: StringReader<'a>, + token: token::Token, + span: Span, + /// Stack of open delimiters and their spans. Used for error message. + open_braces: Vec<(token::DelimToken, Span)>, + unmatched_braces: Vec, + /// The type and spans for all braces + /// + /// Used only for error recovery when arriving to EOF with mismatched braces. + matching_delim_spans: Vec<(token::DelimToken, Span, Span)>, + last_unclosed_found_span: Option, +} + +impl<'a> TokenTreesReader<'a> { // Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`. - crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { + fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { let mut tts = Vec::new(); + self.real_token(); while self.token != token::Eof { tts.push(self.parse_token_tree()?); } @@ -34,11 +67,12 @@ impl<'a> StringReader<'a> { } fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { - let sm = self.sess.source_map(); + let sm = self.string_reader.sess.source_map(); match self.token { token::Eof => { let msg = "this file contains an un-closed delimiter"; - let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg); + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.span, msg); for &(_, sp) in &self.open_braces { err.span_label(sp, "un-closed delimiter"); } @@ -46,13 +80,12 @@ impl<'a> StringReader<'a> { if let Some((delim, _)) = self.open_braces.last() { if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter() .filter(|(d, open_sp, close_sp)| { - - if let Some(close_padding) = sm.span_to_margin(*close_sp) { - if let Some(open_padding) = sm.span_to_margin(*open_sp) { - return delim == d && close_padding != open_padding; + if let Some(close_padding) = sm.span_to_margin(*close_sp) { + if let Some(open_padding) = sm.span_to_margin(*open_sp) { + return delim == d && close_padding != open_padding; + } } - } - false + false }).next() // these are in reverse order as they get inserted on close, but { // we want the last open/first close err.span_label( @@ -164,7 +197,8 @@ impl<'a> StringReader<'a> { // matching opening delimiter). let token_str = token_to_string(&self.token); let msg = format!("unexpected close delimiter: `{}`", token_str); - let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg); + let mut err = self.string_reader.sess.span_diagnostic + .struct_span_err(self.span, &msg); err.span_label(self.span, "unexpected close delimiter"); Err(err) }, @@ -173,11 +207,20 @@ impl<'a> StringReader<'a> { // Note that testing for joint-ness here is done via the raw // source span as the joint-ness is a property of the raw source // rather than wanting to take `override_span` into account. - let raw = self.span_src_raw; + // Additionally, we actually check if the *next* pair of tokens + // is joint, but this is equivalent to checking the current pair. + let raw = self.string_reader.peek_span_src_raw; self.real_token(); - let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token); + let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo() + && token::is_op(&self.token); Ok((tt, if is_joint { Joint } else { NonJoint })) } } } + + fn real_token(&mut self) { + let t = self.string_reader.real_token(); + self.token = t.tok; + self.span = t.sp; + } } diff --git a/src/libsyntax/parse/literal.rs b/src/libsyntax/parse/literal.rs new file mode 100644 index 000000000000..53195421ddce --- /dev/null +++ b/src/libsyntax/parse/literal.rs @@ -0,0 +1,487 @@ +//! Code related to parsing literals. + +use crate::ast::{self, Ident, Lit, LitKind}; +use crate::parse::parser::Parser; +use crate::parse::PResult; +use crate::parse::token::{self, Token}; +use crate::parse::unescape::{unescape_str, unescape_char, unescape_byte_str, unescape_byte}; +use crate::print::pprust; +use crate::symbol::{keywords, Symbol}; +use crate::tokenstream::{TokenStream, TokenTree}; + +use errors::{Applicability, Handler}; +use log::debug; +use rustc_data_structures::sync::Lrc; +use syntax_pos::Span; + +use std::ascii; + +macro_rules! err { + ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => { + match $opt_diag { + Some(($span, $diag)) => { $($body)* } + None => return None, + } + } +} + +impl LitKind { + /// Converts literal token with a suffix into a semantic literal. + /// Works speculatively and may return `None` if diagnostic handler is not passed. + /// If diagnostic handler is passed, always returns `Some`, + /// possibly after reporting non-fatal errors and recovery. + fn from_lit_token( + lit: token::Lit, + suf: Option, + diag: Option<(Span, &Handler)> + ) -> Option { + if suf.is_some() && !lit.may_have_suffix() { + err!(diag, |span, diag| { + expect_no_suffix(span, diag, &format!("a {}", lit.literal_name()), suf) + }); + } + + Some(match lit { + token::Bool(i) => { + assert!(i == keywords::True.name() || i == keywords::False.name()); + LitKind::Bool(i == keywords::True.name()) + } + token::Byte(i) => { + match unescape_byte(&i.as_str()) { + Ok(c) => LitKind::Byte(c), + Err(_) => LitKind::Err(i), + } + }, + token::Char(i) => { + match unescape_char(&i.as_str()) { + Ok(c) => LitKind::Char(c), + Err(_) => LitKind::Err(i), + } + }, + token::Err(i) => LitKind::Err(i), + + // There are some valid suffixes for integer and float literals, + // so all the handling is done internally. + token::Integer(s) => return integer_lit(&s.as_str(), suf, diag), + token::Float(s) => return float_lit(&s.as_str(), suf, diag), + + token::Str_(mut sym) => { + // If there are no characters requiring special treatment we can + // reuse the symbol from the Token. Otherwise, we must generate a + // new symbol because the string in the LitKind is different to the + // string in the Token. + let mut has_error = false; + let s = &sym.as_str(); + if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') { + let mut buf = String::with_capacity(s.len()); + unescape_str(s, &mut |_, unescaped_char| { + match unescaped_char { + Ok(c) => buf.push(c), + Err(_) => has_error = true, + } + }); + if has_error { + return Some(LitKind::Err(sym)); + } + sym = Symbol::intern(&buf) + } + + LitKind::Str(sym, ast::StrStyle::Cooked) + } + token::StrRaw(mut sym, n) => { + // Ditto. + let s = &sym.as_str(); + if s.contains('\r') { + sym = Symbol::intern(&raw_str_lit(s)); + } + LitKind::Str(sym, ast::StrStyle::Raw(n)) + } + token::ByteStr(i) => { + let s = &i.as_str(); + let mut buf = Vec::with_capacity(s.len()); + let mut has_error = false; + unescape_byte_str(s, &mut |_, unescaped_byte| { + match unescaped_byte { + Ok(c) => buf.push(c), + Err(_) => has_error = true, + } + }); + if has_error { + return Some(LitKind::Err(i)); + } + buf.shrink_to_fit(); + LitKind::ByteStr(Lrc::new(buf)) + } + token::ByteStrRaw(i, _) => { + LitKind::ByteStr(Lrc::new(i.to_string().into_bytes())) + } + }) + } + + /// Attempts to recover a token from semantic literal. + /// This function is used when the original token doesn't exist (e.g. the literal is created + /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). + pub fn to_lit_token(&self) -> (token::Lit, Option) { + match *self { + LitKind::Str(string, ast::StrStyle::Cooked) => { + let escaped = string.as_str().escape_default().to_string(); + (token::Lit::Str_(Symbol::intern(&escaped)), None) + } + LitKind::Str(string, ast::StrStyle::Raw(n)) => { + (token::Lit::StrRaw(string, n), None) + } + LitKind::ByteStr(ref bytes) => { + let string = bytes.iter().cloned().flat_map(ascii::escape_default) + .map(Into::::into).collect::(); + (token::Lit::ByteStr(Symbol::intern(&string)), None) + } + LitKind::Byte(byte) => { + let string: String = ascii::escape_default(byte).map(Into::::into).collect(); + (token::Lit::Byte(Symbol::intern(&string)), None) + } + LitKind::Char(ch) => { + let string: String = ch.escape_default().map(Into::::into).collect(); + (token::Lit::Char(Symbol::intern(&string)), None) + } + LitKind::Int(n, ty) => { + let suffix = match ty { + ast::LitIntType::Unsigned(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Signed(ty) => Some(Symbol::intern(ty.ty_to_string())), + ast::LitIntType::Unsuffixed => None, + }; + (token::Lit::Integer(Symbol::intern(&n.to_string())), suffix) + } + LitKind::Float(symbol, ty) => { + (token::Lit::Float(symbol), Some(Symbol::intern(ty.ty_to_string()))) + } + LitKind::FloatUnsuffixed(symbol) => (token::Lit::Float(symbol), None), + LitKind::Bool(value) => { + let kw = if value { keywords::True } else { keywords::False }; + (token::Lit::Bool(kw.name()), None) + } + LitKind::Err(val) => (token::Lit::Err(val), None), + } + } +} + +impl Lit { + /// Converts literal token with a suffix into an AST literal. + /// Works speculatively and may return `None` if diagnostic handler is not passed. + /// If diagnostic handler is passed, may return `Some`, + /// possibly after reporting non-fatal errors and recovery, or `None` for irrecoverable errors. + crate fn from_token( + token: &token::Token, + span: Span, + diag: Option<(Span, &Handler)>, + ) -> Option { + let (token, suffix) = match *token { + token::Ident(ident, false) if ident.name == keywords::True.name() || + ident.name == keywords::False.name() => + (token::Bool(ident.name), None), + token::Literal(token, suffix) => + (token, suffix), + token::Interpolated(ref nt) => { + if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt { + if let ast::ExprKind::Lit(lit) = &expr.node { + return Some(lit.clone()); + } + } + return None; + } + _ => return None, + }; + + let node = LitKind::from_lit_token(token, suffix, diag)?; + Some(Lit { node, token, suffix, span }) + } + + /// Attempts to recover an AST literal from semantic literal. + /// This function is used when the original token doesn't exist (e.g. the literal is created + /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). + pub fn from_lit_kind(node: LitKind, span: Span) -> Lit { + let (token, suffix) = node.to_lit_token(); + Lit { node, token, suffix, span } + } + + /// Losslessly convert an AST literal into a token stream. + crate fn tokens(&self) -> TokenStream { + let token = match self.token { + token::Bool(symbol) => Token::Ident(Ident::with_empty_ctxt(symbol), false), + token => Token::Literal(token, self.suffix), + }; + TokenTree::Token(self.span, token).into() + } +} + +impl<'a> Parser<'a> { + /// Matches `lit = true | false | token_lit`. + crate fn parse_lit(&mut self) -> PResult<'a, Lit> { + let diag = Some((self.span, &self.sess.span_diagnostic)); + if let Some(lit) = Lit::from_token(&self.token, self.span, diag) { + self.bump(); + return Ok(lit); + } else if self.token == token::Dot { + // Recover `.4` as `0.4`. + let recovered = self.look_ahead(1, |t| { + if let token::Literal(token::Integer(val), suf) = *t { + let next_span = self.look_ahead_span(1); + if self.span.hi() == next_span.lo() { + let sym = String::from("0.") + &val.as_str(); + let token = token::Literal(token::Float(Symbol::intern(&sym)), suf); + return Some((token, self.span.to(next_span))); + } + } + None + }); + if let Some((token, span)) = recovered { + self.diagnostic() + .struct_span_err(span, "float literals must have an integer part") + .span_suggestion( + span, + "must have an integer part", + pprust::token_to_string(&token), + Applicability::MachineApplicable, + ) + .emit(); + let diag = Some((span, &self.sess.span_diagnostic)); + if let Some(lit) = Lit::from_token(&token, span, diag) { + self.bump(); + self.bump(); + return Ok(lit); + } + } + } + + Err(self.span_fatal(self.span, &format!("unexpected token: {}", self.this_token_descr()))) + } +} + +crate fn expect_no_suffix(sp: Span, diag: &Handler, kind: &str, suffix: Option) { + match suffix { + None => {/* everything ok */} + Some(suf) => { + let text = suf.as_str(); + if text.is_empty() { + diag.span_bug(sp, "found empty literal suffix in Some") + } + let mut err = if kind == "a tuple index" && + ["i32", "u32", "isize", "usize"].contains(&text.to_string().as_str()) + { + // #59553: warn instead of reject out of hand to allow the fix to percolate + // through the ecosystem when people fix their macros + let mut err = diag.struct_span_warn( + sp, + &format!("suffixes on {} are invalid", kind), + ); + err.note(&format!( + "`{}` is *temporarily* accepted on tuple index fields as it was \ + incorrectly accepted on stable for a few releases", + text, + )); + err.help( + "on proc macros, you'll want to use `syn::Index::from` or \ + `proc_macro::Literal::*_unsuffixed` for code that will desugar \ + to tuple field access", + ); + err.note( + "for more context, see https://github.com/rust-lang/rust/issues/60210", + ); + err + } else { + diag.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) + }; + err.span_label(sp, format!("invalid suffix `{}`", text)); + err.emit(); + } + } +} + +/// Parses a string representing a raw string literal into its final form. The +/// only operation this does is convert embedded CRLF into a single LF. +fn raw_str_lit(lit: &str) -> String { + debug!("raw_str_lit: given {}", lit.escape_default()); + let mut res = String::with_capacity(lit.len()); + + let mut chars = lit.chars().peekable(); + while let Some(c) = chars.next() { + if c == '\r' { + if *chars.peek().unwrap() != '\n' { + panic!("lexer accepted bare CR"); + } + chars.next(); + res.push('\n'); + } else { + res.push(c); + } + } + + res.shrink_to_fit(); + res +} + +// check if `s` looks like i32 or u1234 etc. +fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { + s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) +} + +fn filtered_float_lit(data: Symbol, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { + debug!("filtered_float_lit: {}, {:?}", data, suffix); + let suffix = match suffix { + Some(suffix) => suffix, + None => return Some(LitKind::FloatUnsuffixed(data)), + }; + + Some(match &*suffix.as_str() { + "f32" => LitKind::Float(data, ast::FloatTy::F32), + "f64" => LitKind::Float(data, ast::FloatTy::F64), + suf => { + err!(diag, |span, diag| { + if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { + // if it looks like a width, lets try to be helpful. + let msg = format!("invalid width `{}` for float literal", &suf[1..]); + diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit() + } else { + let msg = format!("invalid suffix `{}` for float literal", suf); + diag.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("valid suffixes are `f32` and `f64`") + .emit(); + } + }); + + LitKind::FloatUnsuffixed(data) + } + }) +} +fn float_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { + debug!("float_lit: {:?}, {:?}", s, suffix); + // FIXME #2252: bounds checking float literals is deferred until trans + + // Strip underscores without allocating a new String unless necessary. + let s2; + let s = if s.chars().any(|c| c == '_') { + s2 = s.chars().filter(|&c| c != '_').collect::(); + &s2 + } else { + s + }; + + filtered_float_lit(Symbol::intern(s), suffix, diag) +} + +fn integer_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) + -> Option { + // s can only be ascii, byte indexing is fine + + // Strip underscores without allocating a new String unless necessary. + let s2; + let mut s = if s.chars().any(|c| c == '_') { + s2 = s.chars().filter(|&c| c != '_').collect::(); + &s2 + } else { + s + }; + + debug!("integer_lit: {}, {:?}", s, suffix); + + let mut base = 10; + let orig = s; + let mut ty = ast::LitIntType::Unsuffixed; + + if s.starts_with('0') && s.len() > 1 { + match s.as_bytes()[1] { + b'x' => base = 16, + b'o' => base = 8, + b'b' => base = 2, + _ => { } + } + } + + // 1f64 and 2f32 etc. are valid float literals. + if let Some(suf) = suffix { + if looks_like_width_suffix(&['f'], &suf.as_str()) { + let err = match base { + 16 => Some("hexadecimal float literal is not supported"), + 8 => Some("octal float literal is not supported"), + 2 => Some("binary float literal is not supported"), + _ => None, + }; + if let Some(err) = err { + err!(diag, |span, diag| { + diag.struct_span_err(span, err) + .span_label(span, "not supported") + .emit(); + }); + } + return filtered_float_lit(Symbol::intern(s), Some(suf), diag) + } + } + + if base != 10 { + s = &s[2..]; + } + + if let Some(suf) = suffix { + if suf.as_str().is_empty() { + err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some")); + } + ty = match &*suf.as_str() { + "isize" => ast::LitIntType::Signed(ast::IntTy::Isize), + "i8" => ast::LitIntType::Signed(ast::IntTy::I8), + "i16" => ast::LitIntType::Signed(ast::IntTy::I16), + "i32" => ast::LitIntType::Signed(ast::IntTy::I32), + "i64" => ast::LitIntType::Signed(ast::IntTy::I64), + "i128" => ast::LitIntType::Signed(ast::IntTy::I128), + "usize" => ast::LitIntType::Unsigned(ast::UintTy::Usize), + "u8" => ast::LitIntType::Unsigned(ast::UintTy::U8), + "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16), + "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32), + "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64), + "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128), + suf => { + // i and u look like widths, so lets + // give an error message along those lines + err!(diag, |span, diag| { + if looks_like_width_suffix(&['i', 'u'], suf) { + let msg = format!("invalid width `{}` for integer literal", &suf[1..]); + diag.struct_span_err(span, &msg) + .help("valid widths are 8, 16, 32, 64 and 128") + .emit(); + } else { + let msg = format!("invalid suffix `{}` for numeric literal", suf); + diag.struct_span_err(span, &msg) + .span_label(span, format!("invalid suffix `{}`", suf)) + .help("the suffix must be one of the integral types \ + (`u32`, `isize`, etc)") + .emit(); + } + }); + + ty + } + } + } + + debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ + string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); + + Some(match u128::from_str_radix(s, base) { + Ok(r) => LitKind::Int(r, ty), + Err(_) => { + // small bases are lexed as if they were base 10, e.g, the string + // might be `0b10201`. This will cause the conversion above to fail, + // but these cases have errors in the lexer: we don't want to emit + // two errors, and we especially don't want to emit this error since + // it isn't necessarily true. + let already_errored = base < 10 && + s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); + + if !already_errored { + err!(diag, |span, diag| diag.span_err(span, "int literal is too large")); + } + LitKind::Int(0, ty) + } + }) +} diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index be44b964ba5a..0611c1d9b42a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -5,7 +5,6 @@ use crate::early_buffered_lints::{BufferedEarlyLint, BufferedEarlyLintId}; use crate::source_map::{SourceMap, FilePathMapping}; use crate::feature_gate::UnstableFeatures; use crate::parse::parser::Parser; -use crate::symbol::Symbol; use crate::syntax::parse::parser::emit_unclosed_delims; use crate::tokenstream::{TokenStream, TokenTree}; use crate::diagnostics::plugin::ErrorMap; @@ -14,7 +13,6 @@ use crate::print::pprust::token_to_string; use errors::{Applicability, FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder}; use rustc_data_structures::sync::{Lrc, Lock}; use syntax_pos::{Span, SourceFile, FileName, MultiSpan}; -use log::debug; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::borrow::Cow; @@ -25,18 +23,15 @@ pub type PResult<'a, T> = Result>; #[macro_use] pub mod parser; - +pub mod attr; pub mod lexer; pub mod token; -pub mod attr; -pub mod diagnostics; -pub mod classify; - -pub(crate) mod unescape; -use unescape::{unescape_str, unescape_char, unescape_byte_str, unescape_byte}; - -pub(crate) mod unescape_error_reporting; +crate mod classify; +crate mod diagnostics; +crate mod literal; +crate mod unescape; +crate mod unescape_error_reporting; /// Info about a parsing session. pub struct ParseSess { @@ -295,22 +290,22 @@ pub fn source_file_to_stream( } /// Given a source file, produces a sequence of token trees. Returns any buffered errors from -/// parsing the token tream. +/// parsing the token stream. pub fn maybe_file_to_stream( sess: &ParseSess, source_file: Lrc, override_span: Option, ) -> Result<(TokenStream, Vec), Vec> { - let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?; - srdr.real_token(); + let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?; + let (token_trees, unmatched_braces) = srdr.into_token_trees(); - match srdr.parse_all_token_trees() { - Ok(stream) => Ok((stream, srdr.unmatched_braces)), + match token_trees { + Ok(stream) => Ok((stream, unmatched_braces)), Err(err) => { let mut buffer = Vec::with_capacity(1); err.buffer(&mut buffer); // Not using `emit_unclosed_delims` to use `db.buffer` - for unmatched in srdr.unmatched_braces { + for unmatched in unmatched_braces { let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!( "incorrect close delimiter: `{}`", token_to_string(&token::Token::CloseDelim(unmatched.found_delim)), @@ -334,284 +329,6 @@ pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> { Parser::new(sess, stream, None, true, false) } -/// Parses a string representing a raw string literal into its final form. The -/// only operation this does is convert embedded CRLF into a single LF. -fn raw_str_lit(lit: &str) -> String { - debug!("raw_str_lit: given {}", lit.escape_default()); - let mut res = String::with_capacity(lit.len()); - - let mut chars = lit.chars().peekable(); - while let Some(c) = chars.next() { - if c == '\r' { - if *chars.peek().unwrap() != '\n' { - panic!("lexer accepted bare CR"); - } - chars.next(); - res.push('\n'); - } else { - res.push(c); - } - } - - res.shrink_to_fit(); - res -} - -// check if `s` looks like i32 or u1234 etc. -fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { - s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) -} - -macro_rules! err { - ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => { - match $opt_diag { - Some(($span, $diag)) => { $($body)* } - None => return None, - } - } -} - -crate fn lit_token(lit: token::Lit, suf: Option, diag: Option<(Span, &Handler)>) - -> (bool /* suffix illegal? */, Option) { - use ast::LitKind; - - match lit { - token::Byte(i) => { - let lit_kind = match unescape_byte(&i.as_str()) { - Ok(c) => LitKind::Byte(c), - Err(_) => LitKind::Err(i), - }; - (true, Some(lit_kind)) - }, - token::Char(i) => { - let lit_kind = match unescape_char(&i.as_str()) { - Ok(c) => LitKind::Char(c), - Err(_) => LitKind::Err(i), - }; - (true, Some(lit_kind)) - }, - token::Err(i) => (true, Some(LitKind::Err(i))), - - // There are some valid suffixes for integer and float literals, - // so all the handling is done internally. - token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)), - token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)), - - token::Str_(mut sym) => { - // If there are no characters requiring special treatment we can - // reuse the symbol from the Token. Otherwise, we must generate a - // new symbol because the string in the LitKind is different to the - // string in the Token. - let mut has_error = false; - let s = &sym.as_str(); - if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') { - let mut buf = String::with_capacity(s.len()); - unescape_str(s, &mut |_, unescaped_char| { - match unescaped_char { - Ok(c) => buf.push(c), - Err(_) => has_error = true, - } - }); - if has_error { - return (true, Some(LitKind::Err(sym))); - } - sym = Symbol::intern(&buf) - } - - (true, Some(LitKind::Str(sym, ast::StrStyle::Cooked))) - } - token::StrRaw(mut sym, n) => { - // Ditto. - let s = &sym.as_str(); - if s.contains('\r') { - sym = Symbol::intern(&raw_str_lit(s)); - } - (true, Some(LitKind::Str(sym, ast::StrStyle::Raw(n)))) - } - token::ByteStr(i) => { - let s = &i.as_str(); - let mut buf = Vec::with_capacity(s.len()); - let mut has_error = false; - unescape_byte_str(s, &mut |_, unescaped_byte| { - match unescaped_byte { - Ok(c) => buf.push(c), - Err(_) => has_error = true, - } - }); - if has_error { - return (true, Some(LitKind::Err(i))); - } - buf.shrink_to_fit(); - (true, Some(LitKind::ByteStr(Lrc::new(buf)))) - } - token::ByteStrRaw(i, _) => { - (true, Some(LitKind::ByteStr(Lrc::new(i.to_string().into_bytes())))) - } - } -} - -fn filtered_float_lit(data: Symbol, suffix: Option, diag: Option<(Span, &Handler)>) - -> Option { - debug!("filtered_float_lit: {}, {:?}", data, suffix); - let suffix = match suffix { - Some(suffix) => suffix, - None => return Some(ast::LitKind::FloatUnsuffixed(data)), - }; - - Some(match &*suffix.as_str() { - "f32" => ast::LitKind::Float(data, ast::FloatTy::F32), - "f64" => ast::LitKind::Float(data, ast::FloatTy::F64), - suf => { - err!(diag, |span, diag| { - if suf.len() >= 2 && looks_like_width_suffix(&['f'], suf) { - // if it looks like a width, lets try to be helpful. - let msg = format!("invalid width `{}` for float literal", &suf[1..]); - diag.struct_span_err(span, &msg).help("valid widths are 32 and 64").emit() - } else { - let msg = format!("invalid suffix `{}` for float literal", suf); - diag.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{}`", suf)) - .help("valid suffixes are `f32` and `f64`") - .emit(); - } - }); - - ast::LitKind::FloatUnsuffixed(data) - } - }) -} -fn float_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) - -> Option { - debug!("float_lit: {:?}, {:?}", s, suffix); - // FIXME #2252: bounds checking float literals is deferred until trans - - // Strip underscores without allocating a new String unless necessary. - let s2; - let s = if s.chars().any(|c| c == '_') { - s2 = s.chars().filter(|&c| c != '_').collect::(); - &s2 - } else { - s - }; - - filtered_float_lit(Symbol::intern(s), suffix, diag) -} - -fn integer_lit(s: &str, suffix: Option, diag: Option<(Span, &Handler)>) - -> Option { - // s can only be ascii, byte indexing is fine - - // Strip underscores without allocating a new String unless necessary. - let s2; - let mut s = if s.chars().any(|c| c == '_') { - s2 = s.chars().filter(|&c| c != '_').collect::(); - &s2 - } else { - s - }; - - debug!("integer_lit: {}, {:?}", s, suffix); - - let mut base = 10; - let orig = s; - let mut ty = ast::LitIntType::Unsuffixed; - - if s.starts_with('0') && s.len() > 1 { - match s.as_bytes()[1] { - b'x' => base = 16, - b'o' => base = 8, - b'b' => base = 2, - _ => { } - } - } - - // 1f64 and 2f32 etc. are valid float literals. - if let Some(suf) = suffix { - if looks_like_width_suffix(&['f'], &suf.as_str()) { - let err = match base { - 16 => Some("hexadecimal float literal is not supported"), - 8 => Some("octal float literal is not supported"), - 2 => Some("binary float literal is not supported"), - _ => None, - }; - if let Some(err) = err { - err!(diag, |span, diag| { - diag.struct_span_err(span, err) - .span_label(span, "not supported") - .emit(); - }); - } - return filtered_float_lit(Symbol::intern(s), Some(suf), diag) - } - } - - if base != 10 { - s = &s[2..]; - } - - if let Some(suf) = suffix { - if suf.as_str().is_empty() { - err!(diag, |span, diag| diag.span_bug(span, "found empty literal suffix in Some")); - } - ty = match &*suf.as_str() { - "isize" => ast::LitIntType::Signed(ast::IntTy::Isize), - "i8" => ast::LitIntType::Signed(ast::IntTy::I8), - "i16" => ast::LitIntType::Signed(ast::IntTy::I16), - "i32" => ast::LitIntType::Signed(ast::IntTy::I32), - "i64" => ast::LitIntType::Signed(ast::IntTy::I64), - "i128" => ast::LitIntType::Signed(ast::IntTy::I128), - "usize" => ast::LitIntType::Unsigned(ast::UintTy::Usize), - "u8" => ast::LitIntType::Unsigned(ast::UintTy::U8), - "u16" => ast::LitIntType::Unsigned(ast::UintTy::U16), - "u32" => ast::LitIntType::Unsigned(ast::UintTy::U32), - "u64" => ast::LitIntType::Unsigned(ast::UintTy::U64), - "u128" => ast::LitIntType::Unsigned(ast::UintTy::U128), - suf => { - // i and u look like widths, so lets - // give an error message along those lines - err!(diag, |span, diag| { - if looks_like_width_suffix(&['i', 'u'], suf) { - let msg = format!("invalid width `{}` for integer literal", &suf[1..]); - diag.struct_span_err(span, &msg) - .help("valid widths are 8, 16, 32, 64 and 128") - .emit(); - } else { - let msg = format!("invalid suffix `{}` for numeric literal", suf); - diag.struct_span_err(span, &msg) - .span_label(span, format!("invalid suffix `{}`", suf)) - .help("the suffix must be one of the integral types \ - (`u32`, `isize`, etc)") - .emit(); - } - }); - - ty - } - } - } - - debug!("integer_lit: the type is {:?}, base {:?}, the new string is {:?}, the original \ - string was {:?}, the original suffix was {:?}", ty, base, s, orig, suffix); - - Some(match u128::from_str_radix(s, base) { - Ok(r) => ast::LitKind::Int(r, ty), - Err(_) => { - // small bases are lexed as if they were base 10, e.g, the string - // might be `0b10201`. This will cause the conversion above to fail, - // but these cases have errors in the lexer: we don't want to emit - // two errors, and we especially don't want to emit this error since - // it isn't necessarily true. - let already_errored = base < 10 && - s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base)); - - if !already_errored { - err!(diag, |span, diag| diag.span_err(span, "int literal is too large")); - } - ast::LitKind::Int(0, ty) - } - }) -} - /// A sequence separator. pub struct SeqSep { /// The seperator token. @@ -674,6 +391,8 @@ mod tests { #[test] fn string_to_tts_macro () { with_globals(|| { + use crate::symbol::sym; + let tts: Vec<_> = string_to_stream("macro_rules! zip (($a)=>($a))".to_string()).trees().collect(); let tts: &[TokenTree] = &tts[..]; @@ -686,8 +405,8 @@ mod tests { Some(&TokenTree::Token(_, token::Ident(name_zip, false))), Some(&TokenTree::Delimited(_, macro_delim, ref macro_tts)), ) - if name_macro_rules.name == "macro_rules" - && name_zip.name == "zip" => { + if name_macro_rules.name == sym::macro_rules + && name_zip.name.as_str() == "zip" => { let tts = ¯o_tts.trees().collect::>(); match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) { ( @@ -704,7 +423,7 @@ mod tests { Some(&TokenTree::Token(_, token::Dollar)), Some(&TokenTree::Token(_, token::Ident(ident, false))), ) - if first_delim == token::Paren && ident.name == "a" => {}, + if first_delim == token::Paren && ident.name.as_str() == "a" => {}, _ => panic!("value 3: {:?} {:?}", first_delim, first_tts), } let tts = &second_tts.trees().collect::>(); @@ -714,7 +433,7 @@ mod tests { Some(&TokenTree::Token(_, token::Dollar)), Some(&TokenTree::Token(_, token::Ident(ident, false))), ) - if second_delim == token::Paren && ident.name == "a" => {}, + if second_delim == token::Paren && ident.name.as_str() == "a" => {}, _ => panic!("value 4: {:?} {:?}", second_delim, second_tts), } }, @@ -858,20 +577,22 @@ mod tests { #[test] fn crlf_doc_comments() { with_globals(|| { + use crate::symbol::sym; + let sess = ParseSess::new(FilePathMapping::empty()); let name_1 = FileName::Custom("crlf_source_1".to_string()); let source = "/// doc comment\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_1, source, &sess) .unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); - assert_eq!(doc, "/// doc comment"); + let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + assert_eq!(doc.as_str(), "/// doc comment"); let name_2 = FileName::Custom("crlf_source_2".to_string()); let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_2, source, &sess) .unwrap().unwrap(); - let docs = item.attrs.iter().filter(|a| a.path == "doc") + let docs = item.attrs.iter().filter(|a| a.path == sym::doc) .map(|a| a.value_str().unwrap().to_string()).collect::>(); let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()]; assert_eq!(&docs[..], b); @@ -879,8 +600,8 @@ mod tests { let name_3 = FileName::Custom("clrf_source_3".to_string()); let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string(); let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap(); - let doc = first_attr_value_str_by_name(&item.attrs, "doc").unwrap(); - assert_eq!(doc, "/** doc comment\n * with CRLF */"); + let doc = first_attr_value_str_by_name(&item.attrs, sym::doc).unwrap(); + assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */"); }); } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d97d1e2f0f4e..24d120376def 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -15,7 +15,7 @@ use crate::ast::{ForeignItem, ForeignItemKind, FunctionRetTy}; use crate::ast::{GenericParam, GenericParamKind}; use crate::ast::GenericArg; use crate::ast::{Ident, ImplItem, IsAsync, IsAuto, Item, ItemKind}; -use crate::ast::{Label, Lifetime, Lit, LitKind}; +use crate::ast::{Label, Lifetime}; use crate::ast::{Local, LocalSource}; use crate::ast::MacStmtStyle; use crate::ast::{Mac, Mac_, MacDelimiter}; @@ -35,7 +35,7 @@ use crate::ast::{RangeEnd, RangeSyntax}; use crate::{ast, attr}; use crate::ext::base::DummyResult; use crate::source_map::{self, SourceMap, Spanned, respan}; -use crate::parse::{self, SeqSep, classify, token}; +use crate::parse::{SeqSep, classify, literal, token}; use crate::parse::lexer::{TokenAndSpan, UnmatchedBrace}; use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration}; use crate::parse::token::DelimToken; @@ -46,7 +46,7 @@ use crate::ptr::P; use crate::parse::PResult; use crate::ThinVec; use crate::tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint}; -use crate::symbol::{Symbol, keywords}; +use crate::symbol::{keywords, sym, Symbol}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId, FatalError}; use rustc_target::spec::abi::{self, Abi}; @@ -104,14 +104,14 @@ pub enum PathStyle { } #[derive(Clone, Copy, PartialEq, Debug)] -enum SemiColonMode { +crate enum SemiColonMode { Break, Ignore, Comma, } #[derive(Clone, Copy, PartialEq, Debug)] -enum BlockMode { +crate enum BlockMode { Break, Ignore, } @@ -352,7 +352,7 @@ impl TokenCursor { let body = TokenTree::Delimited( delim_span, token::Bracket, - [TokenTree::Token(sp, token::Ident(ast::Ident::from_str("doc"), false)), + [TokenTree::Token(sp, token::Ident(ast::Ident::with_empty_ctxt(sym::doc), false)), TokenTree::Token(sp, token::Eq), TokenTree::Token(sp, token::Literal( token::StrRaw(Symbol::intern(&stripped), num_of_hashes), None)) @@ -389,7 +389,7 @@ crate enum TokenType { } impl TokenType { - fn to_string(&self) -> String { + crate fn to_string(&self) -> String { match *self { TokenType::Token(ref t) => format!("`{}`", pprust::token_to_string(t)), TokenType::Keyword(kw) => format!("`{}`", kw.name()), @@ -613,7 +613,7 @@ impl<'a> Parser<'a> { }) } - fn this_token_descr(&self) -> String { + crate fn this_token_descr(&self) -> String { if let Some(prefix) = self.token_descr() { format!("{} `{}`", prefix, self.this_token_to_string()) } else { @@ -621,11 +621,6 @@ impl<'a> Parser<'a> { } } - fn unexpected_last(&self, t: &token::Token) -> PResult<'a, T> { - let token_str = pprust::token_to_string(t); - Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str))) - } - crate fn unexpected(&mut self) -> PResult<'a, T> { match self.expect_one_of(&[], &[]) { Err(e) => Err(e), @@ -678,56 +673,6 @@ impl<'a> Parser<'a> { } } - fn recover_closing_delimiter( - &mut self, - tokens: &[token::Token], - mut err: DiagnosticBuilder<'a>, - ) -> PResult<'a, bool> { - let mut pos = None; - // we want to use the last closing delim that would apply - for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { - if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) - && Some(self.span) > unmatched.unclosed_span - { - pos = Some(i); - } - } - match pos { - Some(pos) => { - // Recover and assume that the detected unclosed delimiter was meant for - // this location. Emit the diagnostic and act as if the delimiter was - // present for the parser's sake. - - // Don't attempt to recover from this unclosed delimiter more than once. - let unmatched = self.unclosed_delims.remove(pos); - let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); - - // We want to suggest the inclusion of the closing delimiter where it makes - // the most sense, which is immediately after the last token: - // - // {foo(bar {}} - // - ^ - // | | - // | help: `)` may belong here (FIXME: #58270) - // | - // unclosed delimiter - if let Some(sp) = unmatched.unclosed_span { - err.span_label(sp, "unclosed delimiter"); - } - err.span_suggestion_short( - self.sess.source_map().next_point(self.prev_span), - &format!("{} may belong here", delim.to_string()), - delim.to_string(), - Applicability::MaybeIncorrect, - ); - err.emit(); - self.expected_tokens.clear(); // reduce errors - Ok(true) - } - _ => Err(err), - } - } - /// Expect next token to be edible or inedible token. If edible, /// then consume it; if inedible, then return without consuming /// anything. Signal a fatal error if next token is unexpected. @@ -1109,43 +1054,7 @@ impl<'a> Parser<'a> { } fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { - match suffix { - None => {/* everything ok */} - Some(suf) => { - let text = suf.as_str(); - if text.is_empty() { - self.span_bug(sp, "found empty literal suffix in Some") - } - let mut err = if kind == "a tuple index" && - ["i32", "u32", "isize", "usize"].contains(&text.to_string().as_str()) - { - // #59553: warn instead of reject out of hand to allow the fix to percolate - // through the ecosystem when people fix their macros - let mut err = self.struct_span_warn( - sp, - &format!("suffixes on {} are invalid", kind), - ); - err.note(&format!( - "`{}` is *temporarily* accepted on tuple index fields as it was \ - incorrectly accepted on stable for a few releases", - text, - )); - err.help( - "on proc macros, you'll want to use `syn::Index::from` or \ - `proc_macro::Literal::*_unsuffixed` for code that will desugar \ - to tuple field access", - ); - err.note( - "for more context, see https://github.com/rust-lang/rust/issues/60210", - ); - err - } else { - self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind)) - }; - err.span_label(sp, format!("invalid suffix `{}`", text)); - err.emit(); - } - } + literal::expect_no_suffix(sp, &self.sess.span_diagnostic, kind, suffix) } /// Attempts to consume a `<`. If `<<` is seen, replaces it with a single @@ -1423,7 +1332,7 @@ impl<'a> Parser<'a> { }) } - fn look_ahead_span(&self, dist: usize) -> Span { + crate fn look_ahead_span(&self, dist: usize) -> Span { if dist == 0 { return self.span } @@ -1452,9 +1361,6 @@ impl<'a> Parser<'a> { crate fn struct_span_err>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { self.sess.span_diagnostic.struct_span_err(sp, m) } - fn struct_span_warn>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> { - self.sess.span_diagnostic.struct_span_warn(sp, m) - } crate fn span_bug>(&self, sp: S, m: &str) -> ! { self.sess.span_diagnostic.span_bug(sp, m) } @@ -1877,7 +1783,7 @@ impl<'a> Parser<'a> { Ok(MutTy { ty: t, mutbl: mutbl }) } - fn is_named_argument(&mut self) -> bool { + fn is_named_argument(&self) -> bool { let offset = match self.token { token::Interpolated(ref nt) => match **nt { token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), @@ -1925,8 +1831,6 @@ impl<'a> Parser<'a> { /// This version of parse arg doesn't necessarily require identifier names. fn parse_arg_general(&mut self, require_name: bool, is_trait_item: bool, allow_c_variadic: bool) -> PResult<'a, Arg> { - maybe_whole!(self, NtArg, |x| x); - if let Ok(Some(_)) = self.parse_self_arg() { let mut err = self.struct_span_err(self.prev_span, "unexpected `self` argument in function"); @@ -2069,88 +1973,6 @@ impl<'a> Parser<'a> { } } - /// Matches `token_lit = LIT_INTEGER | ...`. - fn parse_lit_token(&mut self) -> PResult<'a, LitKind> { - let out = match self.token { - token::Interpolated(ref nt) => match **nt { - token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node { - ExprKind::Lit(ref lit) => { lit.node.clone() } - _ => { return self.unexpected_last(&self.token); } - }, - _ => { return self.unexpected_last(&self.token); } - }, - token::Literal(lit, suf) => { - let diag = Some((self.span, &self.sess.span_diagnostic)); - let (suffix_illegal, result) = parse::lit_token(lit, suf, diag); - - if suffix_illegal { - let sp = self.span; - self.expect_no_suffix(sp, &format!("a {}", lit.literal_name()), suf) - } - - result.unwrap() - } - token::Dot if self.look_ahead(1, |t| match t { - token::Literal(parse::token::Lit::Integer(_) , _) => true, - _ => false, - }) => { // recover from `let x = .4;` - let lo = self.span; - self.bump(); - if let token::Literal( - parse::token::Lit::Integer(val), - suffix, - ) = self.token { - let suffix = suffix.and_then(|s| { - let s = s.as_str(); - if s == "f32" { - Some("f32") - } else if s == "f64" { - Some("f64") - } else { - None - } - }).unwrap_or(""); - self.bump(); - let sp = lo.to(self.prev_span); - let mut err = self.diagnostic() - .struct_span_err(sp, "float literals must have an integer part"); - err.span_suggestion( - sp, - "must have an integer part", - format!("0.{}{}", val, suffix), - Applicability::MachineApplicable, - ); - err.emit(); - return Ok(match suffix { - "f32" => ast::LitKind::Float(val, ast::FloatTy::F32), - "f64" => ast::LitKind::Float(val, ast::FloatTy::F64), - _ => ast::LitKind::FloatUnsuffixed(val), - }); - } else { - unreachable!(); - }; - } - _ => { return self.unexpected_last(&self.token); } - }; - - self.bump(); - Ok(out) - } - - /// Matches `lit = true | false | token_lit`. - crate fn parse_lit(&mut self) -> PResult<'a, Lit> { - let lo = self.span; - let lit = if self.eat_keyword(keywords::True) { - LitKind::Bool(true) - } else if self.eat_keyword(keywords::False) { - LitKind::Bool(false) - } else { - let lit = self.parse_lit_token()?; - lit - }; - Ok(source_map::Spanned { node: lit, span: lo.to(self.prev_span) }) - } - /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); @@ -2471,27 +2293,27 @@ impl<'a> Parser<'a> { }) } - fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec) -> P { + crate fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec) -> P { P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID }) } - fn mk_unary(&mut self, unop: ast::UnOp, expr: P) -> ast::ExprKind { + fn mk_unary(&self, unop: ast::UnOp, expr: P) -> ast::ExprKind { ExprKind::Unary(unop, expr) } - fn mk_binary(&mut self, binop: ast::BinOp, lhs: P, rhs: P) -> ast::ExprKind { + fn mk_binary(&self, binop: ast::BinOp, lhs: P, rhs: P) -> ast::ExprKind { ExprKind::Binary(binop, lhs, rhs) } - fn mk_call(&mut self, f: P, args: Vec>) -> ast::ExprKind { + fn mk_call(&self, f: P, args: Vec>) -> ast::ExprKind { ExprKind::Call(f, args) } - fn mk_index(&mut self, expr: P, idx: P) -> ast::ExprKind { + fn mk_index(&self, expr: P, idx: P) -> ast::ExprKind { ExprKind::Index(expr, idx) } - fn mk_range(&mut self, + fn mk_range(&self, start: Option>, end: Option>, limits: RangeLimits) @@ -2503,7 +2325,7 @@ impl<'a> Parser<'a> { } } - fn mk_assign_op(&mut self, binop: ast::BinOp, + fn mk_assign_op(&self, binop: ast::BinOp, lhs: P, rhs: P) -> ast::ExprKind { ExprKind::AssignOp(binop, lhs, rhs) } @@ -2643,13 +2465,12 @@ impl<'a> Parser<'a> { hi = path.span; return Ok(self.mk_expr(lo.to(hi), ExprKind::Path(Some(qself), path), attrs)); } - if self.span.rust_2018() && self.check_keyword(keywords::Async) - { - if self.is_async_block() { // check for `async {` and `async move {` - return self.parse_async_block(attrs); + if self.span.rust_2018() && self.check_keyword(keywords::Async) { + return if self.is_async_block() { // check for `async {` and `async move {` + self.parse_async_block(attrs) } else { - return self.parse_lambda_expr(attrs); - } + self.parse_lambda_expr(attrs) + }; } if self.check_keyword(keywords::Move) || self.check_keyword(keywords::Static) { return self.parse_lambda_expr(attrs); @@ -2758,13 +2579,9 @@ impl<'a> Parser<'a> { db.note("variable declaration using `let` is a statement"); return Err(db); } else if self.span.rust_2018() && self.eat_keyword(keywords::Await) { - // FIXME: remove this branch when `await!` is no longer supported - // https://github.com/rust-lang/rust/issues/60610 - self.expect(&token::Not)?; - self.expect(&token::OpenDelim(token::Paren))?; - let expr = self.parse_expr()?; - self.expect(&token::CloseDelim(token::Paren))?; - ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr); + let (await_hi, e_kind) = self.parse_await_macro_or_alt(lo, self.prev_span)?; + hi = await_hi; + ex = e_kind; } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Expr)?; @@ -2829,6 +2646,31 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr, true) } + /// Parse `await!()` calls, or alternatively recover from incorrect but reasonable + /// alternative syntaxes `await `, `await? `, `await()` and + /// `await { }`. + fn parse_await_macro_or_alt( + &mut self, + lo: Span, + await_sp: Span, + ) -> PResult<'a, (Span, ExprKind)> { + if self.token == token::Not { + // Handle correct `await!()`. + // FIXME: make this an error when `await!` is no longer supported + // https://github.com/rust-lang/rust/issues/60610 + self.expect(&token::Not)?; + self.expect(&token::OpenDelim(token::Paren))?; + let expr = self.parse_expr().map_err(|mut err| { + err.span_label(await_sp, "while parsing this await macro call"); + err + })?; + self.expect(&token::CloseDelim(token::Paren))?; + Ok((self.prev_span, ExprKind::Await(ast::AwaitOrigin::MacroLike, expr))) + } else { // Handle `await `. + self.parse_incorrect_await_syntax(lo, await_sp) + } + } + fn maybe_parse_struct_expr( &mut self, lo: Span, @@ -2977,10 +2819,13 @@ impl<'a> Parser<'a> { } /// Parses a block or unsafe block. - fn parse_block_expr(&mut self, opt_label: Option