diff --git a/.mailmap b/.mailmap index 120d1f1457e65..63a49cd413287 100644 --- a/.mailmap +++ b/.mailmap @@ -53,7 +53,8 @@ Chris C Cerami Chris C Cerami Chris Thorn Chris Thorn Chris Vittal Christopher Vittal -Christian Poveda +Christian Poveda +Christian Poveda Clark Gaebel Clinton Ryan Corey Richardson Elaine "See More" Nemo @@ -79,7 +80,9 @@ Eric Holk Eric Holmes Eric Reed Erick Tryzelaar -Esteban Küber +Esteban Küber +Esteban Küber +Esteban Küber Evgeny Sologubov Falco Hirschenberger Felix S. Klock II Felix S Klock II @@ -146,12 +149,14 @@ NAKASHIMA, Makoto NAKASHIMA, Makoto Marcell Pardavi Margaret Meyerhofer -Mark Simulacrum +Mark Rousskov Mark Sinclair 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 @@ -226,7 +231,7 @@ Tim Joseph Dumol Torsten Weber Ty Overby Ulrik Sverdrup bluss -Ulrik Sverdrup bluss bluss +Ulrik Sverdrup bluss Ulrik Sverdrup Ulrik Sverdrup Vadim Petrochenkov Vadim Petrochenkov petrochenkov diff --git a/Cargo.lock b/Cargo.lock index 7823c377b2ad8..982070a243ee5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,7 +17,7 @@ dependencies = [ name = "alloc" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (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)", @@ -29,7 +29,7 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "html5ever 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -115,7 +115,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (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", ] @@ -169,14 +169,13 @@ dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (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)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.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)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -192,7 +191,6 @@ name = "build-manifest" version = "0.1.0" dependencies = [ "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)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -266,14 +264,15 @@ dependencies = [ "ignore 0.4.6 (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.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "libgit2-sys 0.7.11 (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)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "opener 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "proptest 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -373,13 +372,12 @@ dependencies = [ "clippy_lints 0.0.212", "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.2.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)", "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]] @@ -393,14 +391,13 @@ dependencies = [ "cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", @@ -449,7 +446,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", @@ -463,15 +460,14 @@ 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.18 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (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)", "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)", "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)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -484,7 +480,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (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.18 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (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)", @@ -591,7 +587,7 @@ 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.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (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)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -605,7 +601,7 @@ 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)", - "lazy_static 1.2.0 (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)", ] @@ -735,7 +731,7 @@ name = "dlmalloc" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (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", ] @@ -750,7 +746,7 @@ name = "elasticlunr-rs" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.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)", "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)", @@ -901,7 +897,7 @@ name = "fortanix-sgx-abi" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -974,7 +970,7 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1031,7 +1027,7 @@ name = "handlebars" version = "0.32.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.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)", "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)", @@ -1046,7 +1042,7 @@ name = "handlebars" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.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)", "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)", @@ -1062,7 +1058,7 @@ name = "hashbrown" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-alloc 1.0.0", "rustc-std-workspace-core 1.0.0", ] @@ -1142,7 +1138,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)", - "lazy_static 1.2.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)", "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)", @@ -1168,7 +1164,7 @@ dependencies = [ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1264,7 +1260,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1353,7 +1349,7 @@ name = "log_settings" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1440,7 +1436,7 @@ dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.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)", "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)", @@ -1468,7 +1464,7 @@ dependencies = [ "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.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)", "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)", @@ -1688,11 +1684,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "opener" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1704,7 +1698,7 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (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)", "openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1765,7 +1759,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ - "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (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)", ] @@ -1775,7 +1769,7 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc 0.0.0", - "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (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", @@ -1960,7 +1954,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1972,7 +1966,7 @@ dependencies = [ "bit-set 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1989,7 +1983,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2008,7 +2002,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2046,7 +2040,7 @@ dependencies = [ "derive_more 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.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)", "rls-span 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-syntax 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2142,7 +2136,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (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)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2244,7 +2238,7 @@ dependencies = [ "home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.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)", "lsp-codec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "lsp-types 0.57.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2350,7 +2344,7 @@ dependencies = [ "fmt_macros 0.0.0", "graphviz 0.0.0", "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2403,7 +2397,7 @@ dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "ena 0.11.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.2.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)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-ap-graphviz 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2485,7 +2479,7 @@ name = "rustc-demangle" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "compiler_builtins 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-std-workspace-core 1.0.0", ] @@ -2533,7 +2527,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (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)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2544,7 +2538,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (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)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2613,7 +2607,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2703,7 +2697,7 @@ dependencies = [ "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", "jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2843,7 +2837,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2905,7 +2899,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -2957,6 +2951,7 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_metadata 0.0.0", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -3021,7 +3016,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -3094,10 +3089,10 @@ dependencies = [ "dirs 1.0.4 (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)", - "getopts 0.2.18 (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)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "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)", "rustc-ap-rustc_target 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3143,7 +3138,7 @@ name = "schannel" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3290,7 +3285,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (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)", @@ -3313,7 +3308,7 @@ name = "string_cache" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3404,7 +3399,7 @@ name = "syntax" version = "0.0.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.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)", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -3521,7 +3516,7 @@ dependencies = [ name = "test" version = "0.0.0" dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "term 0.0.0", ] @@ -3531,7 +3526,7 @@ name = "tester" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3549,7 +3544,7 @@ name = "thread_local" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3558,7 +3553,6 @@ version = "0.1.0" dependencies = [ "regex 1.1.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)", "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3664,7 +3658,7 @@ 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)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.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)", "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3783,7 +3777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.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 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3795,7 +3789,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" 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.2.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)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3882,7 +3876,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.10 (registry+https://github.com/rust-lang/crates.io-index)", + "compiler_builtins 0.1.12 (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)", ] @@ -4078,7 +4072,7 @@ 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.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4ada53ac629568219809178f988ca2aac9889e9a847379588c097d30ce185145" +"checksum compiler_builtins 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6549720ae78db799196d4af8f719facb4c7946710b4b64148482553e54b56d15" "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" @@ -4131,7 +4125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum fwdansi 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34dd4c507af68d37ffef962063dfa1944ce0dd4d5b82043dbab1dabe088610c3" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "72327b15c228bfe31f1390f93dd5e9279587f0463836393c9df719ce62a3e450" "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" @@ -4160,7 +4154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum jsonrpc-core 10.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a5152c3fda235dfd68341b3edf4121bc4428642c93acbd6de88c26bf95fc5d7" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" "checksum libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)" = "c6785aa7dd976f5fbf3b71cfd9cd49d7f783c1ff565a858d71031c6c313aa5c6" "checksum libgit2-sys 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)" = "48441cb35dc255da8ae72825689a95368bf510659ae1ad55dc4aa88cb1789bf1" @@ -4201,7 +4195,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum opener 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "04b1d6b086d9b3009550f9b6f81b10ad9428cf14f404b8e1a3a06f6f012c8ec9" +"checksum opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "998c59e83d9474c01127a96e023b7a04bb061dd286bf8bb939d31dc8d31a7448" "checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" "checksum openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)" = "26bb632127731bf4ac49bf86a5dde12d2ca0918c2234fc39d79d4da2ccbc6da7" diff --git a/appveyor.yml b/appveyor.yml index be960dc13af57..dffd79c56e48a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -158,9 +158,9 @@ install: # Note that the LLVM installer is an NSIS installer # # Original downloaded here came from - # http://releases.llvm.org/7.0.0/LLVM-7.0.0-win64.exe - - if NOT defined MINGW_URL appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/LLVM-7.0.0-win64.exe - - if NOT defined MINGW_URL .\LLVM-7.0.0-win64.exe /S /NCRC /D=C:\clang-rust + # http://releases.llvm.org/8.0.0/LLVM-8.0.0-win64.exe + - if NOT defined MINGW_URL appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/LLVM-8.0.0-win64.exe + - if NOT defined MINGW_URL .\LLVM-8.0.0-win64.exe /S /NCRC /D=C:\clang-rust - if NOT defined MINGW_URL set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=C:\clang-rust\bin\clang-cl.exe # Here we do a pretty heinous thing which is to mangle the MinGW installation diff --git a/config.toml.example b/config.toml.example index 8b2153cd2e63c..556625b531d1c 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/Cargo.toml b/src/bootstrap/Cargo.toml index 9a410c339bf5f..589ee9276a5a3 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -39,14 +39,13 @@ build_helper = { path = "../build_helper" } cmake = "0.1.38" filetime = "0.2" num_cpus = "1.0" -getopts = "0.2.18" +getopts = "0.2.19" cc = "1.0.35" libc = "0.2" -serde = "1.0.8" -serde_derive = "1.0.8" +serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" toml = "0.4" -lazy_static = "0.2" +lazy_static = "1.3.0" time = "0.1" petgraph = "0.4.13" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index c84eb6476e087..51663e9316982 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -11,6 +11,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{Duration, Instant}; +use build_helper::t; + use crate::cache::{Cache, Interned, INTERNER}; use crate::check; use crate::compile; @@ -1308,6 +1310,8 @@ mod __test { use crate::config::Config; use std::thread; + use pretty_assertions::assert_eq; + fn configure(host: &[&str], target: &[&str]) -> Config { let mut config = Config::default_opts(); // don't save toolstates diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index 239959682cb00..f137a7b8cc281 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -13,6 +13,8 @@ use std::path::{Path, PathBuf}; use std::sync::Mutex; use std::cmp::{PartialOrd, Ord, Ordering}; +use lazy_static::lazy_static; + use crate::builder::Step; pub struct Interned(usize, PhantomData<*const T>); diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index b52e1a7b0e681..73be8bfed8e88 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -9,6 +9,8 @@ use std::fs; use std::io::{self, ErrorKind}; use std::path::Path; +use build_helper::t; + use crate::Build; pub fn clean(build: &Build, all: bool) { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 66443d472d334..9c4e856f0b88b 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -15,8 +15,9 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio, exit}; use std::str; -use build_helper::{output, mtime, up_to_date}; +use build_helper::{output, mtime, t, up_to_date}; use filetime::FileTime; +use serde::Deserialize; use serde_json; use crate::dist; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 0c31c41ceda86..b1d009a674066 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -10,8 +10,10 @@ use std::path::{Path, PathBuf}; use std::process; use std::cmp; +use build_helper::t; use num_cpus; use toml; +use serde::Deserialize; use crate::cache::{INTERNER, Interned}; use crate::flags::Flags; pub use crate::flags::Subcommand; diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 57c06061c34ae..b0616ff66918c 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -14,7 +14,7 @@ use std::io::Write; use std::path::{PathBuf, Path}; use std::process::{Command, Stdio}; -use build_helper::output; +use build_helper::{output, t}; use crate::{Compiler, Mode, LLVM_TOOLS}; use crate::channel; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 330f66c1df0df..9c3a17bff6b7a 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -13,7 +13,7 @@ use std::io; use std::path::{PathBuf, Path}; use crate::Mode; -use build_helper::up_to_date; +use build_helper::{t, up_to_date}; use crate::util::symlink_dir; use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index 2d040d60e5fd7..deda30b6bbd9b 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -8,6 +8,8 @@ use std::fs; use std::path::{Path, PathBuf, Component}; use std::process::Command; +use build_helper::t; + use crate::dist::{self, pkgname, sanitize_sh, tmpdir}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f63aac0f0e249..ca4489655ca7b 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -108,17 +108,6 @@ #![feature(core_intrinsics)] #![feature(drain_filter)] -#[macro_use] -extern crate build_helper; -#[macro_use] -extern crate serde_derive; -#[macro_use] -extern crate lazy_static; - -#[cfg(test)] -#[macro_use] -extern crate pretty_assertions; - use std::cell::{RefCell, Cell}; use std::collections::{HashSet, HashMap}; use std::env; @@ -134,7 +123,9 @@ use std::os::unix::fs::symlink as symlink_file; #[cfg(windows)] use std::os::windows::fs::symlink_file; -use build_helper::{run_silent, run_suppressed, try_run_silent, try_run_suppressed, output, mtime}; +use build_helper::{ + mtime, output, run_silent, run_suppressed, t, try_run_silent, try_run_suppressed, +}; use filetime::FileTime; use crate::util::{exe, libdir, OutputFolder, CiEnv}; diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 7fa377f310b4f..4a71fd2ce0bd2 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; use std::collections::HashSet; use build_helper::output; +use serde::Deserialize; use serde_json; use crate::{Build, Crate}; diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 285f9458c44b6..5777331b9bfd5 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -14,7 +14,7 @@ use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::output; +use build_helper::{output, t}; use cmake; use cc; diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index fa6857cdc1125..dc65fb9b79706 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -15,7 +15,7 @@ use std::fs; use std::path::PathBuf; use std::process::Command; -use build_helper::output; +use build_helper::{output, t}; use crate::Build; diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 38027aded9c53..9867113e48f43 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -11,7 +11,7 @@ use std::iter; use std::path::{Path, PathBuf}; use std::process::Command; -use build_helper::{self, output}; +use build_helper::{self, output, t}; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; @@ -1870,6 +1870,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/bootstrap/tool.rs b/src/bootstrap/tool.rs index c23ddbdbc6810..edcd68d010e84 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -4,6 +4,8 @@ use std::path::PathBuf; use std::process::{Command, exit}; use std::collections::HashSet; +use build_helper::t; + use crate::Mode; use crate::Compiler; use crate::builder::{Step, RunConfig, ShouldRun, Builder}; diff --git a/src/bootstrap/toolstate.rs b/src/bootstrap/toolstate.rs index 8ff7c09fc2996..e86209be91fe1 100644 --- a/src/bootstrap/toolstate.rs +++ b/src/bootstrap/toolstate.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + #[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] #[serde(rename_all = "kebab-case")] /// Whether a tool can be compiled, tested or neither diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index bda1e56e1e73b..a162c65672f82 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -11,6 +11,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::time::{SystemTime, Instant}; +use build_helper::t; + use crate::config::Config; use crate::builder::Builder; diff --git a/src/ci/docker/dist-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile index cddfa557f6aed..f5eb66ed7142f 100644 --- a/src/ci/docker/dist-aarch64-linux/Dockerfile +++ b/src/ci/docker/dist-aarch64-linux/Dockerfile @@ -32,5 +32,8 @@ ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \ ENV HOSTS=aarch64-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS \ + --enable-extended \ + --enable-profiler \ + --disable-docs ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index c0f3326524d5c..869ee9883c100 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -1,9 +1,12 @@ -FROM ubuntu:17.10 +FROM ubuntu:18.04 COPY scripts/cross-apt-packages.sh /scripts/ RUN sh /scripts/cross-apt-packages.sh -RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \ +# Enable source repositories, which are disabled by default on Ubuntu >= 18.04 +RUN sed -i 's/^# deb-src/deb-src/' /etc/apt/sources.list + +RUN apt-get update && apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommends \ build-essential \ gcc-multilib \ libedit-dev \ @@ -15,7 +18,10 @@ RUN apt-get build-dep -y clang llvm && apt-get install -y --no-install-recommend nodejs \ python2.7-dev \ software-properties-common \ - unzip + unzip \ + # Needed for apt-key to work: + dirmngr \ + gpg-agent RUN apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys 74DA7924C5513486 RUN add-apt-repository -y 'deb http://apt.dilos.org/dilos dilos2-testing main' @@ -69,7 +75,7 @@ ENV TARGETS=x86_64-fuchsia ENV TARGETS=$TARGETS,aarch64-fuchsia ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,wasm32-unknown-unknown -ENV TARGETS=$TARGETS,wasm32-unknown-wasi +ENV TARGETS=$TARGETS,wasm32-wasi ENV TARGETS=$TARGETS,x86_64-sun-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV TARGETS=$TARGETS,x86_64-unknown-cloudabi @@ -79,5 +85,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-fuchsia-toolchain.sh b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh index 3b91918288a2b..73acdf5be6356 100755 --- a/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh @@ -10,7 +10,7 @@ pushd zircon > /dev/null # Download sources git init -git remote add origin https://fuchsia.googlesource.com/zircon +git remote add origin https://github.com/rust-lang-nursery/mirror-google-fuchsia-zircon git fetch --depth=1 origin $ZIRCON git reset --hard FETCH_HEAD 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 965286e5bcf64..98d6df043baca 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 39ad785b41ac6..385eefde846c2 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 8cdbfebea4dd9..d5988a25671a2 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-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile index 1c7eff68adc15..7a503ea4e98c5 100644 --- a/src/ci/docker/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.10 +FROM ubuntu:19.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile index dd94f2652b4c9..c3519a0077872 100644 --- a/src/ci/docker/x86_64-gnu/Dockerfile +++ b/src/ci/docker/x86_64-gnu/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:18.10 +FROM ubuntu:19.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ diff --git a/src/liballoc/collections/binary_heap.rs b/src/liballoc/collections/binary_heap.rs index 8c142a3d317c6..c355361b53c46 100644 --- a/src/liballoc/collections/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -207,6 +207,30 @@ use super::SpecExtend; /// // The heap should now be empty. /// assert!(heap.is_empty()) /// ``` +/// +/// ## Min-heap +/// +/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to +/// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest +/// value instead of the greatest one. +/// +/// ``` +/// use std::collections::BinaryHeap; +/// use std::cmp::Reverse; +/// +/// let mut heap = BinaryHeap::new(); +/// +/// // Wrap values in `Reverse` +/// heap.push(Reverse(1)); +/// heap.push(Reverse(5)); +/// heap.push(Reverse(2)); +/// +/// // If we pop these scores now, they should come back in the reverse order. +/// assert_eq!(heap.pop(), Some(Reverse(1))); +/// assert_eq!(heap.pop(), Some(Reverse(2))); +/// assert_eq!(heap.pop(), Some(Reverse(5))); +/// assert_eq!(heap.pop(), None); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct BinaryHeap { data: Vec, diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index d65c24f7350ae..9a8d48083e67c 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 diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index eb673488170b6..2edd946ff11cf 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -87,7 +87,6 @@ #![feature(fundamental)] #![feature(lang_items)] #![feature(libc)] -#![feature(needs_allocator)] #![feature(nll)] #![feature(optin_builtin_traits)] #![feature(pattern)] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 68eecd97ea11a..0dffb19476f3d 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 a3e2098695f70..3fdcf95ccaa3f 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) diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs index 466e806663c7f..90c7859b3db9e 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/vec.rs b/src/liballoc/vec.rs index cd62c3e05244c..073d3ab593703 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 diff --git a/src/libcore/array.rs b/src/libcore/array.rs index fb9c99f667df2..03094bfd33374 100644 --- a/src/libcore/array.rs +++ b/src/libcore/array.rs @@ -4,14 +4,11 @@ //! //! *[See also the array primitive type](../../std/primitive.array.html).* -#![unstable(feature = "fixed_size_array", - reason = "traits and impls are better expressed through generic \ - integer constants", - issue = "27778")] +#![stable(feature = "core_array", since = "1.36.0")] 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; @@ -30,13 +27,17 @@ use crate::slice::{Iter, IterMut}; /// Note that the traits AsRef and AsMut provide similar methods for types that /// may not be fixed-size arrays. Implementors should prefer those traits /// instead. +#[unstable(feature = "fixed_size_array", issue = "27778")] pub unsafe trait FixedSizeArray { /// Converts the array to immutable slice + #[unstable(feature = "fixed_size_array", issue = "27778")] fn as_slice(&self) -> &[T]; /// Converts the array to mutable slice + #[unstable(feature = "fixed_size_array", issue = "27778")] fn as_mut_slice(&mut self) -> &mut [T]; } +#[unstable(feature = "fixed_size_array", issue = "27778")] unsafe impl> FixedSizeArray for A { #[inline] fn as_slice(&self) -> &[T] { @@ -53,6 +54,7 @@ unsafe impl> FixedSizeArray for A { #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); +#[stable(feature = "core_array", since = "1.36.0")] impl fmt::Display for TryFromSliceError { #[inline] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -72,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/mem.rs b/src/libcore/mem.rs index 5bd442bc0664f..9fb071d29524b 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -665,8 +665,8 @@ pub fn swap(x: &mut T, y: &mut T) { /// let mut v: Vec = vec![1, 2]; /// /// let old_v = mem::replace(&mut v, vec![3, 4, 5]); -/// assert_eq!(2, old_v.len()); -/// assert_eq!(3, v.len()); +/// assert_eq!(vec![1, 2], old_v); +/// assert_eq!(vec![3, 4, 5], v); /// ``` /// /// `replace` allows consumption of a struct field by replacing it with another value. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index c1887a93490f8..562a7a4b3c719 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -214,11 +214,31 @@ pub mod diy_float; mod wrapping; +macro_rules! usize_isize_to_xe_bytes_doc { + () => {" + +**Note**: This function returns an array of length 2, 4 or 8 bytes +depending on the target pointer size. + +"} +} + + +macro_rules! usize_isize_from_xe_bytes_doc { + () => {" + +**Note**: This function takes an array of length 2, 4 or 8 bytes +depending on the target pointer size. + +"} +} + // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr) => { + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { doc_comment! { concat!("Returns the smallest value that can be represented by this integer type. @@ -2023,7 +2043,9 @@ $EndFeature, " doc_comment! { concat!("Return the memory representation of this integer as a byte array in big-endian (network) byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -2041,7 +2063,9 @@ assert_eq!(bytes, ", $be_bytes, "); doc_comment! { concat!("Return the memory representation of this integer as a byte array in little-endian byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -2064,7 +2088,9 @@ native byte order. As the target platform's native endianness is used, portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. - +", +$to_xe_bytes_doc, +" [`to_be_bytes`]: #method.to_be_bytes [`to_le_bytes`]: #method.to_le_bytes @@ -2089,7 +2115,9 @@ assert_eq!(bytes, if cfg!(target_endian = \"big\") { doc_comment! { concat!("Create an integer value from its representation as a byte array in big endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -2120,7 +2148,9 @@ doc_comment! { concat!(" Create an integer value from its representation as a byte array in little endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -2157,7 +2187,9 @@ appropriate instead. [`from_be_bytes`]: #method.from_be_bytes [`from_le_bytes`]: #method.from_le_bytes - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -2193,20 +2225,20 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[lang = "i8"] impl i8 { int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", - "[0x12]", "[0x12]" } + "[0x12]", "[0x12]", "", "" } } #[lang = "i16"] impl i16 { int_impl! { i16, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", - "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]" } + "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "i32"] impl i32 { int_impl! { i32, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]" } + "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "i64"] @@ -2214,7 +2246,7 @@ impl i64 { int_impl! { i64, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } } #[lang = "i128"] @@ -2226,14 +2258,15 @@ impl i128 { "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ - 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]" } + 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" } } #[cfg(target_pointer_width = "16")] #[lang = "isize"] impl isize { int_impl! { isize, i16, u16, 16, -32768, 32767, "", "", 4, "-0x5ffd", "0x3a", "0x1234", - "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]" } + "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "32")] @@ -2241,7 +2274,8 @@ impl isize { impl isize { int_impl! { isize, i32, u32, 32, -2147483648, 2147483647, "", "", 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78]" } + "[0x12, 0x34, 0x56, 0x78]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "64")] @@ -2250,14 +2284,16 @@ impl isize { int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr, $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr, - $reversed:expr, $le_bytes:expr, $be_bytes:expr) => { + $reversed:expr, $le_bytes:expr, $be_bytes:expr, + $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => { doc_comment! { concat!("Returns the smallest value that can be represented by this integer type. @@ -3817,7 +3853,9 @@ $EndFeature, " doc_comment! { concat!("Return the memory representation of this integer as a byte array in big-endian (network) byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -3835,7 +3873,9 @@ assert_eq!(bytes, ", $be_bytes, "); doc_comment! { concat!("Return the memory representation of this integer as a byte array in little-endian byte order. - +", +$to_xe_bytes_doc, +" # Examples ``` @@ -3858,7 +3898,9 @@ native byte order. As the target platform's native endianness is used, portable code should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, instead. - +", +$to_xe_bytes_doc, +" [`to_be_bytes`]: #method.to_be_bytes [`to_le_bytes`]: #method.to_le_bytes @@ -3883,7 +3925,9 @@ assert_eq!(bytes, if cfg!(target_endian = \"big\") { doc_comment! { concat!("Create an integer value from its representation as a byte array in big endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -3914,7 +3958,9 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), concat!(" Create an integer value from its representation as a byte array in little endian. - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -3951,7 +3997,9 @@ appropriate instead. [`from_be_bytes`]: #method.from_be_bytes [`from_le_bytes`]: #method.from_le_bytes - +", +$from_xe_bytes_doc, +" # Examples ``` @@ -3987,7 +4035,7 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[lang = "u8"] impl u8 { uint_impl! { u8, u8, 8, 255, "", "", 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", - "[0x12]" } + "[0x12]", "", "" } /// Checks if the value is within the ASCII range. @@ -4506,13 +4554,13 @@ impl u8 { #[lang = "u16"] impl u16 { uint_impl! { u16, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", - "[0x34, 0x12]", "[0x12, 0x34]" } + "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } #[lang = "u32"] impl u32 { uint_impl! { u32, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678", - "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]" } + "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } #[lang = "u64"] @@ -4520,7 +4568,8 @@ impl u64 { uint_impl! { u64, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + "", ""} } #[lang = "u128"] @@ -4531,20 +4580,23 @@ impl u128 { "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \ 0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \ - 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]" } + 0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", + "", ""} } #[cfg(target_pointer_width = "16")] #[lang = "usize"] impl usize { uint_impl! { usize, u16, 16, 65535, "", "", 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", - "[0x34, 0x12]", "[0x12, 0x34]" } + "[0x34, 0x12]", "[0x12, 0x34]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "32")] #[lang = "usize"] impl usize { uint_impl! { usize, u32, 32, 4294967295, "", "", 8, "0x10000b3", "0xb301", "0x12345678", - "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]" } + "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } #[cfg(target_pointer_width = "64")] @@ -4553,7 +4605,8 @@ impl usize { uint_impl! { usize, u64, 64, 18446744073709551615, "", "", 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]", - "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]" } + "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", + usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } /// A classification of floating point numbers. diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index e74ed9b7889cb..4ced860948bee 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -274,7 +274,7 @@ use crate::ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn}; /// value in place, preventing the value referenced by that pointer from being moved /// unless it implements [`Unpin`]. /// -/// See the [`pin` module] documentation for further explanation on pinning. +/// *See the [`pin` module] documentation for an explanation of pinning.* /// /// [`Unpin`]: ../../std/marker/trait.Unpin.html /// [`pin` module]: ../../std/pin/index.html diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index a41be4269d504..b6de9f57b0110 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -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); @@ -974,6 +971,13 @@ impl *const T { (self as *const u8) == null() } + /// Cast to a pointer to a different type + #[unstable(feature = "ptr_cast", issue = "60602")] + #[inline] + pub const fn cast(self) -> *const U { + self as _ + } + /// Returns `None` if the pointer is null, or else returns a reference to /// the value wrapped in `Some`. /// @@ -1593,6 +1597,13 @@ impl *mut T { (self as *mut u8) == null_mut() } + /// Cast to a pointer to a different type + #[unstable(feature = "ptr_cast", issue = "60602")] + #[inline] + pub const fn cast(self) -> *mut U { + self as _ + } + /// Returns `None` if the pointer is null, or else returns a reference to /// the value wrapped in `Some`. /// @@ -2959,7 +2970,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; @@ -3023,7 +3033,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 8731f48675356..72a54c5ce82d0 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -4152,6 +4152,40 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { Some(snd) } } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let remainder = match self.v.len().checked_rem(self.chunk_size) { + Some(res) => res, + None => 0, + }; + + let sub_chunk_size = if remainder != 0 { remainder } else { self.chunk_size }; + + let safe_sub = match n.checked_mul(sub_chunk_size) { + Some(res) => res, + None => 0, + }; + + let (end, overflow) = self.v.len().overflowing_sub(safe_sub); + if overflow { + self.v= &[]; + None + } else { + let start = if n == 0 { + self.v.len() - sub_chunk_size + } else { + match end.checked_sub(self.chunk_size) { + Some(res) => res, + None => 0, + } + }; + + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 025f7fb5cc6c3..b8075ef2942e0 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -31,7 +31,7 @@ #![feature(slice_partition_dedup)] #![feature(copy_within)] #![feature(int_error_matching)] -#![deny(rust_2018_idioms)] +#![warn(rust_2018_idioms)] extern crate test; diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index acf6b03791f01..cf2602f3210f1 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -134,6 +134,30 @@ fn test_chunks_nth() { assert_eq!(c2.next(), None); } +#[test] +fn test_chunks_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let mut c = v.chunks(2); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let mut c2 = v2.chunks(3); + assert_eq!(c2.nth_back(1).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &[i32] = &[0, 1, 2, 3, 4]; + let mut c3 = v3.chunks(10); + assert_eq!(c3.nth_back(0).unwrap(), &[0, 1, 2, 3, 4]); + assert_eq!(c3.next(), None); + + let v4: &[i32] = &[0, 1, 2]; + let mut c4 = v4.chunks(10); + assert_eq!(c4.nth_back(1_000_000_000usize), None); +} + #[test] fn test_chunks_last() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; diff --git a/src/libprofiler_builtins/build.rs b/src/libprofiler_builtins/build.rs index ff52a03d9dd97..331edb73d6df9 100644 --- a/src/libprofiler_builtins/build.rs +++ b/src/libprofiler_builtins/build.rs @@ -44,6 +44,19 @@ fn main() { cfg.define("COMPILER_RT_HAS_UNAME", Some("1")); } + // Assume that the Unixes we are building this for have fnctl() available + if env::var_os("CARGO_CFG_UNIX").is_some() { + cfg.define("COMPILER_RT_HAS_FCNTL_LCK", Some("1")); + } + + // This should be a pretty good heuristic for when to set + // COMPILER_RT_HAS_ATOMICS + if env::var_os("CARGO_CFG_TARGET_HAS_ATOMIC").map(|features| { + features.to_string_lossy().to_lowercase().contains("cas") + }).unwrap_or(false) { + cfg.define("COMPILER_RT_HAS_ATOMICS", Some("1")); + } + // The source for `compiler-rt` comes from the `compiler-builtins` crate, so // load our env var set by cargo to find the source code. let root = env::var_os("DEP_COMPILER_RT_COMPILER_RT").unwrap(); diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 2592af7d4ad5a..2e54165be1f1b 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/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 1ecc580d8c5c4..a87c98a04a4ab 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -1021,25 +1021,22 @@ impl CurrentDepGraph { fn complete_anon_task(&mut self, kind: DepKind, task_deps: TaskDeps) -> DepNodeIndex { debug_assert!(!kind.is_eval_always()); - let mut fingerprint = self.anon_id_seed; let mut hasher = StableHasher::new(); - for &read in task_deps.reads.iter() { - let read_dep_node = self.data[read].node; + // The dep node indices are hashed here instead of hashing the dep nodes of the + // dependencies. These indices may refer to different nodes per session, but this isn't + // a problem here because we that ensure the final dep node hash is per session only by + // combining it with the per session random number `anon_id_seed`. This hash only need + // to map the dependencies to a single value on a per session basis. + task_deps.reads.hash(&mut hasher); - ::std::mem::discriminant(&read_dep_node.kind).hash(&mut hasher); + let target_dep_node = DepNode { + kind, // Fingerprint::combine() is faster than sending Fingerprint // through the StableHasher (at least as long as StableHasher // is so slow). - fingerprint = fingerprint.combine(read_dep_node.hash); - } - - fingerprint = fingerprint.combine(hasher.finish()); - - let target_dep_node = DepNode { - kind, - hash: fingerprint, + hash: self.anon_id_seed.combine(hasher.finish()), }; self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO).0 diff --git a/src/librustc/error_codes.rs b/src/librustc/error_codes.rs index fd089fc688e32..a1bfd417566ad 100644 --- a/src/librustc/error_codes.rs +++ b/src/librustc/error_codes.rs @@ -2205,4 +2205,6 @@ register_diagnostics! { E0711, // a feature has been declared with conflicting stability attributes // E0702, // replaced with a generic attribute input check E0726, // non-explicit (not `'_`) elided lifetime in unsupported position + E0727, // `async` generators are not yet supported + E0728, // `await` must be in an `async` function or block } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 4c527f80d0f5d..b199eee6dad87 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.rs b/src/librustc/hir/def.rs index 6366c1f93e671..91256385232a9 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -1,5 +1,5 @@ use crate::hir::def_id::DefId; -use crate::util::nodemap::{NodeMap, DefIdMap}; +use crate::util::nodemap::DefIdMap; use syntax::ast; use syntax::ext::base::MacroKind; use syntax::ast::NodeId; @@ -140,9 +140,8 @@ pub enum Res { SelfCtor(DefId /* impl */), // `DefId` refers to the impl Local(Id), Upvar(Id, // `HirId` of closed over local - usize, // index in the `freevars` list of the closure + usize, // index in the `upvars` list of the closure ast::NodeId), // expr node that creates the closure - Label(ast::NodeId), // Macro namespace NonMacroAttr(NonMacroAttrKind), // e.g., `#[inline]` or `#[rustfmt::skip]` @@ -151,7 +150,9 @@ pub enum Res { Err, } -/// The result of resolving a path before lowering to HIR. +/// The result of resolving a path before lowering to HIR, +/// with "module" segments resolved and associated item +/// segments deferred to type checking. /// `base_res` is the resolution of the resolved part of the /// path, `unresolved_segments` is the number of unresolved /// segments. @@ -166,19 +167,21 @@ pub enum Res { /// base_res unresolved_segments = 2 /// ``` #[derive(Copy, Clone, Debug)] -pub struct PathResolution { +pub struct PartialRes { base_res: Res, unresolved_segments: usize, } -impl PathResolution { - pub fn new(res: Res) -> Self { - PathResolution { base_res: res, unresolved_segments: 0 } +impl PartialRes { + #[inline] + pub fn new(base_res: Res) -> Self { + PartialRes { base_res, unresolved_segments: 0 } } - pub fn with_unresolved_segments(res: Res, mut unresolved_segments: usize) -> Self { - if res == Res::Err { unresolved_segments = 0 } - PathResolution { base_res: res, unresolved_segments: unresolved_segments } + #[inline] + pub fn with_unresolved_segments(base_res: Res, mut unresolved_segments: usize) -> Self { + if base_res == Res::Err { unresolved_segments = 0 } + PartialRes { base_res, unresolved_segments } } #[inline] @@ -269,17 +272,10 @@ impl PerNS> { } } -/// Definition mapping -pub type ResMap = NodeMap; - /// This is the replacement export map. It maps a module to all of the exports /// within. pub type ExportMap = DefIdMap>>; -/// Map used to track the `use` statements within a scope, matching it with all the items in every -/// namespace. -pub type ImportMap = NodeMap>>; - #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct Export { /// The name of the target. @@ -352,7 +348,6 @@ impl Res { Res::Local(..) | Res::Upvar(..) | - Res::Label(..) | Res::PrimTy(..) | Res::SelfTy(..) | Res::SelfCtor(..) | @@ -373,14 +368,13 @@ impl Res { } /// A human readable name for the res kind ("function", "module", etc.). - pub fn kind_name(&self) -> &'static str { + pub fn descr(&self) -> &'static str { match *self { Res::Def(kind, _) => kind.descr(), Res::SelfCtor(..) => "self constructor", Res::PrimTy(..) => "builtin type", Res::Local(..) => "local variable", Res::Upvar(..) => "closure capture", - Res::Label(..) => "label", Res::SelfTy(..) => "self type", Res::ToolMod => "tool module", Res::NonMacroAttr(attr_kind) => attr_kind.descr(), @@ -408,7 +402,6 @@ impl Res { index, closure ), - Res::Label(id) => Res::Label(id), Res::SelfTy(a, b) => Res::SelfTy(a, b), Res::ToolMod => Res::ToolMod, Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 8536f38e48c6d..b268a1a494d10 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -1,5 +1,5 @@ use crate::ty::{self, TyCtxt}; -use crate::hir::map::definitions::FIRST_FREE_HIGH_DEF_INDEX; +use crate::hir::map::definitions::FIRST_FREE_DEF_INDEX; use rustc_data_structures::indexed_vec::Idx; use serialize; use std::fmt; @@ -99,17 +99,6 @@ 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. -/// -/// At the moment we are allocating the numerical values of DefIndexes from two -/// address spaces: DefIndexAddressSpace::Low and DefIndexAddressSpace::High. -/// This allows us to allocate the DefIndexes of all item-likes -/// (Items, TraitItems, and ImplItems) into one of these spaces and -/// consequently use a simple array for lookup tables keyed by DefIndex and -/// known to be densely populated. This is especially important for the HIR map. -/// -/// Since the DefIndex is mostly treated as an opaque ID, you probably -/// don't have to care about these address spaces. - #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub struct DefIndex(u32); @@ -119,33 +108,20 @@ 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.address_space().index(), - self.as_array_index()) + write!(f, "DefIndex({})", self.as_array_index()) } } impl DefIndex { - #[inline] - pub fn address_space(&self) -> DefIndexAddressSpace { - match self.0 & 1 { - 0 => DefIndexAddressSpace::Low, - 1 => DefIndexAddressSpace::High, - _ => unreachable!() - } - } - /// Converts this DefIndex into a zero-based array index. - /// This index is the offset within the given DefIndexAddressSpace. #[inline] pub fn as_array_index(&self) -> usize { - (self.0 >> 1) as usize + self.0 as usize } #[inline] - pub fn from_array_index(i: usize, address_space: DefIndexAddressSpace) -> DefIndex { - DefIndex::from_raw_u32(((i << 1) | (address_space as usize)) as u32) + 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 @@ -153,33 +129,28 @@ impl DefIndex { // index of the macro in the CrateMetadata::proc_macros array) to the // corresponding DefIndex. pub fn from_proc_macro_index(proc_macro_index: usize) -> DefIndex { - // DefIndex for proc macros start from FIRST_FREE_HIGH_DEF_INDEX, - // because the first FIRST_FREE_HIGH_DEF_INDEX indexes are reserved + // 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( - proc_macro_index.checked_add(FIRST_FREE_HIGH_DEF_INDEX) - .expect("integer overflow adding `proc_macro_index`"), - DefIndexAddressSpace::High); + proc_macro_index.checked_add(FIRST_FREE_DEF_INDEX) + .expect("integer overflow adding `proc_macro_index`")); assert!(def_index != CRATE_DEF_INDEX); def_index } // This function is the reverse of from_proc_macro_index() above. pub fn to_proc_macro_index(self: DefIndex) -> usize { - assert_eq!(self.address_space(), DefIndexAddressSpace::High); - - self.as_array_index().checked_sub(FIRST_FREE_HIGH_DEF_INDEX) + self.as_array_index().checked_sub(FIRST_FREE_DEF_INDEX) .unwrap_or_else(|| { bug!("using local index {:?} as proc-macro index", self) }) } - // Don't use this if you don't know about the DefIndex encoding. pub fn from_raw_u32(x: u32) -> DefIndex { DefIndex(x) } - // Don't use this if you don't know about the DefIndex encoding. pub fn as_raw_u32(&self) -> u32 { self.0 } @@ -188,19 +159,6 @@ impl DefIndex { impl serialize::UseSpecializedEncodable for DefIndex {} impl serialize::UseSpecializedDecodable for DefIndex {} -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum DefIndexAddressSpace { - Low = 0, - High = 1, -} - -impl DefIndexAddressSpace { - #[inline] - pub fn index(&self) -> usize { - *self as usize - } -} - /// A `DefId` identifies a particular *definition*, by combining a crate /// index and a def index. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] @@ -211,10 +169,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.address_space().index(), - self.index.as_array_index())?; + write!(f, "DefId({}:{}", self.krate, self.index.as_array_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 0c73d97394fda..38d6d710868c0 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 8361a62c07e48..dd0d13d8f5a6a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -36,8 +36,8 @@ use crate::dep_graph::DepGraph; use crate::hir::{self, ParamName}; use crate::hir::HirVec; use crate::hir::map::{DefKey, DefPathData, Definitions}; -use crate::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX}; -use crate::hir::def::{Res, DefKind, PathResolution, PerNS}; +use crate::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use crate::hir::def::{Res, DefKind, PartialRes, PerNS}; use crate::hir::{GenericArg, ConstArg}; use crate::lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, ELIDED_LIFETIMES_IN_PATHS}; @@ -50,7 +50,6 @@ use errors::Applicability; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::thin_vec::ThinVec; -use rustc_data_structures::sync::Lrc; use std::collections::{BTreeSet, BTreeMap}; use std::mem; @@ -59,12 +58,13 @@ use syntax::attr; use syntax::ast; use syntax::ast::*; use syntax::errors; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::Mark; use syntax::print::pprust; use syntax::ptr::P; -use syntax::source_map::{self, respan, CompilerDesugaringKind, Spanned}; +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}; @@ -73,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, @@ -95,6 +95,7 @@ pub struct LoweringContext<'a> { modules: BTreeMap, is_generator: bool, + is_async_body: bool, catch_scopes: Vec, loop_scopes: Vec, @@ -145,11 +146,14 @@ pub trait Resolver { is_value: bool, ) -> hir::Path; - /// Obtain the resolution for a `NodeId`. - fn get_resolution(&mut self, id: NodeId) -> Option; + /// Obtain resolution for a `NodeId` with a single resolution. + fn get_partial_res(&mut self, id: NodeId) -> Option; - /// Obtain the possible resolutions for the given `use` statement. - fn get_import(&mut self, id: NodeId) -> PerNS>; + /// Obtain per-namespace resolutions for `use` statement with the given `NoedId`. + fn get_import_res(&mut self, id: NodeId) -> PerNS>>; + + /// Obtain resolution for a label with the given `NodeId`. + fn get_label_res(&mut self, id: NodeId) -> Option; /// We must keep the set of definitions up to date as we add nodes that weren't in the AST. /// This should only return `None` during testing. @@ -160,8 +164,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; } @@ -224,7 +228,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, @@ -245,6 +249,7 @@ pub fn lower_crate( item_local_id_counters: Default::default(), node_id_to_hir_id: IndexVec::new(), is_generator: false, + is_async_body: false, is_in_trait_impl: false, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, @@ -413,7 +418,6 @@ impl<'a> LoweringContext<'a> { owner, id, DefPathData::Misc, - DefIndexAddressSpace::High, Mark::root(), tree.prefix.span, ); @@ -798,8 +802,17 @@ impl<'a> LoweringContext<'a> { } fn record_body(&mut self, value: hir::Expr, arguments: HirVec) -> hir::BodyId { + if self.is_generator && self.is_async_body { + span_err!( + self.sess, + value.span, + E0727, + "`async` generators are not yet supported", + ); + self.sess.abort_if_errors(); + } let body = hir::Body { - is_generator: self.is_generator, + is_generator: self.is_generator || self.is_async_body, arguments, value, }; @@ -821,7 +834,7 @@ impl<'a> LoweringContext<'a> { } fn expect_full_res(&mut self, id: NodeId) -> Res { - self.resolver.get_resolution(id).map_or(Res::Err, |pr| { + self.resolver.get_partial_res(id).map_or(Res::Err, |pr| { if pr.unresolved_segments() != 0 { bug!("path not fully resolved: {:?}", pr); } @@ -830,12 +843,7 @@ impl<'a> LoweringContext<'a> { } fn expect_full_res_from_use(&mut self, id: NodeId) -> impl Iterator> { - self.resolver.get_import(id).present_items().map(|pr| { - if pr.unresolved_segments() != 0 { - bug!("path not fully resolved: {:?}", pr); - } - pr.base_res() - }) + self.resolver.get_import_res(id).present_items() } fn diagnostic(&self) -> &errors::Handler { @@ -846,27 +854,6 @@ impl<'a> LoweringContext<'a> { Ident::with_empty_ctxt(Symbol::gensym(s)) } - /// Reuses the span but adds information like the kind of the desugaring and features that are - /// allowed inside this span. - fn mark_span_with_reason( - &self, - reason: CompilerDesugaringKind, - span: Span, - allow_internal_unstable: Option>, - ) -> Span { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(source_map::ExpnInfo { - call_site: span, - def_site: Some(span), - format: source_map::CompilerDesugaring(reason), - allow_internal_unstable, - allow_internal_unsafe: false, - local_inner_macros: false, - edition: source_map::hygiene::default_edition(), - }); - span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) - } - fn with_anonymous_lifetime_mode( &mut self, anonymous_lifetime_mode: AnonymousLifetimeMode, @@ -952,8 +939,7 @@ impl<'a> LoweringContext<'a> { self.resolver.definitions().create_def_with_parent( parent_index, node_id, - DefPathData::LifetimeParam(str_name), - DefIndexAddressSpace::High, + DefPathData::LifetimeNs(str_name), Mark::root(), span, ); @@ -1126,7 +1112,8 @@ impl<'a> LoweringContext<'a> { span: Span, body: impl FnOnce(&mut LoweringContext<'_>) -> hir::Expr, ) -> hir::ExprKind { - let prev_is_generator = mem::replace(&mut self.is_generator, true); + let prev_is_generator = mem::replace(&mut self.is_generator, false); + let prev_is_async_body = mem::replace(&mut self.is_async_body, true); let output = match ret_ty { Some(ty) => FunctionRetTy::Ty(P(ty.clone())), None => FunctionRetTy::Default(span), @@ -1142,6 +1129,7 @@ impl<'a> LoweringContext<'a> { let body_expr = body(self); let body_id = self.record_body(body_expr, arguments); self.is_generator = prev_is_generator; + self.is_async_body = prev_is_async_body; let capture_clause = self.lower_capture_clause(capture_clause); let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None); @@ -1153,7 +1141,7 @@ impl<'a> LoweringContext<'a> { attrs: ThinVec::new(), }; - let unstable_span = self.mark_span_with_reason( + let unstable_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::Async, span, Some(vec![ @@ -1161,7 +1149,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]) } @@ -1169,11 +1157,13 @@ impl<'a> LoweringContext<'a> { where F: FnOnce(&mut LoweringContext<'_>) -> hir::Expr, { - let prev = mem::replace(&mut self.is_generator, false); + let prev_generator = mem::replace(&mut self.is_generator, false); + let prev_async = mem::replace(&mut self.is_async_body, false); let arguments = self.lower_args(decl); let result = f(self); let r = self.record_body(result, arguments); - self.is_generator = prev; + self.is_generator = prev_generator; + self.is_async_body = prev_async; return r; } @@ -1251,7 +1241,7 @@ impl<'a> LoweringContext<'a> { fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination { let target_id = match destination { Some((id, _)) => { - if let Res::Label(loop_id) = self.expect_full_res(id) { + if let Some(loop_id) = self.resolver.get_label_res(id) { Ok(self.lower_node_id(loop_id)) } else { Err(hir::LoopIdError::UnresolvedLabel) @@ -1558,7 +1548,7 @@ impl<'a> LoweringContext<'a> { // desugaring that explicitly states that we don't want to track that. // Not tracking it makes lints in rustc and clippy very fragile as // frequently opened issues show. - let exist_ty_span = self.mark_span_with_reason( + let exist_ty_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::ExistentialReturnType, span, None, @@ -1749,8 +1739,7 @@ impl<'a> LoweringContext<'a> { self.context.resolver.definitions().create_def_with_parent( self.parent, def_node_id, - DefPathData::LifetimeParam(name.ident().as_interned_str()), - DefIndexAddressSpace::High, + DefPathData::LifetimeNs(name.ident().as_interned_str()), Mark::root(), lifetime.span, ); @@ -1842,13 +1831,13 @@ impl<'a> LoweringContext<'a> { let qself_position = qself.as_ref().map(|q| q.position); let qself = qself.as_ref().map(|q| self.lower_ty(&q.ty, itctx.reborrow())); - let resolution = self.resolver - .get_resolution(id) - .unwrap_or_else(|| PathResolution::new(Res::Err)); + let partial_res = self.resolver + .get_partial_res(id) + .unwrap_or_else(|| PartialRes::new(Res::Err)); - let proj_start = p.segments.len() - resolution.unresolved_segments(); + let proj_start = p.segments.len() - partial_res.unresolved_segments(); let path = P(hir::Path { - res: self.lower_res(resolution.base_res()), + res: self.lower_res(partial_res.base_res()), segments: p.segments[..proj_start] .iter() .enumerate() @@ -1869,7 +1858,7 @@ impl<'a> LoweringContext<'a> { krate: def_id.krate, index: this.def_key(def_id).parent.expect("missing parent"), }; - let type_def_id = match resolution.base_res() { + let type_def_id = match partial_res.base_res() { Res::Def(DefKind::AssociatedTy, def_id) if i + 2 == proj_start => { Some(parent_def_id(self, def_id)) } @@ -1886,7 +1875,7 @@ impl<'a> LoweringContext<'a> { } _ => None, }; - let parenthesized_generic_args = match resolution.base_res() { + let parenthesized_generic_args = match partial_res.base_res() { // `a::b::Trait(Args)` Res::Def(DefKind::Trait, _) if i + 1 == proj_start => ParenthesizedGenericArgs::Ok, @@ -1940,7 +1929,7 @@ impl<'a> LoweringContext<'a> { // Simple case, either no projections, or only fully-qualified. // E.g., `std::mem::size_of` or `::Item`. - if resolution.unresolved_segments() == 0 { + if partial_res.unresolved_segments() == 0 { return hir::QPath::Resolved(qself, path); } @@ -2433,7 +2422,7 @@ impl<'a> LoweringContext<'a> { ) -> hir::FunctionRetTy { let span = output.span(); - let exist_ty_span = self.mark_span_with_reason( + let exist_ty_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::Async, span, None, @@ -2559,7 +2548,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 { @@ -2738,7 +2727,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(), }; @@ -2756,7 +2745,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, @@ -2792,7 +2781,7 @@ impl<'a> LoweringContext<'a> { && bound_pred.bound_generic_params.is_empty() => { if let Some(Res::Def(DefKind::TyParam, def_id)) = self.resolver - .get_resolution(bound_pred.bounded_ty.id) + .get_partial_res(bound_pred.bounded_ty.id) .map(|d| d.base_res()) { if let Some(node_id) = @@ -3784,8 +3773,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 { @@ -3946,7 +3935,7 @@ impl<'a> LoweringContext<'a> { let node = match p.node { PatKind::Wild => hir::PatKind::Wild, PatKind::Ident(ref binding_mode, ident, ref sub) => { - match self.resolver.get_resolution(p.id).map(|d| d.base_res()) { + match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) { // `None` can occur in body-less function signatures res @ None | res @ Some(Res::Local(_)) => { let canonical_id = match res { @@ -4111,7 +4100,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())) @@ -4127,31 +4116,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 then_blk = self.lower_block(blk, false); - let then_expr = self.expr_block(then_blk, ThinVec::new()); + }; + let else_arm = self.arm(hir_vec![else_pat], P(else_expr)); + + // 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( @@ -4169,7 +4173,7 @@ impl<'a> LoweringContext<'a> { }), ExprKind::TryBlock(ref body) => { self.with_catch_scope(body.id, |this| { - let unstable_span = this.mark_span_with_reason( + let unstable_span = this.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::TryBlock, body.span, Some(vec![ @@ -4190,7 +4194,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) }) } @@ -4207,6 +4211,7 @@ impl<'a> LoweringContext<'a> { }) }) } + ExprKind::Await(_origin, ref expr) => self.lower_await(e.span, expr), ExprKind::Closure( capture_clause, ref asyncness, movability, ref decl, ref body, fn_decl_span ) => { @@ -4328,22 +4333,23 @@ impl<'a> LoweringContext<'a> { let id = self.next_id(); let e1 = self.lower_expr(e1); let e2 = self.lower_expr(e2); - let ty_path = P(self.std_path(e.span, &["ops", "RangeInclusive"], None, false)); - let ty = P(self.ty_path(id, e.span, hir::QPath::Resolved(None, ty_path))); - let new_seg = P(hir::PathSegment::from_ident(Ident::from_str("new"))); - let new_path = hir::QPath::TypeRelative(ty, new_seg); - let new = P(self.expr(e.span, hir::ExprKind::Path(new_path), ThinVec::new())); - hir::ExprKind::Call(new, hir_vec![e1, e2]) + self.expr_call_std_assoc_fn( + id, + e.span, + &[sym::ops, sym::RangeInclusive], + "new", + hir_vec![e1, e2], + ) } ExprKind::Range(ref e1, ref e2, lims) => { 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") @@ -4361,7 +4367,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)); @@ -4470,9 +4476,7 @@ impl<'a> LoweringContext<'a> { let expr = opt_expr .as_ref() .map(|x| self.lower_expr(x)) - .unwrap_or_else(|| - self.expr(e.span, hir::ExprKind::Tup(hir_vec![]), ThinVec::new()) - ); + .unwrap_or_else(|| self.expr_unit(e.span)); hir::ExprKind::Yield(P(expr)) } @@ -4498,16 +4502,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 { - 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(); @@ -4602,7 +4606,7 @@ impl<'a> LoweringContext<'a> { // expand let mut head = self.lower_expr(head); let head_sp = head.span; - let desugared_span = self.mark_span_with_reason( + let desugared_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::ForLoop, head_sp, None, @@ -4652,9 +4656,12 @@ 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 = P(self.expr_std_path(head_sp, next_path, None, ThinVec::new())); - let next_expr = P(self.expr_call(head_sp, next_path, hir_vec![ref_mut_iter])); + let next_path = &[sym::iter, sym::Iterator, sym::next]; + let next_expr = P(self.expr_call_std_path( + head_sp, + next_path, + hir_vec![ref_mut_iter], + )); let arms = hir_vec![pat_arm, break_arm]; P(self.expr( @@ -4667,11 +4674,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)); @@ -4694,11 +4697,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, @@ -4724,10 +4723,13 @@ 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 = P(self.expr_std_path( - head_sp, into_iter_path, None, ThinVec::new())); - P(self.expr_call(head_sp, into_iter, hir_vec![head])) + let into_iter_path = + &[sym::iter, sym::IntoIterator, sym::into_iter]; + P(self.expr_call_std_path( + head_sp, + into_iter_path, + hir_vec![head], + )) }; let match_expr = P(self.expr_match( @@ -4758,7 +4760,7 @@ impl<'a> LoweringContext<'a> { // return Try::from_error(From::from(err)), // } - let unstable_span = self.mark_span_with_reason( + let unstable_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::QuestionMark, e.span, Some(vec![ @@ -4766,7 +4768,7 @@ impl<'a> LoweringContext<'a> { ].into()), ); let try_span = self.sess.source_map().end_point(e.span); - let try_span = self.mark_span_with_reason( + let try_span = self.sess.source_map().mark_span_with_reason( CompilerDesugaringKind::QuestionMark, try_span, Some(vec![ @@ -4779,10 +4781,12 @@ impl<'a> LoweringContext<'a> { // expand let sub_expr = self.lower_expr(sub_expr); - let path = &["ops", "Try", "into_result"]; - let path = P(self.expr_std_path( - unstable_span, path, None, ThinVec::new())); - P(self.expr_call(e.span, path, hir_vec![sub_expr])) + let path = &[sym::ops, sym::Try, sym::into_result]; + P(self.expr_call_std_path( + unstable_span, + path, + hir_vec![sub_expr], + )) }; // `#[allow(unreachable_code)]` @@ -4819,15 +4823,12 @@ impl<'a> LoweringContext<'a> { let err_ident = self.str_to_ident("err"); let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); let from_expr = { - let path = &["convert", "From", "from"]; - let from = P(self.expr_std_path( - try_span, path, None, ThinVec::new())); + 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(try_span, from, hir_vec![err_expr]) + 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 { @@ -4877,12 +4878,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({ @@ -5058,6 +5054,42 @@ impl<'a> LoweringContext<'a> { self.expr(span, hir::ExprKind::Call(e, args), ThinVec::new()) } + // Note: associated functions must use `expr_call_std_path`. + fn expr_call_std_path( + &mut self, + span: Span, + path_components: &[Symbol], + args: hir::HirVec, + ) -> hir::Expr { + let path = P(self.expr_std_path(span, path_components, None, ThinVec::new())); + self.expr_call(span, path, args) + } + + // Create an expression calling an associated function of an std type. + // + // Associated functions cannot be resolved through the normal `std_path` function, + // as they are resolved differently and so cannot use `expr_call_std_path`. + // + // This function accepts the path component (`ty_path_components`) separately from + // the name of the associated function (`assoc_fn_name`) in order to facilitate + // separate resolution of the type and creation of a path referring to its associated + // function. + fn expr_call_std_assoc_fn( + &mut self, + ty_path_id: hir::HirId, + span: Span, + ty_path_components: &[Symbol], + assoc_fn_name: &str, + args: hir::HirVec, + ) -> hir::ExprKind { + let ty_path = P(self.std_path(span, ty_path_components, None, false)); + let ty = P(self.ty_path(ty_path_id, span, hir::QPath::Resolved(None, ty_path))); + let fn_seg = P(hir::PathSegment::from_ident(Ident::from_str(assoc_fn_name))); + let fn_path = hir::QPath::TypeRelative(ty, fn_seg); + let fn_expr = P(self.expr(span, hir::ExprKind::Path(fn_path), ThinVec::new())); + hir::ExprKind::Call(fn_expr, args) + } + fn expr_ident(&mut self, span: Span, ident: Ident, binding: hir::HirId) -> hir::Expr { self.expr_ident_with_attrs(span, ident, binding, ThinVec::new()) } @@ -5088,7 +5120,7 @@ impl<'a> LoweringContext<'a> { fn expr_std_path( &mut self, span: Span, - components: &[&str], + components: &[Symbol], params: Option>, attrs: ThinVec, ) -> hir::Expr { @@ -5129,8 +5161,12 @@ impl<'a> LoweringContext<'a> { self.expr(b.span, hir::ExprKind::Block(b, None), attrs) } - fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec) -> P { - P(self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new())) + fn expr_unit(&mut self, sp: Span) -> hir::Expr { + self.expr_tuple(sp, hir_vec![]) + } + + fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec) -> hir::Expr { + self.expr(sp, hir::ExprKind::Tup(exprs), ThinVec::new()) } fn expr(&mut self, span: Span, node: hir::ExprKind, attrs: ThinVec) -> hir::Expr { @@ -5142,28 +5178,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 { @@ -5186,26 +5226,50 @@ impl<'a> LoweringContext<'a> { } } + fn expr_unsafe(&mut self, expr: P) -> hir::Expr { + let hir_id = self.next_id(); + let span = expr.span; + self.expr( + span, + hir::ExprKind::Block(P(hir::Block { + stmts: hir_vec![], + expr: Some(expr), + hir_id, + rules: hir::UnsafeBlock(hir::CompilerGenerated), + span, + targeted_by_break: false, + }), None), + ThinVec::new(), + ) + } + + /// 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); @@ -5258,15 +5322,14 @@ impl<'a> LoweringContext<'a> { fn std_path( &mut self, span: Span, - components: &[&str], + components: &[Symbol], params: Option>, - is_value: bool + is_value: bool, ) -> hir::Path { let mut path = self.resolver .resolve_str_path(span, self.crate_root, components, is_value); path.segments.last_mut().unwrap().args = params; - for seg in path.segments.iter_mut() { if seg.hir_id.is_some() { seg.hir_id = Some(self.next_id()); @@ -5458,15 +5521,168 @@ 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])) } + + fn lower_await( + &mut self, + await_span: Span, + expr: &ast::Expr, + ) -> hir::ExprKind { + // to: + // + // { + // let mut pinned = ; + // loop { + // 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::Pending => {}, + // } + // yield (); + // } + // } + if !self.is_async_body { + span_err!( + self.sess, + await_span, + E0728, + "`await` is only allowed inside `async` functions and blocks" + ); + self.sess.abort_if_errors(); + } + let span = self.sess.source_map().mark_span_with_reason( + CompilerDesugaringKind::Await, + await_span, + None, + ); + let gen_future_span = self.sess.source_map().mark_span_with_reason( + CompilerDesugaringKind::Await, + await_span, + Some(vec![Symbol::intern("gen_future")].into()), + ); + + // let mut pinned = ; + let expr = P(self.lower_expr(expr)); + let pinned_ident = self.str_to_ident("pinned"); + let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode( + span, + pinned_ident, + hir::BindingAnnotation::Mutable, + ); + let pinned_let = self.stmt_let_pat( + span, + Some(expr), + pinned_pat, + hir::LocalSource::AwaitDesugar, + ); + + // ::std::future::poll_with_tls_context(unsafe { + // ::std::pin::Pin::new_unchecked(&mut pinned) + // })` + let poll_expr = { + let pinned = P(self.expr_ident(span, pinned_ident, pinned_pat_hid)); + let ref_mut_pinned = self.expr_mut_addr_of(span, pinned); + let pin_ty_id = self.next_id(); + let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( + pin_ty_id, + span, + &[sym::pin, sym::Pin], + "new_unchecked", + hir_vec![ref_mut_pinned], + ); + let new_unchecked = P(self.expr(span, new_unchecked_expr_kind, ThinVec::new())); + let unsafe_expr = self.expr_unsafe(new_unchecked); + P(self.expr_call_std_path( + gen_future_span, + &[sym::future, sym::poll_with_tls_context], + hir_vec![unsafe_expr], + )) + }; + + // `::std::task::Poll::Ready(x) => break x` + 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_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, + &[sym::task, sym::Poll, sym::Ready], + hir_vec![x_pat], + ); + let break_x = self.with_loop_scope(loop_node_id, |this| { + let expr_break = hir::ExprKind::Break( + this.lower_loop_destination(None), + Some(x_expr), + ); + P(this.expr(await_span, expr_break, ThinVec::new())) + }); + self.arm(hir_vec![ready_pat], break_x) + }; + + // `::std::task::Poll::Pending => {}` + let pending_arm = { + let pending_pat = self.pat_std_enum( + span, + &[sym::task, sym::Poll, sym::Pending], + hir_vec![], + ); + let empty_block = P(self.expr_block_empty(span)); + self.arm(hir_vec![pending_pat], empty_block) + }; + + let match_stmt = { + let match_expr = P(self.expr_match( + span, + poll_expr, + hir_vec![ready_arm, pending_arm], + hir::MatchSource::AwaitDesugar, + )); + self.stmt(span, hir::StmtKind::Expr(match_expr)) + }; + + let yield_stmt = { + let unit = self.expr_unit(span); + let yield_expr = P(self.expr( + span, + hir::ExprKind::Yield(P(unit)), + ThinVec::new(), + )); + self.stmt(span, hir::StmtKind::Expr(yield_expr)) + }; + + let loop_block = P(self.block_all( + span, + hir_vec![match_stmt, yield_stmt], + None, + )); + + let loop_expr = P(hir::Expr { + hir_id: loop_hir_id, + node: hir::ExprKind::Loop( + loop_block, + None, + hir::LoopSource::Loop, + ), + span, + attrs: ThinVec::new(), + }); + + hir::ExprKind::Block( + P(self.block_all(span, hir_vec![pinned_let], Some(loop_expr))), + None, + ) + } } fn body_ids(bodies: &BTreeMap) -> Vec { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 50bd89a158964..a1cf338bf12ea 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -1,9 +1,11 @@ use super::*; use crate::dep_graph::{DepGraph, DepKind, DepNodeIndex}; use crate::hir; +use crate::hir::map::HirEntryMap; use crate::hir::def_id::{LOCAL_CRATE, CrateNum}; use crate::hir::intravisit::{Visitor, NestedVisitorMap}; use rustc_data_structures::svh::Svh; +use rustc_data_structures::indexed_vec::IndexVec; use crate::ich::Fingerprint; use crate::middle::cstore::CrateStore; use crate::session::CrateDisambiguator; @@ -12,6 +14,7 @@ use crate::util::nodemap::FxHashMap; use syntax::ast::NodeId; use syntax::source_map::SourceMap; use syntax_pos::Span; +use std::iter::repeat; use crate::ich::StableHashingContext; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; @@ -25,7 +28,7 @@ pub(super) struct NodeCollector<'a, 'hir> { source_map: &'a SourceMap, /// The node map - map: FxHashMap>, + map: HirEntryMap<'hir>, /// The parent of this node parent_node: hir::HirId, @@ -145,8 +148,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { let mut collector = NodeCollector { krate, source_map: sess.source_map(), - map: FxHashMap::with_capacity_and_hasher(sess.current_node_id_count(), - Default::default()), + map: vec![None; definitions.def_index_count()], parent_node: hir::CRATE_HIR_ID, current_signature_dep_index: root_mod_sig_dep_index, current_full_dep_index: root_mod_full_dep_index, @@ -171,7 +173,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { crate_disambiguator: CrateDisambiguator, cstore: &dyn CrateStore, commandline_args_hash: u64) - -> (FxHashMap>, Svh) + -> (HirEntryMap<'hir>, Svh) { self.hir_body_nodes.sort_unstable_by_key(|bn| bn.0); @@ -224,7 +226,17 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { fn insert_entry(&mut self, id: HirId, entry: Entry<'hir>) { debug!("hir_map: {:?} => {:?}", id, entry); - self.map.insert(id, entry); + let local_map = &mut self.map[id.owner.as_array_index()]; + let i = id.local_id.as_u32() as usize; + if local_map.is_none() { + *local_map = Some(IndexVec::with_capacity(i + 1)); + } + let local_map = local_map.as_mut().unwrap(); + let len = local_map.len(); + if i >= len { + local_map.extend(repeat(None).take(i - len + 1)); + } + local_map[id.local_id] = Some(entry); } fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 7f1352095d936..6e7a8f5bc234f 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -1,5 +1,5 @@ use crate::hir::map::definitions::*; -use crate::hir::def_id::{CRATE_DEF_INDEX, DefIndex, DefIndexAddressSpace}; +use crate::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; use crate::session::CrateDisambiguator; use syntax::ast::*; @@ -10,8 +10,6 @@ use syntax::symbol::Symbol; use syntax::parse::token::{self, Token}; use syntax_pos::Span; -use crate::hir::map::{ITEM_LIKE_SPACE, REGULAR_SPACE}; - /// Creates `DefId`s for nodes in the AST. pub struct DefCollector<'a> { definitions: &'a mut Definitions, @@ -47,13 +45,12 @@ impl<'a> DefCollector<'a> { fn create_def(&mut self, node_id: NodeId, data: DefPathData, - address_space: DefIndexAddressSpace, span: Span) -> DefIndex { let parent_def = self.parent_def.unwrap(); debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); self.definitions - .create_def_with_parent(parent_def, node_id, data, address_space, self.expansion, span) + .create_def_with_parent(parent_def, node_id, data, self.expansion, span) } pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { @@ -85,9 +82,9 @@ impl<'a> DefCollector<'a> { // For async functions, we need to create their inner defs inside of a // closure to match their desugared representation. let fn_def_data = DefPathData::ValueNs(name.as_interned_str()); - let fn_def = self.create_def(id, fn_def_data, ITEM_LIKE_SPACE, span); + let fn_def = self.create_def(id, fn_def_data, span); return self.with_parent(fn_def, |this| { - this.create_def(*return_impl_trait_id, DefPathData::ImplTrait, REGULAR_SPACE, span); + this.create_def(*return_impl_trait_id, DefPathData::ImplTrait, span); visit::walk_generics(this, generics); @@ -106,7 +103,7 @@ impl<'a> DefCollector<'a> { visit::walk_fn_ret_ty(this, &decl.output); let closure_def = this.create_def( - *closure_id, DefPathData::ClosureExpr, REGULAR_SPACE, span, + *closure_id, DefPathData::ClosureExpr, span, ); this.with_parent(closure_def, |this| { use visit::Visitor; @@ -141,14 +138,13 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { // information we encapsulate into, the better let def_data = match i.node { ItemKind::Impl(..) => DefPathData::Impl, - ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()), - ItemKind::TraitAlias(..) => DefPathData::TraitAlias(i.ident.as_interned_str()), - ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | - ItemKind::Existential(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | - ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.as_interned_str()), ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => { return visit::walk_item(self, i); } + ItemKind::Mod(..) | ItemKind::Trait(..) | ItemKind::TraitAlias(..) | + ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) | + ItemKind::Existential(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | + ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.as_interned_str()), ItemKind::Fn( ref decl, ref header, @@ -165,24 +161,23 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { body, ) } - ItemKind::Mod(..) => DefPathData::Module(i.ident.as_interned_str()), ItemKind::Static(..) | ItemKind::Const(..) | ItemKind::Fn(..) => DefPathData::ValueNs(i.ident.as_interned_str()), - ItemKind::MacroDef(..) => DefPathData::MacroDef(i.ident.as_interned_str()), + ItemKind::MacroDef(..) => DefPathData::MacroNs(i.ident.as_interned_str()), ItemKind::Mac(..) => return self.visit_macro_invoc(i.id), ItemKind::GlobalAsm(..) => DefPathData::Misc, ItemKind::Use(..) => { return visit::walk_item(self, i); } }; - let def = self.create_def(i.id, def_data, ITEM_LIKE_SPACE, i.span); + let def = self.create_def(i.id, def_data, i.span); self.with_parent(def, |this| { match i.node { ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { // If this is a unit or tuple-like struct, register the constructor. if let Some(ctor_hir_id) = struct_def.ctor_id() { - this.create_def(ctor_hir_id, DefPathData::Ctor, REGULAR_SPACE, i.span); + this.create_def(ctor_hir_id, DefPathData::Ctor, i.span); } } _ => {} @@ -192,7 +187,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { - self.create_def(id, DefPathData::Misc, ITEM_LIKE_SPACE, use_tree.span); + self.create_def(id, DefPathData::Misc, use_tree.span); visit::walk_use_tree(self, use_tree, id); } @@ -203,7 +198,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let def = self.create_def(foreign_item.id, DefPathData::ValueNs(foreign_item.ident.as_interned_str()), - REGULAR_SPACE, foreign_item.span); self.with_parent(def, |this| { @@ -213,12 +207,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_variant(&mut self, v: &'a Variant, g: &'a Generics, item_id: NodeId) { let def = self.create_def(v.node.id, - DefPathData::EnumVariant(v.node.ident.as_interned_str()), - REGULAR_SPACE, + DefPathData::TypeNs(v.node.ident.as_interned_str()), v.span); self.with_parent(def, |this| { if let Some(ctor_hir_id) = v.node.data.ctor_id() { - this.create_def(ctor_hir_id, DefPathData::Ctor, REGULAR_SPACE, v.span); + this.create_def(ctor_hir_id, DefPathData::Ctor, v.span); } visit::walk_variant(this, v, g, item_id) }); @@ -230,8 +223,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { let name = field.ident.map(|ident| ident.name) .unwrap_or_else(|| Symbol::intern(&index.to_string())); let def = self.create_def(field.id, - DefPathData::Field(name.as_interned_str()), - REGULAR_SPACE, + DefPathData::ValueNs(name.as_interned_str()), field.span); self.with_parent(def, |this| this.visit_struct_field(field)); } @@ -240,11 +232,11 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_generic_param(&mut self, param: &'a GenericParam) { let name = param.ident.as_interned_str(); let def_path_data = match param.kind { - GenericParamKind::Lifetime { .. } => DefPathData::LifetimeParam(name), - GenericParamKind::Type { .. } => DefPathData::TypeParam(name), - GenericParamKind::Const { .. } => DefPathData::ConstParam(name), + GenericParamKind::Lifetime { .. } => DefPathData::LifetimeNs(name), + GenericParamKind::Type { .. } => DefPathData::TypeNs(name), + GenericParamKind::Const { .. } => DefPathData::ValueNs(name), }; - self.create_def(param.id, def_path_data, REGULAR_SPACE, param.ident.span); + self.create_def(param.id, def_path_data, param.ident.span); visit::walk_generic_param(self, param); } @@ -254,12 +246,12 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { TraitItemKind::Method(..) | TraitItemKind::Const(..) => DefPathData::ValueNs(ti.ident.as_interned_str()), TraitItemKind::Type(..) => { - DefPathData::AssocTypeInTrait(ti.ident.as_interned_str()) + DefPathData::TypeNs(ti.ident.as_interned_str()) }, TraitItemKind::Macro(..) => return self.visit_macro_invoc(ti.id), }; - let def = self.create_def(ti.id, def_data, ITEM_LIKE_SPACE, ti.span); + let def = self.create_def(ti.id, def_data, ti.span); self.with_parent(def, |this| visit::walk_trait_item(this, ti)); } @@ -281,14 +273,14 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.ident.as_interned_str()), - ImplItemKind::Type(..) => DefPathData::AssocTypeInImpl(ii.ident.as_interned_str()), + ImplItemKind::Type(..) | ImplItemKind::Existential(..) => { - DefPathData::AssocExistentialInImpl(ii.ident.as_interned_str()) + DefPathData::TypeNs(ii.ident.as_interned_str()) }, ImplItemKind::Macro(..) => return self.visit_macro_invoc(ii.id), }; - let def = self.create_def(ii.id, def_data, ITEM_LIKE_SPACE, ii.span); + let def = self.create_def(ii.id, def_data, ii.span); self.with_parent(def, |this| visit::walk_impl_item(this, ii)); } @@ -302,7 +294,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { fn visit_anon_const(&mut self, constant: &'a AnonConst) { let def = self.create_def(constant.id, DefPathData::AnonConst, - REGULAR_SPACE, constant.value.span); self.with_parent(def, |this| visit::walk_anon_const(this, constant)); } @@ -315,7 +306,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ExprKind::Closure(_, ref asyncness, ..) => { let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, - REGULAR_SPACE, expr.span); self.parent_def = Some(closure_def); @@ -324,7 +314,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { if let IsAsync::Async { closure_id, .. } = asyncness { let async_def = self.create_def(*closure_id, DefPathData::ClosureExpr, - REGULAR_SPACE, expr.span); self.parent_def = Some(async_def); } @@ -332,7 +321,6 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { ExprKind::Async(_, async_id, _) => { let async_def = self.create_def(async_id, DefPathData::ClosureExpr, - REGULAR_SPACE, expr.span); self.parent_def = Some(async_def); } @@ -347,7 +335,7 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { match ty.node { TyKind::Mac(..) => return self.visit_macro_invoc(ty.id), TyKind::ImplTrait(node_id, _) => { - self.create_def(node_id, DefPathData::ImplTrait, REGULAR_SPACE, ty.span); + self.create_def(node_id, DefPathData::ImplTrait, ty.span); } _ => {} } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 1006d813e65ed..dc6cddc89f912 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -5,8 +5,7 @@ //! expressions) that are mostly just leftovers. use crate::hir; -use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, DefIndexAddressSpace, - CRATE_DEF_INDEX}; +use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE, CRATE_DEF_INDEX}; use crate::ich::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::indexed_vec::{IndexVec}; @@ -26,59 +25,41 @@ use crate::util::nodemap::NodeMap; /// Internally the DefPathTable holds a tree of DefKeys, where each DefKey /// stores the DefIndex of its parent. /// There is one DefPathTable for each crate. -#[derive(Default)] +#[derive(Clone, Default)] pub struct DefPathTable { - index_to_key: [Vec; 2], - def_path_hashes: [Vec; 2], -} - -// Unfortunately we have to provide a manual impl of Clone because of the -// fixed-sized array field. -impl Clone for DefPathTable { - fn clone(&self) -> Self { - DefPathTable { - index_to_key: [self.index_to_key[0].clone(), - self.index_to_key[1].clone()], - def_path_hashes: [self.def_path_hashes[0].clone(), - self.def_path_hashes[1].clone()], - } - } + index_to_key: Vec, + def_path_hashes: Vec, } impl DefPathTable { fn allocate(&mut self, key: DefKey, - def_path_hash: DefPathHash, - address_space: DefIndexAddressSpace) + def_path_hash: DefPathHash) -> DefIndex { let index = { - let index_to_key = &mut self.index_to_key[address_space.index()]; - let index = DefIndex::from_array_index(index_to_key.len(), address_space); + let index = DefIndex::from_array_index(self.index_to_key.len()); debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index); - index_to_key.push(key); + self.index_to_key.push(key); index }; - self.def_path_hashes[address_space.index()].push(def_path_hash); - debug_assert!(self.def_path_hashes[address_space.index()].len() == - self.index_to_key[address_space.index()].len()); + self.def_path_hashes.push(def_path_hash); + debug_assert!(self.def_path_hashes.len() == self.index_to_key.len()); index } - pub fn next_id(&self, address_space: DefIndexAddressSpace) -> DefIndex { - DefIndex::from_array_index(self.index_to_key[address_space.index()].len(), address_space) + pub fn next_id(&self) -> DefIndex { + DefIndex::from_array_index(self.index_to_key.len()) } #[inline(always)] pub fn def_key(&self, index: DefIndex) -> DefKey { - self.index_to_key[index.address_space().index()] - [index.as_array_index()].clone() + self.index_to_key[index.as_array_index()].clone() } #[inline(always)] pub fn def_path_hash(&self, index: DefIndex) -> DefPathHash { - let ret = self.def_path_hashes[index.address_space().index()] - [index.as_array_index()]; + let ret = self.def_path_hashes[index.as_array_index()]; debug!("def_path_hash({:?}) = {:?}", index, ret); return ret } @@ -86,24 +67,22 @@ impl DefPathTable { pub fn add_def_path_hashes_to(&self, cnum: CrateNum, out: &mut FxHashMap) { - for &address_space in &[DefIndexAddressSpace::Low, DefIndexAddressSpace::High] { - out.extend( - (&self.def_path_hashes[address_space.index()]) - .iter() - .enumerate() - .map(|(index, &hash)| { - let def_id = DefId { - krate: cnum, - index: DefIndex::from_array_index(index, address_space), - }; - (hash, def_id) - }) - ); - } + out.extend( + self.def_path_hashes + .iter() + .enumerate() + .map(|(index, &hash)| { + let def_id = DefId { + krate: cnum, + index: DefIndex::from_array_index(index), + }; + (hash, def_id) + }) + ); } pub fn size(&self) -> usize { - self.index_to_key.iter().map(|v| v.len()).sum() + self.index_to_key.len() } } @@ -111,12 +90,10 @@ impl DefPathTable { impl Encodable for DefPathTable { fn encode(&self, s: &mut S) -> Result<(), S::Error> { // Index to key - self.index_to_key[DefIndexAddressSpace::Low.index()].encode(s)?; - self.index_to_key[DefIndexAddressSpace::High.index()].encode(s)?; + self.index_to_key.encode(s)?; // DefPath hashes - self.def_path_hashes[DefIndexAddressSpace::Low.index()].encode(s)?; - self.def_path_hashes[DefIndexAddressSpace::High.index()].encode(s)?; + self.def_path_hashes.encode(s)?; Ok(()) } @@ -124,18 +101,9 @@ impl Encodable for DefPathTable { impl Decodable for DefPathTable { fn decode(d: &mut D) -> Result { - let index_to_key_lo: Vec = Decodable::decode(d)?; - let index_to_key_hi: Vec = Decodable::decode(d)?; - - let def_path_hashes_lo: Vec = Decodable::decode(d)?; - let def_path_hashes_hi: Vec = Decodable::decode(d)?; - - let index_to_key = [index_to_key_lo, index_to_key_hi]; - let def_path_hashes = [def_path_hashes_lo, def_path_hashes_hi]; - Ok(DefPathTable { - index_to_key, - def_path_hashes, + index_to_key: Decodable::decode(d)?, + def_path_hashes : Decodable::decode(d)?, }) } } @@ -147,7 +115,7 @@ impl Decodable for DefPathTable { pub struct Definitions { table: DefPathTable, node_to_def_index: NodeMap, - def_index_to_node: [Vec; 2], + def_index_to_node: Vec, pub(super) node_to_hir_id: IndexVec, /// If `Mark` is an ID of some macro expansion, /// then `DefId` is the normal module (`mod`) in which the expanded macro was defined. @@ -337,35 +305,17 @@ pub enum DefPathData { // Different kinds of items and item-like things: /// An impl Impl, - /// A trait - Trait(InternedString), - /// An associated type **declaration** (i.e., in a trait) - AssocTypeInTrait(InternedString), - /// An associated type **value** (i.e., in an impl) - AssocTypeInImpl(InternedString), - /// An existential associated type **value** (i.e., in an impl) - AssocExistentialInImpl(InternedString), /// Something in the type NS TypeNs(InternedString), /// Something in the value NS ValueNs(InternedString), - /// A module declaration - Module(InternedString), - /// A macro rule - MacroDef(InternedString), + /// Something in the macro NS + MacroNs(InternedString), + /// Something in the lifetime NS + LifetimeNs(InternedString), /// A closure expression ClosureExpr, // Subportions of items - /// A type (generic) parameter - TypeParam(InternedString), - /// A lifetime (generic) parameter - LifetimeParam(InternedString), - /// A const (generic) parameter - ConstParam(InternedString), - /// A variant of a enum - EnumVariant(InternedString), - /// A struct field - Field(InternedString), /// Implicit ctor for a unit or tuple-like struct or enum variant. Ctor, /// A constant expression (see {ast,hir}::AnonConst). @@ -376,8 +326,6 @@ pub enum DefPathData { /// a whole crate (as opposed to just one item). GlobalMetaData components /// are only supposed to show up right below the crate root. GlobalMetaData(InternedString), - /// A trait alias. - TraitAlias(InternedString), } #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, @@ -394,30 +342,13 @@ impl Borrow for DefPathHash { } impl Definitions { - /// Creates new empty definition map. - /// - /// The `DefIndex` returned from a new `Definitions` are as follows: - /// 1. At `DefIndexAddressSpace::Low`, - /// CRATE_ROOT has index 0:0, and then new indexes are allocated in - /// ascending order. - /// 2. At `DefIndexAddressSpace::High`, - /// the first `FIRST_FREE_HIGH_DEF_INDEX` indexes are reserved for - /// internal use, then `1:FIRST_FREE_HIGH_DEF_INDEX` are allocated in - /// ascending order. - // - // FIXME: there is probably a better place to put this comment. - pub fn new() -> Self { - Self::default() - } - pub fn def_path_table(&self) -> &DefPathTable { &self.table } /// Gets the number of definitions. - pub fn def_index_counts_lo_hi(&self) -> (usize, usize) { - (self.table.index_to_key[DefIndexAddressSpace::Low.index()].len(), - self.table.index_to_key[DefIndexAddressSpace::High.index()].len()) + pub fn def_index_count(&self) -> usize { + self.table.index_to_key.len() } pub fn def_key(&self, index: DefIndex) -> DefKey { @@ -456,17 +387,12 @@ impl Definitions { #[inline] pub fn as_local_node_id(&self, def_id: DefId) -> Option { if def_id.krate == LOCAL_CRATE { - let space_index = def_id.index.address_space().index(); - let array_index = def_id.index.as_array_index(); - let node_id = self.def_index_to_node[space_index][array_index]; + let node_id = self.def_index_to_node[def_id.index.as_array_index()]; if node_id != ast::DUMMY_NODE_ID { - Some(node_id) - } else { - None + return Some(node_id); } - } else { - None } + None } // FIXME(@ljedrz): replace the NodeId variant @@ -491,9 +417,7 @@ impl Definitions { #[inline] pub fn def_index_to_hir_id(&self, def_index: DefIndex) -> hir::HirId { - let space_index = def_index.address_space().index(); - let array_index = def_index.as_array_index(); - let node_id = self.def_index_to_node[space_index][array_index]; + let node_id = self.def_index_to_node[def_index.as_array_index()]; self.node_to_hir_id[node_id] } @@ -508,7 +432,11 @@ impl Definitions { } } - /// Adds a root definition (no parent). + /// Adds a root definition (no parent) and a few other reserved definitions. + /// + /// After the initial definitions are created the first `FIRST_FREE_DEF_INDEX` indexes + /// are taken, so the "user" indexes will be allocated starting with `FIRST_FREE_DEF_INDEX` + /// in ascending order. pub fn create_root_def(&mut self, crate_name: &str, crate_disambiguator: CrateDisambiguator) @@ -526,11 +454,10 @@ impl Definitions { let def_path_hash = key.compute_stable_hash(parent_hash); // Create the definition. - let address_space = super::ITEM_LIKE_SPACE; - let root_index = self.table.allocate(key, def_path_hash, address_space); + let root_index = self.table.allocate(key, def_path_hash); assert_eq!(root_index, CRATE_DEF_INDEX); - assert!(self.def_index_to_node[address_space.index()].is_empty()); - self.def_index_to_node[address_space.index()].push(ast::CRATE_NODE_ID); + assert!(self.def_index_to_node.is_empty()); + self.def_index_to_node.push(ast::CRATE_NODE_ID); self.node_to_def_index.insert(ast::CRATE_NODE_ID, root_index); // Allocate some other DefIndices that always must exist. @@ -544,7 +471,6 @@ impl Definitions { parent: DefIndex, node_id: ast::NodeId, data: DefPathData, - address_space: DefIndexAddressSpace, expansion: Mark, span: Span) -> DefIndex { @@ -581,10 +507,9 @@ impl Definitions { debug!("create_def_with_parent: after disambiguation, key = {:?}", key); // Create the definition. - let index = self.table.allocate(key, def_path_hash, address_space); - assert_eq!(index.as_array_index(), - self.def_index_to_node[address_space.index()].len()); - self.def_index_to_node[address_space.index()].push(node_id); + let index = self.table.allocate(key, def_path_hash); + assert_eq!(index.as_array_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 // anything in the AST, so they don't have a NodeId. For these cases @@ -633,19 +558,9 @@ impl DefPathData { use self::DefPathData::*; match *self { TypeNs(name) | - Trait(name) | - TraitAlias(name) | - AssocTypeInTrait(name) | - AssocTypeInImpl(name) | - AssocExistentialInImpl(name) | ValueNs(name) | - Module(name) | - MacroDef(name) | - TypeParam(name) | - LifetimeParam(name) | - ConstParam(name) | - EnumVariant(name) | - Field(name) | + MacroNs(name) | + LifetimeNs(name) | GlobalMetaData(name) => Some(name), Impl | @@ -662,19 +577,9 @@ impl DefPathData { use self::DefPathData::*; let s = match *self { TypeNs(name) | - Trait(name) | - TraitAlias(name) | - AssocTypeInTrait(name) | - AssocTypeInImpl(name) | - AssocExistentialInImpl(name) | ValueNs(name) | - Module(name) | - MacroDef(name) | - TypeParam(name) | - LifetimeParam(name) | - ConstParam(name) | - EnumVariant(name) | - Field(name) | + MacroNs(name) | + LifetimeNs(name) | GlobalMetaData(name) => { return name } @@ -713,8 +618,7 @@ macro_rules! define_global_metadata_kind { $($variant),* } - const GLOBAL_MD_ADDRESS_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High; - pub const FIRST_FREE_HIGH_DEF_INDEX: usize = count!($($variant)*); + pub const FIRST_FREE_DEF_INDEX: usize = 1 + count!($($variant)*); impl GlobalMetaDataKind { fn allocate_def_indices(definitions: &mut Definitions) { @@ -724,7 +628,6 @@ macro_rules! define_global_metadata_kind { CRATE_DEF_INDEX, ast::DUMMY_NODE_ID, DefPathData::GlobalMetaData(instance.name().as_interned_str()), - GLOBAL_MD_ADDRESS_SPACE, Mark::root(), DUMMY_SP ); @@ -745,12 +648,12 @@ macro_rules! define_global_metadata_kind { // These DefKeys are all right after the root, // so a linear search is fine. - let index = def_path_table.index_to_key[GLOBAL_MD_ADDRESS_SPACE.index()] + let index = def_path_table.index_to_key .iter() .position(|k| *k == def_key) .unwrap(); - DefIndex::from_array_index(index, GLOBAL_MD_ADDRESS_SPACE) + DefIndex::from_array_index(index) } fn name(&self) -> Symbol { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 9c895198ddde9..b8ee98551a20e 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -5,12 +5,13 @@ pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, use crate::dep_graph::{DepGraph, DepNode, DepKind, DepNodeIndex}; -use crate::hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId, DefIndexAddressSpace}; +use crate::hir::def_id::{CRATE_DEF_INDEX, DefId, LocalDefId}; use crate::middle::cstore::CrateStoreDyn; use rustc_target::spec::abi::Abi; use rustc_data_structures::svh::Svh; +use rustc_data_structures::indexed_vec::IndexVec; use syntax::ast::{self, Name, NodeId}; use syntax::source_map::Spanned; use syntax::ext::base::MacroKind; @@ -33,9 +34,6 @@ mod def_collector; pub mod definitions; mod hir_id_validator; -pub const ITEM_LIKE_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::Low; -pub const REGULAR_SPACE: DefIndexAddressSpace = DefIndexAddressSpace::High; - /// Represents an entry and its parent `NodeId`. #[derive(Copy, Clone, Debug)] pub struct Entry<'hir> { @@ -161,6 +159,12 @@ impl Forest { } } +/// This type is effectively a `HashMap>`, +/// but it is implemented as 2 layers of arrays. +/// - first we have `A = Vec>` mapping a `DefIndex`'s index to an inner value +/// - which is `B = IndexVec>` which gives you the `Entry`. +pub(super) type HirEntryMap<'hir> = Vec>>>>; + /// Represents a mapping from `NodeId`s to AST elements and their parent `NodeId`s. #[derive(Clone)] pub struct Map<'hir> { @@ -174,16 +178,7 @@ pub struct Map<'hir> { /// The SVH of the local crate. pub crate_hash: Svh, - /// `NodeId`s are sequential integers from 0, so we can be - /// super-compact by storing them in a vector. Not everything with - /// a `NodeId` is in the map, but empirically the occupancy is about - /// 75-80%, so there's not too much overhead (certainly less than - /// a hashmap, since they (at the time of writing) have a maximum - /// of 75% occupancy). - /// - /// Also, indexing is pretty quick when you've got a vector and - /// plain old integers. - map: FxHashMap>, + map: HirEntryMap<'hir>, definitions: &'hir Definitions, @@ -192,6 +187,12 @@ 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())?; + local_map.as_ref()?.get(id.local_id)?.as_ref() + } + /// Registers a read in the dependency graph of the AST node with /// the given `id`. This needs to be called each time a public /// function returns the HIR for a node -- in other words, when it @@ -199,14 +200,8 @@ impl<'hir> Map<'hir> { /// otherwise have had access to those contents, and hence needs a /// read recorded). If the function just returns a DefId or /// NodeId, no actual content was returned, so no read is needed. - pub fn read(&self, id: NodeId) { - let hir_id = self.node_to_hir_id(id); - self.read_by_hir_id(hir_id); - } - - // FIXME(@ljedrz): replace the NodeId variant - pub fn read_by_hir_id(&self, hir_id: HirId) { - if let Some(entry) = self.map.get(&hir_id) { + pub fn read(&self, hir_id: HirId) { + if let Some(entry) = self.lookup(hir_id) { self.dep_graph.read_index(entry.dep_node); } else { bug!("called `HirMap::read()` with invalid `HirId`: {:?}", hir_id) @@ -223,17 +218,12 @@ impl<'hir> Map<'hir> { self.definitions.def_key(def_id.index) } - pub fn def_path_from_id(&self, id: NodeId) -> Option { - self.opt_local_def_id(id).map(|def_id| { + pub fn def_path_from_hir_id(&self, id: HirId) -> Option { + self.opt_local_def_id_from_hir_id(id).map(|def_id| { self.def_path(def_id) }) } - // FIXME(@ljedrz): replace the NodeId variant - pub fn def_path_from_hir_id(&self, id: HirId) -> DefPath { - self.def_path(self.local_def_id_from_hir_id(id)) - } - pub fn def_path(&self, def_id: DefId) -> DefPath { assert!(def_id.is_local()); self.definitions.def_path(def_id.index) @@ -398,12 +388,8 @@ impl<'hir> Map<'hir> { }) } - fn entry_count(&self) -> usize { - self.map.len() - } - fn find_entry(&self, id: HirId) -> Option> { - self.map.get(&id).cloned() + self.lookup(id).cloned() } pub fn krate(&self) -> &'hir Crate { @@ -411,7 +397,7 @@ impl<'hir> Map<'hir> { } pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem { - self.read_by_hir_id(id.hir_id); + self.read(id.hir_id); // N.B., intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here @@ -419,7 +405,7 @@ impl<'hir> Map<'hir> { } pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem { - self.read_by_hir_id(id.hir_id); + self.read(id.hir_id); // N.B., intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here @@ -427,7 +413,7 @@ impl<'hir> Map<'hir> { } pub fn body(&self, id: BodyId) -> &'hir Body { - self.read_by_hir_id(id.hir_id); + self.read(id.hir_id); // N.B., intentionally bypass `self.forest.krate()` so that we // do not trigger a read of the whole krate here @@ -453,7 +439,7 @@ impl<'hir> Map<'hir> { /// item (possibly associated), a closure, or a `hir::AnonConst`. pub fn body_owner(&self, BodyId { hir_id }: BodyId) -> NodeId { let parent = self.get_parent_node_by_hir_id(hir_id); - assert!(self.map.get(&parent).map_or(false, |e| e.is_body_owner(hir_id))); + assert!(self.lookup(parent).map_or(false, |e| e.is_body_owner(hir_id))); self.hir_to_node_id(parent) } @@ -560,7 +546,7 @@ impl<'hir> Map<'hir> { pub fn get_module(&self, module: DefId) -> (&'hir Mod, Span, HirId) { let hir_id = self.as_local_hir_id(module).unwrap(); - self.read_by_hir_id(hir_id); + self.read(hir_id); match self.find_entry(hir_id).unwrap().node { Node::Item(&Item { span, @@ -575,13 +561,15 @@ impl<'hir> Map<'hir> { pub fn visit_item_likes_in_module(&self, module: DefId, visitor: &mut V) where V: ItemLikeVisitor<'hir> { - let node_id = self.as_local_node_id(module).unwrap(); + let hir_id = self.as_local_hir_id(module).unwrap(); // Read the module so we'll be re-executed if new items // appear immediately under in the module. If some new item appears // in some nested item in the module, we'll be re-executed due to reads // in the expect_* calls the loops below - self.read(node_id); + self.read(hir_id); + + let node_id = self.hir_to_node_id[&hir_id]; let module = &self.forest.krate.modules[&node_id]; @@ -659,7 +647,7 @@ impl<'hir> Map<'hir> { } }); if result.is_some() { - self.read_by_hir_id(hir_id); + self.read(hir_id); } result } @@ -893,7 +881,7 @@ impl<'hir> Map<'hir> { if let Entry { node: Node::Item(Item { node: ItemKind::ForeignMod(ref nm), .. }), .. } = entry { - self.read_by_hir_id(hir_id); // reveals some of the content of a node + self.read(hir_id); // reveals some of the content of a node return nm.abi; } } @@ -1001,7 +989,7 @@ impl<'hir> Map<'hir> { // FIXME(@ljedrz): replace the NodeId variant pub fn attrs_by_hir_id(&self, id: HirId) -> &'hir [ast::Attribute] { - self.read_by_hir_id(id); // reveals attributes on the node + self.read(id); // reveals attributes on the node let attrs = match self.find_entry(id).map(|entry| entry.node) { Some(Node::Local(l)) => Some(&l.attrs[..]), Some(Node::Item(i)) => Some(&i.attrs[..]), @@ -1022,6 +1010,26 @@ impl<'hir> Map<'hir> { attrs.unwrap_or(&[]) } + /// Returns an iterator that yields all the hir ids in the map. + fn all_ids<'a>(&'a self) -> impl Iterator + 'a { + // This code is a bit awkward because the map is implemented as 2 levels of arrays, + // see the comment on `HirEntryMap`. + // Iterate over all the indices and return a reference to + // local maps and their index given that they exist. + self.map.iter().enumerate().filter_map(|(i, local_map)| { + local_map.as_ref().map(|m| (i, m)) + }).flat_map(move |(array_index, local_map)| { + // Iterate over each valid entry in the local map + 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), + local_id: i, + } + })) + }) + } + /// Returns an iterator that yields the node id's with paths that /// match `parts`. (Requires `parts` is non-empty.) /// @@ -1030,13 +1038,16 @@ impl<'hir> Map<'hir> { /// such as `foo::bar::quux`, `bar::quux`, `other::bar::quux`, and /// any other such items it can find in the map. pub fn nodes_matching_suffix<'a>(&'a self, parts: &'a [String]) - -> NodesMatchingSuffix<'a, 'hir> { - NodesMatchingSuffix { + -> impl Iterator + 'a { + let nodes = NodesMatchingSuffix { map: self, item_name: parts.last().unwrap(), in_which: &parts[..parts.len() - 1], - idx: ast::CRATE_NODE_ID, - } + }; + + self.all_ids().filter(move |hir| nodes.matches_suffix(*hir)).map(move |hir| { + self.hir_to_node_id(hir) + }) } pub fn span(&self, id: NodeId) -> Span { @@ -1046,7 +1057,7 @@ impl<'hir> Map<'hir> { // FIXME(@ljedrz): replace the NodeId variant pub fn span_by_hir_id(&self, hir_id: HirId) -> Span { - self.read_by_hir_id(hir_id); // reveals span from node + self.read(hir_id); // reveals span from node match self.find_entry(hir_id).map(|entry| entry.node) { Some(Node::Item(item)) => item.span, Some(Node::ForeignItem(foreign_item)) => foreign_item.span, @@ -1088,7 +1099,7 @@ impl<'hir> Map<'hir> { } pub fn node_to_string(&self, id: NodeId) -> String { - node_id_to_string(self, id, true) + hir_id_to_string(self, self.node_to_hir_id(id), true) } // FIXME(@ljedrz): replace the NodeId variant @@ -1097,7 +1108,7 @@ impl<'hir> Map<'hir> { } pub fn node_to_user_string(&self, id: NodeId) -> String { - node_id_to_string(self, id, false) + hir_id_to_string(self, self.node_to_hir_id(id), false) } // FIXME(@ljedrz): replace the NodeId variant @@ -1115,31 +1126,30 @@ impl<'hir> Map<'hir> { } } -pub struct NodesMatchingSuffix<'a, 'hir:'a> { - map: &'a Map<'hir>, +pub struct NodesMatchingSuffix<'a> { + map: &'a Map<'a>, item_name: &'a String, in_which: &'a [String], - idx: NodeId, } -impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> { +impl<'a> NodesMatchingSuffix<'a> { /// Returns `true` only if some suffix of the module path for parent /// matches `self.in_which`. /// /// In other words: let `[x_0,x_1,...,x_k]` be `self.in_which`; /// returns true if parent's path ends with the suffix /// `x_0::x_1::...::x_k`. - fn suffix_matches(&self, parent: NodeId) -> bool { + fn suffix_matches(&self, parent: HirId) -> bool { let mut cursor = parent; for part in self.in_which.iter().rev() { let (mod_id, mod_name) = match find_first_mod_parent(self.map, cursor) { 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(mod_id); + cursor = self.map.get_parent_item(mod_id); } return true; @@ -1149,14 +1159,14 @@ impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> { // If `id` itself is a mod named `m` with parent `p`, then // returns `Some(id, m, p)`. If `id` has no mod in its parent // chain, then returns `None`. - fn find_first_mod_parent<'a>(map: &'a Map<'_>, mut id: NodeId) -> Option<(NodeId, Name)> { + fn find_first_mod_parent<'a>(map: &'a Map<'_>, mut id: HirId) -> Option<(HirId, Name)> { loop { - if let Node::Item(item) = map.find(id)? { + if let Node::Item(item) = map.find_by_hir_id(id)? { if item_is_mod(&item) { return Some((id, item.ident.name)) } } - let parent = map.get_parent(id); + let parent = map.get_parent_item(id); if parent == id { return None } id = parent; } @@ -1172,35 +1182,21 @@ impl<'a, 'hir> NodesMatchingSuffix<'a, 'hir> { // 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: NodeId, name: Name) -> bool { - name == &**self.item_name && self.suffix_matches(parent_of_n) - } -} - -impl<'a, 'hir> Iterator for NodesMatchingSuffix<'a, 'hir> { - type Item = NodeId; - - fn next(&mut self) -> Option { - loop { - let idx = self.idx; - if idx.as_usize() >= self.map.entry_count() { - return None; - } - self.idx = NodeId::from_u32(self.idx.as_u32() + 1); - let hir_idx = self.map.node_to_hir_id(idx); - let name = match self.map.find_entry(hir_idx).map(|entry| entry.node) { - Some(Node::Item(n)) => n.name(), - Some(Node::ForeignItem(n)) => n.name(), - Some(Node::TraitItem(n)) => n.name(), - Some(Node::ImplItem(n)) => n.name(), - Some(Node::Variant(n)) => n.name(), - Some(Node::Field(n)) => n.name(), - _ => continue, - }; - if self.matches_names(self.map.get_parent(idx), name) { - return Some(idx) - } - } + fn matches_names(&self, parent_of_n: HirId, name: Name) -> bool { + name.as_str() == *self.item_name && self.suffix_matches(parent_of_n) + } + + fn matches_suffix(&self, hir: HirId) -> bool { + let name = match self.map.find_entry(hir).map(|entry| entry.node) { + Some(Node::Item(n)) => n.name(), + Some(Node::ForeignItem(n)) => n.name(), + Some(Node::TraitItem(n)) => n.name(), + Some(Node::ImplItem(n)) => n.name(), + Some(Node::Variant(n)) => n.name(), + Some(Node::Field(n)) => n.name(), + _ => return false, + }; + self.matches_names(self.map.get_parent_item(hir), name) } } @@ -1316,8 +1312,8 @@ impl<'a> print::State<'a> { } } -fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { - let id_str = format!(" (id={})", id); +fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { + let id_str = format!(" (hir_id={})", id); let id_str = if include_id { &id_str[..] } else { "" }; let path_str = || { @@ -1325,9 +1321,9 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { // the user-friendly path, otherwise fall back to stringifying DefPath. crate::ty::tls::with_opt(|tcx| { if let Some(tcx) = tcx { - let def_id = map.local_def_id(id); + let def_id = map.local_def_id_from_hir_id(id); tcx.def_path_str(def_id) - } else if let Some(path) = map.def_path_from_id(id) { + } else if let Some(path) = map.def_path_from_hir_id(id) { path.data.into_iter().map(|elem| { elem.data.to_string() }).collect::>().join("::") @@ -1337,7 +1333,7 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { }) }; - match map.find(id) { + match map.find_by_hir_id(id) { Some(Node::Item(item)) => { let item_str = match item.node { ItemKind::ExternCrate(..) => "extern crate", @@ -1398,40 +1394,40 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { path_str(), id_str) } Some(Node::AnonConst(_)) => { - format!("const {}{}", map.node_to_pretty_string(id), id_str) + format!("const {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Expr(_)) => { - format!("expr {}{}", map.node_to_pretty_string(id), id_str) + format!("expr {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Stmt(_)) => { - format!("stmt {}{}", map.node_to_pretty_string(id), id_str) + format!("stmt {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::PathSegment(_)) => { - format!("path segment {}{}", map.node_to_pretty_string(id), id_str) + format!("path segment {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Ty(_)) => { - format!("type {}{}", map.node_to_pretty_string(id), id_str) + format!("type {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::TraitRef(_)) => { - format!("trait_ref {}{}", map.node_to_pretty_string(id), id_str) + format!("trait_ref {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Binding(_)) => { - format!("local {}{}", map.node_to_pretty_string(id), id_str) + format!("local {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Pat(_)) => { - format!("pat {}{}", map.node_to_pretty_string(id), id_str) + format!("pat {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Block(_)) => { - format!("block {}{}", map.node_to_pretty_string(id), id_str) + format!("block {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Local(_)) => { - format!("local {}{}", map.node_to_pretty_string(id), id_str) + format!("local {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::Ctor(..)) => { format!("ctor {}{}", path_str(), id_str) } Some(Node::Lifetime(_)) => { - format!("lifetime {}{}", map.node_to_pretty_string(id), id_str) + format!("lifetime {}{}", map.hir_to_pretty_string(id), id_str) } Some(Node::GenericParam(ref param)) => { format!("generic_param {:?}{}", param, id_str) @@ -1447,12 +1443,6 @@ fn node_id_to_string(map: &Map<'_>, id: NodeId, include_id: bool) -> String { } } -// FIXME(@ljedrz): replace the NodeId variant -fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String { - let node_id = map.hir_to_node_id(id); - node_id_to_string(map, node_id, include_id) -} - pub fn def_kind(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option { if let Some(node_id) = tcx.hir().as_local_node_id(def_id) { tcx.hir().def_kind(node_id) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index ae7358df9d8fa..f407be4e87b82 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; @@ -37,6 +37,7 @@ use rustc_macros::HashStable; use serialize::{self, Encoder, Encodable, Decoder, Decodable}; use std::collections::{BTreeSet, BTreeMap}; use std::fmt; +use smallvec::SmallVec; /// HIR doesn't commit to a concrete storage type and has its own alias for a vector. /// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar @@ -125,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] @@ -1330,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) @@ -1367,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, @@ -1420,7 +1423,6 @@ impl Expr { ExprKind::MethodCall(..) | ExprKind::Struct(..) | ExprKind::Tup(..) | - ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Closure(..) | ExprKind::Block(..) | @@ -1497,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 { }`. @@ -1605,6 +1603,8 @@ pub enum LocalSource { /// } /// ``` AsyncFn, + /// A desugared `.await`. + AwaitDesugar, } /// Hints at the original code for a `match _ { .. }`. @@ -1612,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, @@ -1623,6 +1627,8 @@ pub enum MatchSource { ForLoopDesugar, /// A desugared `?` operator. TryDesugar, + /// A desugared `.await`. + AwaitDesugar, } /// The loop type that yielded an `ExprKind::Loop`. @@ -2142,7 +2148,7 @@ pub enum UseKind { /// resolve maps each TraitRef's ref_id to its defining trait; that's all /// that the ref_id is for. Note that ref_id's value is not the NodeId of the /// trait being referred to but just a unique NodeId that serves as a key -/// within the ResMap. +/// within the resolution map. #[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)] pub struct TraitRef { pub path: Path, @@ -2475,19 +2481,19 @@ impl ForeignItemKind { } } -/// A free variable referred to in a function. +/// A variable captured by a closure. #[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] -pub struct Freevar { - /// The variable being accessed free. +pub struct Upvar { + /// The variable being captured. pub res: Res, // First span where it is accessed (there can be multiple). pub span: Span } -impl Freevar { - pub fn map_id(self, map: impl FnMut(Id) -> R) -> Freevar { - Freevar { +impl Upvar { + pub fn map_id(self, map: impl FnMut(Id) -> R) -> Upvar { + Upvar { res: self.res.map_id(map), span: self.span, } @@ -2496,19 +2502,22 @@ impl Freevar { pub fn var_id(&self) -> Id { match self.res { Res::Local(id) | Res::Upvar(id, ..) => id, - _ => bug!("Freevar::var_id: bad res ({:?})", self.res) + _ => bug!("Upvar::var_id: bad res ({:?})", self.res) } } } -pub type FreevarMap = NodeMap>>; +pub type UpvarMap = NodeMap>>; pub type CaptureModeMap = NodeMap; + // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and + // has length > 0 if the trait is found through an chain of imports, starting with the + // import/use statement in the scope where the trait is used. #[derive(Clone, Debug)] pub struct TraitCandidate { pub def_id: DefId, - pub import_id: Option, + pub import_ids: SmallVec<[NodeId; 1]>, } // Trait method resolution diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 54816316f0bf5..8a9028e544391 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 6da2cb9ab57ea..8be610e8bf7af 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_hir.rs b/src/librustc/ich/impls_hir.rs index 65795d2b136b4..5b2a1e783c039 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -7,6 +7,7 @@ use crate::hir::def_id::{DefId, LocalDefId, CrateNum, CRATE_DEF_INDEX}; use crate::ich::{StableHashingContext, NodeIdHashingMode, Fingerprint}; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; +use smallvec::SmallVec; use std::mem; use syntax::ast; use syntax::attr; @@ -393,30 +394,30 @@ impl<'a> HashStable> for hir::TraitCandidate { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { let hir::TraitCandidate { def_id, - import_id, - } = *self; + import_ids, + } = self; def_id.hash_stable(hcx, hasher); - import_id.hash_stable(hcx, hasher); + import_ids.hash_stable(hcx, hasher); }); } } impl<'a> ToStableHashKey> for hir::TraitCandidate { - type KeyType = (DefPathHash, Option<(DefPathHash, hir::ItemLocalId)>); + type KeyType = (DefPathHash, SmallVec<[(DefPathHash, hir::ItemLocalId); 1]>); fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType { let hir::TraitCandidate { def_id, - import_id, - } = *self; + import_ids, + } = self; - let import_id = import_id.map(|node_id| hcx.node_to_hir_id(node_id)) - .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), - hir_id.local_id)); - (hcx.def_path_hash(def_id), import_id) + let import_keys = import_ids.iter().map(|node_id| hcx.node_to_hir_id(*node_id)) + .map(|hir_id| (hcx.local_def_path_hash(hir_id.owner), + hir_id.local_id)).collect(); + (hcx.def_path_hash(*def_id), import_keys) } } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 40cce8e77c0e0..4e5718cc5ef2a 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,7 +402,9 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { + IfTemporary, Async, + Await, QuestionMark, ExistentialReturnType, ForLoop, diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index b407b75e68c9a..f3fc7ec8fda15 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/at.rs b/src/librustc/infer/at.rs index 34cd3ae5427e0..5772110889290 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -27,6 +27,7 @@ use super::*; +use crate::ty::Const; use crate::ty::relate::{Relate, TypeRelation}; pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> { @@ -308,6 +309,20 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { } } +impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, + a_is_expected: bool, + a: Self, + b: Self) + -> TypeTrace<'tcx> + { + TypeTrace { + cause: cause.clone(), + values: Consts(ExpectedFound::new(a_is_expected, a, b)) + } + } +} + impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { fn to_trace(cause: &ObligationCause<'tcx>, a_is_expected: bool, diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs index 8225ed70c5827..413c1428ff954 100644 --- a/src/librustc/infer/canonical/query_response.rs +++ b/src/librustc/infer/canonical/query_response.rs @@ -318,8 +318,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { obligations.extend(ok.into_obligations()); } - (UnpackedKind::Const(..), UnpackedKind::Const(..)) => { - unimplemented!() // FIXME(const_generics) + (UnpackedKind::Const(v1), UnpackedKind::Const(v2)) => { + let ok = self.at(cause, param_env).eq(v1, v2)?; + obligations.extend(ok.into_obligations()); } _ => { @@ -626,8 +627,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { obligations .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); } - (UnpackedKind::Const(..), UnpackedKind::Const(..)) => { - unimplemented!() // FIXME(const_generics) + (UnpackedKind::Const(v1), UnpackedKind::Const(v2)) => { + let ok = self.at(cause, param_env).eq(v1, v2)?; + obligations.extend(ok.into_obligations()); } _ => { bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 95b566d4a1b69..4b6e7da333081 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -1260,6 +1260,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match *values { infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), infer::Regions(ref exp_found) => self.expected_found_str(exp_found), + infer::Consts(ref exp_found) => self.expected_found_str(exp_found), infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found), infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found), } diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs index c05c6567bbefa..9eb46aa3779d9 100644 --- a/src/librustc/infer/error_reporting/note.rs +++ b/src/librustc/infer/error_reporting/note.rs @@ -46,7 +46,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_note(span, "...so that pointer is not dereferenced outside its lifetime"); } - infer::FreeVariable(span, id) => { + infer::ClosureCapture(span, id) => { err.span_note(span, &format!("...so that captured variable `{}` does not outlive the \ enclosing closure", @@ -214,7 +214,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "the reference is only valid for ", sup, ""); err } - infer::FreeVariable(span, id) => { + infer::ClosureCapture(span, id) => { let mut err = struct_span_err!(self.tcx.sess, span, E0474, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 2044e5ddae90e..b5a9184079aa6 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -232,6 +232,7 @@ pub type PlaceholderMap<'tcx> = BTreeMap>; pub enum ValuePairs<'tcx> { Types(ExpectedFound>), Regions(ExpectedFound>), + Consts(ExpectedFound<&'tcx ty::Const<'tcx>>), TraitRefs(ExpectedFound>), PolyTraitRefs(ExpectedFound>), } @@ -264,8 +265,8 @@ pub enum SubregionOrigin<'tcx> { /// Dereference of reference must be within its lifetime DerefPointer(Span), - /// Closure bound must not outlive captured free variables - FreeVariable(Span, ast::NodeId), + /// Closure bound must not outlive captured variables + ClosureCapture(Span, ast::NodeId), /// Index into slice must be within its lifetime IndexSlice(Span), @@ -1660,7 +1661,7 @@ impl<'tcx> SubregionOrigin<'tcx> { InfStackClosure(a) => a, InvokeClosure(a) => a, DerefPointer(a) => a, - FreeVariable(a, _) => a, + ClosureCapture(a, _) => a, IndexSlice(a) => a, RelateObjectBound(a) => a, RelateParamBound(a, _) => a, @@ -1730,6 +1731,7 @@ EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> { (ValuePairs::Types)(a), (ValuePairs::Regions)(a), + (ValuePairs::Consts)(a), (ValuePairs::TraitRefs)(a), (ValuePairs::PolyTraitRefs)(a), } diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs index f85fd524a5d9b..4351f94df2f13 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/levels.rs b/src/librustc/lint/levels.rs index 2e5bd8add0cdc..9c926dff325bf 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 6613440ee7c9e..68b65f9b4a1cc 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) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index a0107ed0546dd..2a9928567f4dc 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 df77033ebef3b..67db2ec248156 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 cf3f613b08eb5..d46bba92f3fc9 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; @@ -931,9 +923,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("walk_captures({:?})", closure_expr); let closure_def_id = self.tcx().hir().local_def_id_from_hir_id(closure_expr.hir_id); - self.tcx().with_freevars(closure_expr.hir_id, |freevars| { - for freevar in freevars { - let var_hir_id = freevar.var_id(); + if let Some(upvars) = self.tcx().upvars(closure_def_id) { + for upvar in upvars.iter() { + let var_hir_id = upvar.var_id(); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id.to_local(), @@ -941,14 +933,14 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { let upvar_capture = self.mc.tables.upvar_capture(upvar_id); let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id, fn_decl_span, - freevar)); + upvar)); match upvar_capture { ty::UpvarCapture::ByValue => { let mode = copy_or_move(&self.mc, self.param_env, &cmt_var, CaptureMove); - self.delegate.consume(closure_expr.hir_id, freevar.span, &cmt_var, mode); + self.delegate.consume(closure_expr.hir_id, upvar.span, &cmt_var, mode); } ty::UpvarCapture::ByRef(upvar_borrow) => { self.delegate.borrow(closure_expr.hir_id, @@ -956,17 +948,17 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { &cmt_var, upvar_borrow.region, upvar_borrow.kind, - ClosureCapture(freevar.span)); + ClosureCapture(upvar.span)); } } } - }); + } } fn cat_captured_var(&mut self, closure_hir_id: hir::HirId, closure_span: Span, - upvar: &hir::Freevar) + upvar: &hir::Upvar) -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 5d809f1407114..103580a598fcd 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -1,13 +1,13 @@ -// Detecting language items. -// -// Language items are items that represent concepts intrinsic to the language -// itself. Examples are: -// -// * Traits that specify "kinds"; e.g., "Sync", "Send". -// -// * Traits that represent operators; e.g., "Add", "Sub", "Index". -// -// * Functions called by the compiler itself. +//! Detecting language items. +//! +//! Language items are items that represent concepts intrinsic to the language +//! itself. Examples are: +//! +//! * Traits that specify "kinds"; e.g., "Sync", "Send". +//! +//! * Traits that represent operators; e.g., "Add", "Sub", "Index". +//! +//! * Functions called by the compiler itself. pub use self::LangItem::*; @@ -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; @@ -32,6 +32,7 @@ macro_rules! language_item_table { ) => { enum_from_u32! { + /// A representation of all the valid language items in Rust. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum LangItem { $($variant,)* @@ -39,6 +40,9 @@ enum_from_u32! { } impl LangItem { + /// Returns the `name` in `#[lang = "$name"]`. + /// For example, `LangItem::EqTraitLangItem`, + /// that is `#[lang = "eq"]` would result in `"eq"`. fn name(self) -> &'static str { match self { $( $variant => $name, )* @@ -48,28 +52,38 @@ impl LangItem { #[derive(HashStable)] pub struct LanguageItems { + /// Mappings from lang items to their possibly found `DefId`s. + /// The index corresponds to the order in `LangItem`. pub items: Vec>, + /// Lang items that were not found during collection. pub missing: Vec, } impl LanguageItems { - pub fn new() -> LanguageItems { - fn foo(_: LangItem) -> Option { None } + /// Construct an empty collection of lang items and no missing ones. + pub fn new() -> Self { + fn init_none(_: LangItem) -> Option { None } - LanguageItems { - items: vec![$(foo($variant)),*], + Self { + items: vec![$(init_none($variant)),*], missing: Vec::new(), } } + /// Returns the mappings to the possibly found `DefId`s for each lang item. pub fn items(&self) -> &[Option] { &*self.items } + /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. + /// If it wasn't bound, e.g. due to a missing `#[lang = ""]`, + /// returns an error message as a string. pub fn require(&self, it: LangItem) -> Result { self.items[it as usize].ok_or_else(|| format!("requires `{}` lang_item", it.name())) } + /// Returns the kind of closure that `id`, which is one of the `Fn*` traits, corresponds to. + /// If `id` is not one of the `Fn*` traits, `None` is returned. pub fn fn_trait_kind(&self, id: DefId) -> Option { match Some(id) { x if x == self.fn_trait() => Some(ty::ClosureKind::Fn), @@ -80,6 +94,9 @@ impl LanguageItems { } $( + /// Returns the corresponding `DefId` for the lang item + #[doc = $name] + /// if it exists. #[allow(dead_code)] pub fn $method(&self) -> Option { self.items[$variant as usize] @@ -90,6 +107,7 @@ impl LanguageItems { struct LanguageItemCollector<'a, 'tcx: 'a> { items: LanguageItems, tcx: TyCtxt<'a, 'tcx, 'tcx>, + /// A mapping from the name of the lang item to its order and the form it must be of. item_refs: FxHashMap<&'static str, (usize, Target)>, } @@ -105,32 +123,28 @@ impl<'a, 'v, 'tcx> ItemLikeVisitor<'v> for LanguageItemCollector<'a, 'tcx> { }, // Known lang item with attribute on incorrect target. Some((_, expected_target)) => { - let mut err = struct_span_err!( + struct_span_err!( self.tcx.sess, span, E0718, "`{}` language item must be applied to a {}", value, expected_target, - ); - err.span_label( + ).span_label( span, format!( "attribute should be applied to a {}, not a {}", expected_target, actual_target, ), - ); - err.emit(); + ).emit(); }, // Unknown lang item. _ => { - let mut err = struct_span_err!( + struct_span_err!( self.tcx.sess, span, E0522, "definition of an unknown language item: `{}`", value - ); - err.span_label( + ).span_label( span, format!("definition of unknown language item `{}`", value) - ); - err.emit(); + ).emit(); }, } } @@ -190,32 +204,39 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> { } } +/// Extract the first `lang = "$name"` out of a list of attributes. +/// The attributes `#[panic_handler]` and `#[alloc_error_handler]` +/// are also extracted out when found. pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { - for attribute in attrs { - if attribute.check_name("lang") { - if let Some(value) = attribute.value_str() { - return Some((value, attribute.span)); - } - } else if attribute.check_name("panic_handler") { - return Some((Symbol::intern("panic_impl"), attribute.span)) - } else if attribute.check_name("alloc_error_handler") { - return Some((Symbol::intern("oom"), attribute.span)) - } - } - - None + attrs.iter().find_map(|attr| Some(match attr { + _ 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, + })) } +/// Traverse and collect all the lang items in all crates. pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> LanguageItems { + // Initialize the collector. let mut collector = LanguageItemCollector::new(tcx); + + // Collect lang items in other crates. for &cnum in tcx.crates().iter() { for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() { collector.collect_item(item_index, def_id); } } + + // Collect lang items in this crate. tcx.hir().krate().visit_all_item_likes(&mut collector); + + // Extract out the found lang items. let LanguageItemCollector { mut items, .. } = collector; + + // Find all required but not-yet-defined lang items. weak_lang_items::check_crate(tcx, &mut items); + items } @@ -382,6 +403,8 @@ language_item_table! { } impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> { + /// Returns the `DefId` for a given `LangItem`. + /// If not found, fatally abort compilation. pub fn require_lang_item(&self, lang_item: LangItem) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { self.sess.fatal(&msg) diff --git a/src/librustc/middle/lib_features.rs b/src/librustc/middle/lib_features.rs index e79ef8bfc6fb4..76934ddd69b1b 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 15736218a7923..cb333b5b0cba2 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; @@ -144,7 +144,7 @@ impl LiveNode { #[derive(Copy, Clone, PartialEq, Debug)] enum LiveNodeKind { - FreeVarNode(Span), + UpvarNode(Span), ExprNode(Span), VarDefNode(Span), ExitNode @@ -153,8 +153,8 @@ enum LiveNodeKind { fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_, '_, '_>) -> String { let cm = tcx.sess.source_map(); match lnk { - FreeVarNode(s) => { - format!("Free var node [{}]", cm.span_to_string(s)) + UpvarNode(s) => { + format!("Upvar node [{}]", cm.span_to_string(s)) } ExprNode(s) => { format!("Expr node [{}]", cm.span_to_string(s)) @@ -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; } } @@ -483,23 +483,23 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { // in better error messages than just pointing at the closure // construction site. let mut call_caps = Vec::new(); - ir.tcx.with_freevars(expr.hir_id, |freevars| { - call_caps.extend(freevars.iter().filter_map(|fv| { - if let Res::Local(rv) = fv.res { - let fv_ln = ir.add_live_node(FreeVarNode(fv.span)); - Some(CaptureInfo { ln: fv_ln, var_hid: rv }) + let closure_def_id = ir.tcx.hir().local_def_id_from_hir_id(expr.hir_id); + if let Some(upvars) = ir.tcx.upvars(closure_def_id) { + call_caps.extend(upvars.iter().filter_map(|upvar| { + if let Res::Local(rv) = upvar.res { + let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); + Some(CaptureInfo { ln: upvar_ln, var_hid: rv }) } else { None } })); - }); + } ir.set_captures(expr.hir_id, call_caps); intravisit::walk_expr(ir, expr); } // live nodes required for interesting control flow: - hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) => { @@ -1039,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) } @@ -1522,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 f6caf357b393d..c7f8cf684e6b1 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); @@ -1300,8 +1301,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } def => { - span_bug!(pat.span, "tuple struct pattern didn't resolve \ - to variant or struct {:?}", def); + debug!( + "tuple struct pattern didn't resolve to variant or struct {:?} at {:?}", + def, + pat.span, + ); + self.tcx.sess.delay_span_bug(pat.span, &format!( + "tuple struct pattern didn't resolve to variant or struct {:?}", + def, + )); + return Err(()); } }; diff --git a/src/librustc/middle/recursion_limit.rs b/src/librustc/middle/recursion_limit.rs index ea077220e0be3..5f355d17072b8 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 2b88f273adce4..8ef4e9ac8f45f 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -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 d835d872d76d7..2402d0eefde48 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 5078bd7c59423..abcf164cda6d4 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 312924e5e90f5..75c21c738f7a0 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/mod.rs b/src/librustc/mir/mod.rs index 09e2b523fae83..bd67aabfe8e5f 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2572,12 +2572,12 @@ impl<'tcx> Debug for Rvalue<'tcx> { }; let mut struct_fmt = fmt.debug_struct(&name); - tcx.with_freevars(hir_id, |freevars| { - for (freevar, place) in freevars.iter().zip(places) { - let var_name = tcx.hir().name_by_hir_id(freevar.var_id()); + if let Some(upvars) = tcx.upvars(def_id) { + for (upvar, place) in upvars.iter().zip(places) { + let var_name = tcx.hir().name_by_hir_id(upvar.var_id()); struct_fmt.field(&var_name.as_str(), place); } - }); + } struct_fmt.finish() } else { @@ -2591,12 +2591,12 @@ impl<'tcx> Debug for Rvalue<'tcx> { tcx.hir().span_by_hir_id(hir_id)); let mut struct_fmt = fmt.debug_struct(&name); - tcx.with_freevars(hir_id, |freevars| { - for (freevar, place) in freevars.iter().zip(places) { - let var_name = tcx.hir().name_by_hir_id(freevar.var_id()); + if let Some(upvars) = tcx.upvars(def_id) { + for (upvar, place) in upvars.iter().zip(places) { + let var_name = tcx.hir().name_by_hir_id(upvar.var_id()); struct_fmt.field(&var_name.as_str(), place); } - }); + } struct_fmt.finish() } else { diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index e1e115cfe177b..2fff4c3f109b1 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -824,7 +824,7 @@ rustc_queries! { desc { "generating a postorder list of CrateNums" } } - query freevars(_: DefId) -> Option>> { + query upvars(_: DefId) -> Option>> { eval_always } query maybe_unused_trait_import(_: DefId) -> bool { @@ -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 ad80e5d74bd2a..f61ffac15d5f9 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1462,8 +1462,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, the same values as the target option of the same name"), allow_features: Option> = (None, parse_opt_comma_list, [TRACKED], "only allow the listed language features to be enabled in code (space separated)"), - emit_directives: bool = (false, parse_bool, [UNTRACKED], - "emit build directives if producing JSON output"), + emit_artifact_notifications: bool = (false, parse_bool, [UNTRACKED], + "emit notifications after each artifact has been output (only in the JSON format)"), } pub fn default_lib_output() -> CrateType { @@ -2181,10 +2181,21 @@ pub fn build_session_options_and_crate_config( TargetTriple::from_triple(host_triple()) }; let opt_level = { - if matches.opt_present("O") { - if cg.opt_level.is_some() { - early_error(error_format, "-O and -C opt-level both provided"); + // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able + // to use them interchangeably. However, because they're technically different flags, + // we need to work out manually which should take precedence if both are supplied (i.e. + // the rightmost flag). We do this by finding the (rightmost) position of both flags and + // comparing them. Note that if a flag is not found, its position will be `None`, which + // always compared less than `Some(_)`. + let max_o = matches.opt_positions("O").into_iter().max(); + let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| { + if let Some("opt-level") = s.splitn(2, '=').next() { + Some(i) + } else { + None } + }).max(); + if max_o > max_c { OptLevel::Default } else { match cg.opt_level.as_ref().map(String::as_ref) { @@ -2208,11 +2219,19 @@ pub fn build_session_options_and_crate_config( } } }; + // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able + // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`) + // for more details. let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No); - let debuginfo = if matches.opt_present("g") { - if cg.debuginfo.is_some() { - early_error(error_format, "-g and -C debuginfo both provided"); + let max_g = matches.opt_positions("g").into_iter().max(); + let max_c = matches.opt_strs_pos("C").into_iter().flat_map(|(i, s)| { + if let Some("debuginfo") = s.splitn(2, '=').next() { + Some(i) + } else { + None } + }).max(); + let debuginfo = if max_g > max_c { DebugInfo::Full } else { match cg.debuginfo { @@ -2734,6 +2753,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()]) { @@ -2744,7 +2764,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 ad8825bc5de5a..4d47491661e86 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` @@ -408,9 +409,6 @@ impl Session { pub fn next_node_id(&self) -> NodeId { self.reserve_node_ids(1) } - pub(crate) fn current_node_id_count(&self) -> usize { - self.next_node_id.get().as_u32() as usize - } pub fn diagnostic<'a>(&'a self) -> &'a errors::Handler { &self.parse_sess.span_diagnostic } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 35d8e2beef557..afbce5a4f0a49 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 007ff32f32776..df26883971022 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 @@ -1453,7 +1454,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.infcx.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy {name, ..}) = ty.sty { + if let ty::Param(ty::ParamTy {name, .. }) = ty.sty { let infcx = self.infcx; self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var( diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 2b286ee1b97fb..7ba7429f465a6 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 dabb8a728901c..f05a19372918e 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!() @@ -1454,13 +1455,18 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>( } } Err(e) => { - span_bug!( - obligation.cause.span, - "Failed to unify obligation `{:?}` \ - with poly_projection `{:?}`: {:?}", + let msg = format!( + "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}", obligation, poly_cache_entry, - e); + e, + ); + debug!("confirm_param_env_candidate: {}", msg); + infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg); + Progress { + ty: infcx.tcx.types.err, + obligations: vec![], + } } } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index f0c402789c4cd..d68e2be9ea086 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -3424,7 +3424,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let mut found = false; for ty in field.walk() { if let ty::Param(p) = ty.sty { - ty_params.insert(p.idx as usize); + ty_params.insert(p.index as usize); found = true; } } diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 384a5862cde0c..2496419640c2e 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -298,9 +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.address_space().index(), - def_id.index.as_array_index()) + (-(def_id.krate.as_u32() as i64), def_id.index.as_array_index()) }); for impl_def_id in trait_impls { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 90f62a4d132c7..be29ea5701b2f 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -204,7 +204,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { }, Component::Param(p) => { - let ty = tcx.mk_ty_param(p.idx, p.name); + let ty = tcx.mk_ty_param(p.index, p.name); Some(ty::Predicate::TypeOutlives( ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min)))) }, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index fddae02409126..c9fee02f66bbd 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; @@ -1071,10 +1071,10 @@ pub struct GlobalCtxt<'tcx> { pub queries: query::Queries<'tcx>, - // Records the free variables referenced by every closure + // Records the captured variables referenced by every closure // expression. Do not track deps for this, just recompute it from // scratch every time. - freevars: FxHashMap>>, + upvars: FxHashMap>>, maybe_unused_trait_imports: FxHashSet, maybe_unused_extern_crates: Vec<(DefId, Span)>, @@ -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 { @@ -1317,7 +1318,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }).collect(); (k, Lrc::new(exports)) }).collect(), - freevars: resolutions.freevars.into_iter().map(|(k, v)| { + upvars: resolutions.upvars.into_iter().map(|(k, v)| { let vars: Vec<_> = v.into_iter().map(|e| { e.map_id(|id| hir.node_to_hir_id(id)) }).collect(); @@ -2715,10 +2716,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } #[inline] - pub fn mk_ty_param(self, - index: u32, - name: InternedString) -> Ty<'tcx> { - self.mk_ty(Param(ParamTy { idx: index, name: name })) + pub fn mk_ty_param(self, index: u32, name: InternedString) -> Ty<'tcx> { + self.mk_ty(Param(ParamTy { index, name: name })) } #[inline] @@ -3055,7 +3054,7 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) { assert_eq!(id, LOCAL_CRATE); Lrc::new(middle::lang_items::collect(tcx)) }; - providers.freevars = |tcx, id| tcx.gcx.freevars.get(&id).cloned(); + providers.upvars = |tcx, id| tcx.gcx.upvars.get(&id).cloned(); providers.maybe_unused_trait_import = |tcx, id| { tcx.maybe_unused_trait_imports.contains(&id) }; @@ -3104,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 197d3325f51cf..be1d973c2cdd5 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 21e4d8b07a19f..d1a8a9a34e155 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -12,6 +12,7 @@ use std::iter; use std::mem; use std::ops::Bound; +use crate::hir; use crate::ich::StableHashingContext; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, @@ -1518,6 +1519,10 @@ pub trait HasTyCtxt<'tcx>: HasDataLayout { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; } +pub trait HasParamEnv<'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx>; +} + impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> { fn data_layout(&self) -> &TargetDataLayout { &self.data_layout @@ -1530,6 +1535,12 @@ impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> { } } +impl<'tcx, C> HasParamEnv<'tcx> for LayoutCx<'tcx, C> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } +} + impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> { fn data_layout(&self) -> &TargetDataLayout { self.tcx.data_layout() @@ -1543,25 +1554,32 @@ impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> { } pub trait MaybeResult { - fn from_ok(x: T) -> Self; - fn map_same T>(self, f: F) -> Self; + type Error; + + fn from(x: Result) -> Self; + fn to_result(self) -> Result; } impl MaybeResult for T { - fn from_ok(x: T) -> Self { + type Error = !; + + fn from(x: Result) -> Self { + let Ok(x) = x; x } - fn map_same T>(self, f: F) -> Self { - f(self) + fn to_result(self) -> Result { + Ok(self) } } impl MaybeResult for Result { - fn from_ok(x: T) -> Self { - Ok(x) + type Error = E; + + fn from(x: Result) -> Self { + x } - fn map_same T>(self, f: F) -> Self { - self.map(f) + fn to_result(self) -> Result { + self } } @@ -1656,7 +1674,8 @@ impl ty::query::TyCtxtAt<'a, 'tcx, '_> { impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> where C: LayoutOf> + HasTyCtxt<'tcx>, - C::TyLayout: MaybeResult> + C::TyLayout: MaybeResult>, + C: HasParamEnv<'tcx> { fn for_variant(this: TyLayout<'tcx>, cx: &C, variant_index: VariantIdx) -> TyLayout<'tcx> { let details = match this.variants { @@ -1664,10 +1683,9 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> Variants::Single { index } => { // Deny calling for_variant more than once for non-Single enums. - cx.layout_of(this.ty).map_same(|layout| { + if let Ok(layout) = cx.layout_of(this.ty).to_result() { assert_eq!(layout.variants, Variants::Single { index }); - layout - }); + } let fields = match this.ty.sty { ty::Adt(def, _) => def.variants[variant_index].fields.len(), @@ -1700,10 +1718,10 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> let tcx = cx.tcx(); let discr_layout = |discr: &Scalar| -> C::TyLayout { let layout = LayoutDetails::scalar(cx, discr.clone()); - MaybeResult::from_ok(TyLayout { + MaybeResult::from(Ok(TyLayout { details: tcx.intern_layout(layout), - ty: discr.value.to_ty(tcx) - }) + ty: discr.value.to_ty(tcx), + })) }; cx.layout_of(match this.ty.sty { @@ -1737,10 +1755,10 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } else { tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) }; - return cx.layout_of(ptr_ty).map_same(|mut ptr_layout| { + return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| { ptr_layout.ty = this.ty; ptr_layout - }); + })); } match tcx.struct_tail(pointee).sty { @@ -1824,6 +1842,130 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } }) } + + fn pointee_info_at( + this: TyLayout<'tcx>, + cx: &C, + offset: Size, + ) -> Option { + match this.ty.sty { + ty::RawPtr(mt) if offset.bytes() == 0 => { + cx.layout_of(mt.ty).to_result().ok() + .map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: None, + }) + } + + ty::Ref(_, ty, mt) if offset.bytes() == 0 => { + let tcx = cx.tcx(); + let is_freeze = ty.is_freeze(tcx, cx.param_env(), DUMMY_SP); + let kind = match mt { + hir::MutImmutable => if is_freeze { + PointerKind::Frozen + } else { + PointerKind::Shared + }, + hir::MutMutable => { + // Previously we would only emit noalias annotations for LLVM >= 6 or in + // panic=abort mode. That was deemed right, as prior versions had many bugs + // in conjunction with unwinding, but later versions didn’t seem to have + // said issues. See issue #31681. + // + // Alas, later on we encountered a case where noalias would generate wrong + // code altogether even with recent versions of LLVM in *safe* code with no + // unwinding involved. See #54462. + // + // For now, do not enable mutable_noalias by default at all, while the + // issue is being figured out. + let mutable_noalias = tcx.sess.opts.debugging_opts.mutable_noalias + .unwrap_or(false); + if mutable_noalias { + PointerKind::UniqueBorrowed + } else { + PointerKind::Shared + } + } + }; + + cx.layout_of(ty).to_result().ok() + .map(|layout| PointeeInfo { + size: layout.size, + align: layout.align.abi, + safe: Some(kind), + }) + } + + _ => { + let mut data_variant = match this.variants { + // Within the discriminant field, only the niche itself is + // always initialized, so we only check for a pointer at its + // offset. + // + // If the niche is a pointer, it's either valid (according + // to its type), or null (which the niche field's scalar + // validity range encodes). This allows using + // `dereferenceable_or_null` for e.g., `Option<&T>`, and + // this will continue to work as long as we don't start + // using more niches than just null (e.g., the first page of + // the address space, or unaligned pointers). + Variants::Multiple { + discr_kind: DiscriminantKind::Niche { + dataful_variant, + .. + }, + discr_index, + .. + } if this.fields.offset(discr_index) == offset => + Some(this.for_variant(cx, dataful_variant)), + _ => Some(this), + }; + + if let Some(variant) = data_variant { + // We're not interested in any unions. + if let FieldPlacement::Union(_) = variant.fields { + data_variant = None; + } + } + + let mut result = None; + + if let Some(variant) = data_variant { + let ptr_end = offset + Pointer.size(cx); + for i in 0..variant.fields.count() { + let field_start = variant.fields.offset(i); + if field_start <= offset { + let field = variant.field(cx, i); + result = field.to_result().ok() + .and_then(|field| { + if ptr_end <= field_start + field.size { + // We found the right field, look inside it. + field.pointee_info_at(cx, offset - field_start) + } else { + None + } + }); + if result.is_some() { + break; + } + } + } + } + + // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. + if let Some(ref mut pointee) = result { + if let ty::Adt(def, _) = this.ty.sty { + if def.is_box() && offset.bytes() == 0 { + pointee.safe = Some(PointerKind::UniqueOwned); + } + } + } + + result + } + } + } } struct Niche { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index feedf5741f65b..2f71861d4dc0d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -8,8 +8,8 @@ pub use self::BorrowKind::*; pub use self::IntVarValue::*; pub use self::fold::TypeFoldable; -use crate::hir::{map as hir_map, FreevarMap, GlobMap, TraitMap}; -use crate::hir::{HirId, Node}; +use crate::hir::{map as hir_map, UpvarMap, GlobMap, TraitMap}; +use crate::hir::Node; use crate::hir::def::{Res, DefKind, CtorOf, CtorKind, ExportMap}; use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_data_structures::svh::Svh; @@ -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; @@ -122,7 +122,7 @@ mod sty; #[derive(Clone)] pub struct Resolutions { - pub freevars: FreevarMap, + pub upvars: UpvarMap, pub trait_map: TraitMap, pub maybe_unused_trait_imports: NodeSet, pub maybe_unused_extern_crates: Vec<(NodeId, Span)>, @@ -979,7 +979,7 @@ impl<'a, 'gcx, 'tcx> Generics { param: &ParamTy, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx GenericParamDef { - if let Some(index) = param.idx.checked_sub(self.parent_count as u32) { + if let Some(index) = param.index.checked_sub(self.parent_count as u32) { let param = &self.params[index as usize]; match param.kind { GenericParamDefKind::Type { .. } => param, @@ -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) } @@ -3120,18 +3120,6 @@ impl Iterator for AssociatedItemsIterator<'_, '_, '_> { } } -impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn with_freevars(self, fid: HirId, f: F) -> T where - F: FnOnce(&[hir::Freevar]) -> T, - { - let def_id = self.hir().local_def_id_from_hir_id(fid); - match self.freevars(def_id) { - None => f(&[]), - Some(d) => f(&d), - } - } -} - fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> AssociatedItem { let id = tcx.hir().as_local_hir_id(def_id).unwrap(); let parent_id = tcx.hir().get_parent_item(id); diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index d10da495ee72b..8e98d4d85b9cc 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -355,7 +355,6 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: // the children of the visible parent (as was done when computing // `visible_parent_map`), looking for the specific child we currently have and then // have access to the re-exported name. - DefPathData::Module(ref mut name) | DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => { let reexport = self.tcx().item_children(visible_parent) .iter() @@ -367,7 +366,7 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: } // Re-exported `extern crate` (#43189). DefPathData::CrateRoot => { - data = DefPathData::Module( + data = DefPathData::TypeNs( self.tcx().original_crate_name(def_id.krate).as_interned_str(), ); } @@ -583,16 +582,16 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: if let Some(hir_id) = self.tcx().hir().as_local_hir_id(did) { p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id))); let mut sep = " "; - for (freevar, upvar_ty) in self.tcx().freevars(did) + for (upvar, upvar_ty) in self.tcx().upvars(did) .as_ref() - .map_or(&[][..], |fv| &fv[..]) + .map_or(&[][..], |v| &v[..]) .iter() .zip(upvar_tys) { p!( write("{}{}:", sep, - self.tcx().hir().name_by_hir_id(freevar.var_id())), + self.tcx().hir().name_by_hir_id(upvar.var_id())), print(upvar_ty)); sep = ", "; } @@ -626,16 +625,16 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: p!(write("@{:?}", self.tcx().hir().span_by_hir_id(hir_id))); } let mut sep = " "; - for (freevar, upvar_ty) in self.tcx().freevars(did) + for (upvar, upvar_ty) in self.tcx().upvars(did) .as_ref() - .map_or(&[][..], |fv| &fv[..]) + .map_or(&[][..], |v| &v[..]) .iter() .zip(upvar_tys) { p!( write("{}{}:", sep, - self.tcx().hir().name_by_hir_id(freevar.var_id())), + self.tcx().hir().name_by_hir_id(upvar.var_id())), print(upvar_ty)); sep = ", "; } @@ -859,15 +858,16 @@ impl TyCtxt<'_, '_, '_> { // (but also some things just print a `DefId` generally so maybe we need this?) fn guess_def_namespace(self, def_id: DefId) -> Namespace { match self.def_key(def_id).disambiguated_data.data { - DefPathData::ValueNs(..) | - DefPathData::EnumVariant(..) | - DefPathData::Field(..) | - DefPathData::AnonConst | - DefPathData::ConstParam(..) | - DefPathData::ClosureExpr | - DefPathData::Ctor => Namespace::ValueNS, - - DefPathData::MacroDef(..) => Namespace::MacroNS, + DefPathData::TypeNs(..) + | DefPathData::CrateRoot + | DefPathData::ImplTrait => Namespace::TypeNS, + + DefPathData::ValueNs(..) + | DefPathData::AnonConst + | DefPathData::ClosureExpr + | DefPathData::Ctor => Namespace::ValueNS, + + DefPathData::MacroNs(..) => Namespace::MacroNS, _ => Namespace::TypeNS, } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index d7b1907074195..2049341327495 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -390,7 +390,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, } (&ty::Param(ref a_p), &ty::Param(ref b_p)) - if a_p.idx == b_p.idx => + if a_p.index == b_p.index => { Ok(a) } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index bab9527dd07f6..cf04d6eac3ae0 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -6,7 +6,7 @@ use crate::hir::def::Namespace; use crate::mir::ProjectionKind; use crate::mir::interpret::ConstValue; -use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid}; +use crate::ty::{self, Lift, Ty, TyCtxt, ConstVid, InferConst}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::print::{FmtPrinter, Printer}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -240,7 +240,7 @@ impl fmt::Debug for Ty<'tcx> { impl fmt::Debug for ty::ParamTy { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}/#{}", self.name, self.idx) + write!(f, "{}/#{}", self.name, self.index) } } @@ -1352,8 +1352,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { ConstValue::ByRef(ptr, alloc) => ConstValue::ByRef(ptr, alloc), - // FIXME(const_generics): implement TypeFoldable for InferConst - ConstValue::Infer(ic) => ConstValue::Infer(ic), + ConstValue::Infer(ic) => ConstValue::Infer(ic.fold_with(folder)), ConstValue::Param(p) => ConstValue::Param(p.fold_with(folder)), ConstValue::Placeholder(p) => ConstValue::Placeholder(p), ConstValue::Scalar(a) => ConstValue::Scalar(a), @@ -1366,8 +1365,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ConstValue::ByRef(..) => false, - // FIXME(const_generics): implement TypeFoldable for InferConst - ConstValue::Infer(_) => false, + ConstValue::Infer(ic) => ic.visit_with(visitor), ConstValue::Param(p) => p.visit_with(visitor), ConstValue::Placeholder(_) => false, ConstValue::Scalar(_) => false, @@ -1376,3 +1374,13 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { } } } + +impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + *self + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false + } +} diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index cca40c379fc11..760f3d60d0571 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -1111,13 +1111,13 @@ pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder>>; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] pub struct ParamTy { - pub idx: u32, + pub index: u32, pub name: InternedString, } impl<'a, 'gcx, 'tcx> ParamTy { pub fn new(index: u32, name: InternedString) -> ParamTy { - ParamTy { idx: index, name: name } + ParamTy { index, name: name } } pub fn for_self() -> ParamTy { @@ -1129,14 +1129,14 @@ impl<'a, 'gcx, 'tcx> ParamTy { } pub fn to_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - tcx.mk_ty_param(self.idx, self.name) + tcx.mk_ty_param(self.index, self.name) } pub fn is_self(&self) -> bool { - // FIXME(#50125): Ignoring `Self` with `idx != 0` might lead to weird behavior elsewhere, + // 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.idx == 0 + self.name == keywords::SelfUpper.name().as_str() && self.index == 0 } } @@ -1763,7 +1763,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_param(&self, index: u32) -> bool { match self.sty { - ty::Param(ref data) => data.idx == index, + ty::Param(ref data) => data.index == index, _ => false, } } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index ed3da31fb89bd..72dfe581ba735 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -547,20 +547,35 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { // Look up the type in the substitutions. It really should be in there. - let opt_ty = self.substs.get(p.idx as usize).map(|k| k.unpack()); + let opt_ty = self.substs.get(p.index as usize).map(|k| k.unpack()); let ty = match opt_ty { Some(UnpackedKind::Type(ty)) => ty, - _ => { + Some(kind) => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( span, - "Type parameter `{:?}` ({:?}/{}) out of range \ + "expected type for `{:?}` ({:?}/{}) but found {:?} \ when substituting (root type={:?}) substs={:?}", p, source_ty, - p.idx, + p.index, + kind, + self.root_ty, + self.substs, + ); + } + None => { + let span = self.span.unwrap_or(DUMMY_SP); + span_bug!( + span, + "type parameter `{:?}` ({:?}/{}) out of range \ + when substituting (root type={:?}) substs={:?}", + p, + source_ty, + p.index, self.root_ty, - self.substs); + self.substs, + ); } }; @@ -570,29 +585,40 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn const_for_param( &self, p: ParamConst, - source_cn: &'tcx ty::Const<'tcx> + source_ct: &'tcx ty::Const<'tcx> ) -> &'tcx ty::Const<'tcx> { // Look up the const in the substitutions. It really should be in there. - let opt_cn = self.substs.get(p.index as usize).map(|k| k.unpack()); - let cn = match opt_cn { - Some(UnpackedKind::Const(cn)) => cn, - _ => { + let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack()); + let ct = match opt_ct { + Some(UnpackedKind::Const(ct)) => ct, + Some(kind) => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( span, - "Const parameter `{:?}` ({:?}/{}) out of range \ - when substituting (root type={:?}) substs={:?}", + "expected const for `{:?}` ({:?}/{}) but found {:?} \ + when substituting substs={:?}", p, - source_cn, + source_ct, + p.index, + kind, + self.substs, + ); + } + None => { + let span = self.span.unwrap_or(DUMMY_SP); + span_bug!( + span, + "const parameter `{:?}` ({:?}/{}) out of range \ + when substituting substs={:?}", + p, + source_ct, p.index, - self.root_ty, self.substs, ); } }; - // FIXME(const_generics): shift const through binders - cn + self.shift_vars_through_binders(ct) } /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs @@ -637,15 +663,15 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { /// As indicated in the diagram, here the same type `&'a int` is substituted once, but in the /// first case we do not increase the De Bruijn index and in the second case we do. The reason /// is that only in the second case have we passed through a fn binder. - fn shift_vars_through_binders(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("shift_vars(ty={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", - ty, self.binders_passed, ty.has_escaping_bound_vars()); + fn shift_vars_through_binders>(&self, val: T) -> T { + debug!("shift_vars(val={:?}, binders_passed={:?}, has_escaping_bound_vars={:?})", + val, self.binders_passed, val.has_escaping_bound_vars()); - if self.binders_passed == 0 || !ty.has_escaping_bound_vars() { - return ty; + if self.binders_passed == 0 || !val.has_escaping_bound_vars() { + return val; } - let result = ty::fold::shift_vars(self.tcx(), &ty, self.binders_passed); + let result = ty::fold::shift_vars(self.tcx(), &val, self.binders_passed); debug!("shift_vars: shifted result = {:?}", result); result diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 0cd1700dd0d75..926c0f8b94919 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1,6 +1,7 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. use crate::hir; +use crate::hir::def::DefKind; use crate::hir::def_id::DefId; use crate::hir::map::DefPathData; use crate::mir::interpret::{sign_extend, truncate}; @@ -21,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)] @@ -446,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![]; } @@ -529,21 +531,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). pub fn is_trait(self, def_id: DefId) -> bool { - if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data { - true - } else { - false - } + self.def_kind(def_id) == Some(DefKind::Trait) } /// Returns `true` if `def_id` refers to a trait alias (i.e., `trait Foo = ...;`), /// and `false` otherwise. pub fn is_trait_alias(self, def_id: DefId) -> bool { - if let DefPathData::TraitAlias(_) = self.def_key(def_id).disambiguated_data.data { - true - } else { - false - } + self.def_kind(def_id) == Some(DefKind::TraitAlias) } /// Returns `true` if this `DefId` refers to the implicit constructor for diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 758a0d63886b1..0200e6c53b69c 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::{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); diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs index 2c4a1ded97f39..70d184240fccd 100644 --- a/src/librustc_codegen_llvm/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -2,8 +2,8 @@ use crate::llvm::{self, AttributePlace}; use crate::builder::Builder; use crate::context::CodegenCx; use crate::type_::Type; -use crate::type_of::{LayoutLlvmExt, PointerKind}; use crate::value::Value; +use crate::type_of::{LayoutLlvmExt}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::mir::operand::OperandValue; @@ -13,7 +13,7 @@ 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; +use rustc::ty::layout::{self, PointerKind}; use libc::c_uint; diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index b15a64c966b1b..f26684d9ef04a 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/builder.rs b/src/librustc_codegen_llvm/builder.rs index 123fda1e215ff..bc2bb97a19e54 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -66,6 +66,12 @@ impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { } } +impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.cx.param_env() + } +} + 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 8c83e9ef538e5..5f47108309fbf 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/context.rs b/src/librustc_codegen_llvm/context.rs index f6956bd5736eb..7bf8f705ea8ad 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -8,7 +8,6 @@ use rustc::hir; use crate::monomorphize::partitioning::CodegenUnit; use crate::type_::Type; -use crate::type_of::PointeeInfo; use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n; @@ -16,7 +15,9 @@ use rustc_data_structures::small_c_str::SmallCStr; use rustc::mir::mono::Stats; use rustc::session::config::{self, DebugInfo}; use rustc::session::Session; -use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout, VariantIdx}; +use rustc::ty::layout::{ + LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv +}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::util::nodemap::FxHashMap; use rustc_target::spec::{HasTargetSpec, Target}; @@ -862,3 +863,9 @@ impl LayoutOf for CodegenCx<'ll, 'tcx> { }) } } + +impl<'tcx, 'll> HasParamEnv<'tcx> for CodegenCx<'ll, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + ty::ParamEnv::reveal_all() + } +} diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index 91496ffbe557a..04c9e93c7a527 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/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index f1b8d532eeb76..274c89659628d 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_of.rs b/src/librustc_codegen_llvm/type_of.rs index cbcc457fda9a2..ff25ed9256613 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -1,10 +1,9 @@ use crate::abi::{FnType, FnTypeExt}; use crate::common::*; use crate::type_::Type; -use rustc::hir; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; -use rustc_target::abi::FloatTy; +use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout}; +use rustc_target::abi::{FloatTy, TyLayoutMethods}; use rustc_mir::monomorphize::item::DefPathBasedNames; use rustc_codegen_ssa::traits::*; @@ -174,28 +173,6 @@ impl<'a, 'tcx> CodegenCx<'a, 'tcx> { } } -#[derive(Copy, Clone, PartialEq, Eq)] -pub enum PointerKind { - /// Most general case, we know no restrictions to tell LLVM. - Shared, - - /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. - Frozen, - - /// `&mut T`, when we know `noalias` is safe for LLVM. - UniqueBorrowed, - - /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. - UniqueOwned -} - -#[derive(Copy, Clone)] -pub struct PointeeInfo { - pub size: Size, - pub align: Align, - pub safe: Option, -} - pub trait LayoutLlvmExt<'tcx> { fn is_llvm_immediate(&self) -> bool; fn is_llvm_scalar_pair<'a>(&self) -> bool; @@ -406,112 +383,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { return pointee; } - let mut result = None; - match self.ty.sty { - ty::RawPtr(mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(mt.ty); - result = Some(PointeeInfo { - size, - align, - safe: None - }); - } - - ty::Ref(_, ty, mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(ty); - - let kind = match mt { - hir::MutImmutable => if cx.type_is_freeze(ty) { - PointerKind::Frozen - } else { - PointerKind::Shared - }, - hir::MutMutable => { - // Previously we would only emit noalias annotations for LLVM >= 6 or in - // panic=abort mode. That was deemed right, as prior versions had many bugs - // in conjunction with unwinding, but later versions didn’t seem to have - // said issues. See issue #31681. - // - // Alas, later on we encountered a case where noalias would generate wrong - // code altogether even with recent versions of LLVM in *safe* code with no - // unwinding involved. See #54462. - // - // For now, do not enable mutable_noalias by default at all, while the - // issue is being figured out. - let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias - .unwrap_or(false); - if mutable_noalias { - PointerKind::UniqueBorrowed - } else { - PointerKind::Shared - } - } - }; - - result = Some(PointeeInfo { - size, - align, - safe: Some(kind) - }); - } - - _ => { - let mut data_variant = match self.variants { - // Within the discriminant field, only the niche itself is - // always initialized, so we only check for a pointer at its - // offset. - // - // If the niche is a pointer, it's either valid (according - // to its type), or null (which the niche field's scalar - // validity range encodes). This allows using - // `dereferenceable_or_null` for e.g., `Option<&T>`, and - // this will continue to work as long as we don't start - // using more niches than just null (e.g., the first page of - // the address space, or unaligned pointers). - layout::Variants::Multiple { - discr_kind: layout::DiscriminantKind::Niche { - dataful_variant, - .. - }, - discr_index, - .. - } if self.fields.offset(discr_index) == offset => - Some(self.for_variant(cx, dataful_variant)), - _ => Some(*self), - }; - - if let Some(variant) = data_variant { - // We're not interested in any unions. - if let layout::FieldPlacement::Union(_) = variant.fields { - data_variant = None; - } - } - - if let Some(variant) = data_variant { - let ptr_end = offset + layout::Pointer.size(cx); - for i in 0..variant.fields.count() { - let field_start = variant.fields.offset(i); - if field_start <= offset { - let field = variant.field(cx, i); - if ptr_end <= field_start + field.size { - // We found the right field, look inside it. - result = field.pointee_info_at(cx, offset - field_start); - break; - } - } - } - } - - // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. - if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = self.ty.sty { - if def.is_box() && offset.bytes() == 0 { - pointee.safe = Some(PointerKind::UniqueOwned); - } - } - } - } - } + let result = Ty::pointee_info_at(*self, cx, offset); cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); result diff --git a/src/librustc_codegen_ssa/back/link.rs b/src/librustc_codegen_ssa/back/link.rs index f25891d77ce53..d5a56f6a09e02 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/src/librustc_codegen_ssa/back/link.rs @@ -95,6 +95,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(sess: &'a Session, ); } } + if sess.opts.debugging_opts.emit_artifact_notifications { + sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename); + } } if sess.opts.cg.save_temps { @@ -1017,12 +1020,10 @@ fn link_args<'a, B: ArchiveBuilder<'a>>(cmd: &mut dyn Linker, } } - // If we're building a dynamic library then some platforms need to make sure - // that all symbols are exported correctly from the dynamic library. - if crate_type != config::CrateType::Executable || - sess.target.target.options.is_like_emscripten { - cmd.export_symbols(tmpdir, crate_type); - } + // If we're building something like a dynamic library then some platforms + // need to make sure that all symbols are exported correctly from the + // dynamic library. + cmd.export_symbols(tmpdir, crate_type); // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main diff --git a/src/librustc_codegen_ssa/back/linker.rs b/src/librustc_codegen_ssa/back/linker.rs index c99fc17dd89a1..926f4febe7bae 100644 --- a/src/librustc_codegen_ssa/back/linker.rs +++ b/src/librustc_codegen_ssa/back/linker.rs @@ -372,6 +372,11 @@ impl<'a> Linker for GccLinker<'a> { } fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { + // Symbol visibility in object files typically takes care of this. + if crate_type == CrateType::Executable { + return; + } + // If we're compiling a dylib, then we let symbol visibility in object // files to take care of whether they're exported or not. // @@ -645,6 +650,11 @@ impl<'a> Linker for MsvcLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { + // Symbol visibility takes care of this typically + if crate_type == CrateType::Executable { + return; + } + let path = tmpdir.join("lib.def"); let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 576bcc8f38e65..6320d8a671ddb 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; @@ -382,11 +382,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)); diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/src/librustc_codegen_ssa/mir/rvalue.rs index 8d3e64c1aa6c7..586db5cfabea4 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/builder.rs b/src/librustc_codegen_ssa/traits/builder.rs index 48142fc9fa9f4..a3f99cd869e28 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/src/librustc_codegen_ssa/traits/builder.rs @@ -10,7 +10,7 @@ use crate::mir::operand::OperandRef; use crate::mir::place::PlaceRef; use crate::MemFlags; use rustc::ty::Ty; -use rustc::ty::layout::{Align, Size}; +use rustc::ty::layout::{Align, Size, HasParamEnv}; use std::ops::Range; use std::iter::TrustedLen; @@ -29,6 +29,8 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: + IntrinsicCallMethods<'tcx> + AsmBuilderMethods<'tcx> + StaticBuilderMethods<'tcx> + + HasParamEnv<'tcx> + { fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self; fn with_cx(cx: &'a Self::CodegenCx) -> Self; diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs index 8fe8b7ecd4709..c237cd8bd2645 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/src/librustc_codegen_ssa/traits/mod.rs @@ -41,6 +41,8 @@ pub use self::type_::{ ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods, }; pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods}; +use rustc::ty::layout::{HasParamEnv}; + use std::fmt; @@ -58,6 +60,7 @@ pub trait CodegenMethods<'tcx>: + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> + + HasParamEnv<'tcx> { } @@ -72,6 +75,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + DeclareMethods<'tcx> + AsmMethods<'tcx> + PreDefineMethods<'tcx> + + HasParamEnv<'tcx> { } diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs index 437515f1e9ab4..b4ba90c61f650 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 f3a1b219f8a84..a2ac64fa7e0c6 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_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs index 6a2b6f1321b88..27ae0b97e5945 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/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 19343a9250df3..fa573907d4c73 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -1,6 +1,7 @@ use std::hash::{Hash, Hasher, BuildHasher}; use std::marker::PhantomData; use std::mem; +use smallvec::SmallVec; use crate::sip128::SipHasher128; use crate::indexed_vec; use crate::bit_set; @@ -318,6 +319,15 @@ impl, CTX> HashStable for Vec { } } +impl HashStable for SmallVec<[A; 1]> where A: HashStable { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (&self[..]).hash_stable(ctx, hasher); + } +} + impl, CTX> HashStable for Box { #[inline] fn hash_stable(&self, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 5b42b049b5b18..02f8eee67b151 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 5cefc35607db0..c74ed5ec30c3c 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -255,7 +255,10 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { /// Computes an user-readable representation of a path, if possible. fn node_path(&self, id: ast::NodeId) -> Option { - self.hir_map().and_then(|map| map.def_path_from_id(id)).map(|path| { + self.hir_map().and_then(|map| { + let hir_id = map.node_to_hir_id(id); + map.def_path_from_hir_id(hir_id) + }).map(|path| { path.data .into_iter() .map(|elem| elem.data.to_string()) @@ -540,12 +543,12 @@ impl FromStr for UserIdentifiedItem { } } -enum NodesMatchingUII<'a, 'hir: 'a> { +enum NodesMatchingUII<'a> { NodesMatchingDirect(option::IntoIter), - NodesMatchingSuffix(hir_map::NodesMatchingSuffix<'a, 'hir>), + NodesMatchingSuffix(Box + 'a>), } -impl<'a, 'hir> Iterator for NodesMatchingUII<'a, 'hir> { +impl<'a> Iterator for NodesMatchingUII<'a> { type Item = ast::NodeId; fn next(&mut self) -> Option { @@ -573,10 +576,12 @@ impl UserIdentifiedItem { fn all_matching_node_ids<'a, 'hir>(&'a self, map: &'a hir_map::Map<'hir>) - -> NodesMatchingUII<'a, 'hir> { + -> NodesMatchingUII<'a> { match *self { ItemViaNode(node_id) => NodesMatchingDirect(Some(node_id).into_iter()), - ItemViaPath(ref parts) => NodesMatchingSuffix(map.nodes_matching_suffix(&parts)), + ItemViaPath(ref parts) => { + NodesMatchingSuffix(Box::new(map.nodes_matching_suffix(&parts))) + } } } @@ -642,8 +647,7 @@ fn print_flowgraph<'a, 'tcx, W: Write>(variants: Vec, // alphanumeric. This does not appear in the rendered graph, so it does not // have to be user friendly. let name = format!( - "hir_id_{}_{}_{}", - hir_id.owner.address_space().index(), + "hir_id_{}_{}", hir_id.owner.as_array_index(), hir_id.local_id.index(), ); @@ -801,8 +805,7 @@ pub fn print_after_hir_lowering<'tcx>( src_name, &mut rdr, box out, - annotation.pp_ann(), - true) + annotation.pp_ann()) }) } @@ -825,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 c8d47339fb365..31f697a724a03 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) { @@ -184,7 +196,7 @@ impl<'a> DiagnosticBuilder<'a> { ) -> &mut Self); forward!(pub fn warn(&mut self, msg: &str) -> &mut Self); forward!(pub fn span_warn>(&mut self, sp: S, msg: &str) -> &mut Self); - forward!(pub fn help(&mut self , msg: &str) -> &mut Self); + forward!(pub fn help(&mut self, msg: &str) -> &mut Self); forward!(pub fn span_help>(&mut self, sp: S, msg: &str, diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index bfc9113c2d41e..59cbd65f05c68 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -16,6 +16,7 @@ use std::borrow::Cow; use std::io::prelude::*; use std::io; use std::cmp::{min, Reverse}; +use std::path::Path; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter, Ansi}; use termcolor::{WriteColor, Color, Buffer}; @@ -52,9 +53,10 @@ pub trait Emitter { /// Emit a structured diagnostic. fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>); - /// Emit a JSON directive. The default is to do nothing; this should only - /// be emitted with --error-format=json. - fn maybe_emit_json_directive(&mut self, _directive: String) {} + /// Emit a notification that an artifact has been output. + /// This is currently only supported for the JSON format, + /// other formats can, and will, simply ignore it. + fn emit_artifact_notification(&mut self, _path: &Path) {} /// Checks if should show explanations about "rustc --explain" fn should_show_explain(&self) -> bool { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index e173e1060cc10..3aa87fad07174 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -26,6 +26,7 @@ use std::borrow::Cow; use std::cell::Cell; use std::{error, fmt}; use std::panic; +use std::path::Path; use termcolor::{ColorSpec, Color}; @@ -294,16 +295,9 @@ impl error::Error for ExplicitBug { pub use diagnostic::{Diagnostic, SubDiagnostic, DiagnosticStyledString, DiagnosticId}; pub use diagnostic_builder::DiagnosticBuilder; -/// A handler deals with two kinds of compiler output. -/// - Errors: certain errors (fatal, bug, unimpl) may cause immediate exit, -/// others log errors for later reporting. -/// - Directives: with --error-format=json, the compiler produces directives -/// that indicate when certain actions have completed, which are useful for -/// Cargo. They may change at any time and should not be considered a public -/// API. -/// -/// This crate's name (rustc_errors) doesn't encompass the directives, because -/// directives were added much later. +/// A handler deals with errors and other compiler output. +/// Certain errors (fatal, bug, unimpl) may cause immediate exit, +/// others log errors for later reporting. pub struct Handler { pub flags: HandlerFlags, @@ -775,8 +769,8 @@ impl Handler { } } - pub fn maybe_emit_json_directive(&self, directive: String) { - self.emitter.borrow_mut().maybe_emit_json_directive(directive); + pub fn emit_artifact_notification(&self, path: &Path) { + self.emitter.borrow_mut().emit_artifact_notification(path); } } diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index 2c83501c86f52..04dad9c5355c5 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 6f5b411946c2d..f404a4f82e672 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::ty::TyCtxt; use rustc_data_structures::fx::FxHashSet; +use syntax::ast::{self, Attribute, NestedMetaItem}; +use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; -use rustc::ty::TyCtxt; -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 6d3115c621343..c5ac8860ccd9b 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -180,7 +180,7 @@ impl ExpansionResult { ExpansionResult { defs: Steal::new(resolver.definitions), resolutions: Steal::new(Resolutions { - freevars: resolver.freevars, + upvars: resolver.upvars, export_map: resolver.export_map, trait_map: resolver.trait_map, glob_map: resolver.glob_map, @@ -199,7 +199,7 @@ impl ExpansionResult { ExpansionResult { defs: Steal::new(resolver.definitions.clone()), resolutions: Steal::new(Resolutions { - freevars: resolver.freevars.clone(), + upvars: resolver.upvars.clone(), export_map: resolver.export_map.clone(), trait_map: resolver.trait_map.clone(), glob_map: resolver.glob_map.clone(), @@ -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>( @@ -1048,14 +1048,11 @@ fn encode_and_write_metadata<'tcx>( tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)) }); let metadata_filename = emit_metadata(tcx.sess, &metadata, &metadata_tmpdir); - match std::fs::rename(&metadata_filename, &out_filename) { - Ok(_) => { - if tcx.sess.opts.debugging_opts.emit_directives { - tcx.sess.parse_sess.span_diagnostic.maybe_emit_json_directive( - format!("metadata file written: {}", out_filename.display())); - } - } - Err(e) => tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)), + if let Err(e) = fs::rename(&metadata_filename, &out_filename) { + tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); + } + if tcx.sess.opts.debugging_opts.emit_artifact_notifications { + tcx.sess.parse_sess.span_diagnostic.emit_artifact_notification(&out_filename); } } diff --git a/src/librustc_interface/proc_macro_decls.rs b/src/librustc_interface/proc_macro_decls.rs index 8ed03efd1a784..e9f2f0410d440 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 17523aedffb58..d2d0d19180783 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 f70429c22b68c..af4f1b88b0fb0 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -42,11 +42,10 @@ 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; -use syntax::struct_span_err; use rustc::hir::{self, GenericParamKind, PatKind}; @@ -208,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"); @@ -286,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; } @@ -296,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; } } @@ -356,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); @@ -724,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( @@ -830,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 { .. } => {} @@ -857,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]"; @@ -948,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"); @@ -1383,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, @@ -1438,15 +1437,10 @@ impl KeywordIdents { UnderMacro(under_macro): UnderMacro, ident: ast::Ident) { - let ident_str = &ident.as_str()[..]; - let cur_edition = cx.sess.edition(); - let is_raw_ident = |ident: ast::Ident| { - cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) - }; - let next_edition = match cur_edition { + let next_edition = match cx.sess.edition() { Edition::Edition2015 => { - match ident_str { - "async" | "try" => Edition::Edition2018, + match &ident.as_str()[..] { + "async" | "await" | "try" => Edition::Edition2018, // rust-lang/rust#56327: Conservatively do not // attempt to report occurrences of `dyn` within @@ -1462,43 +1456,16 @@ impl KeywordIdents { // an identifier. "dyn" if !under_macro => Edition::Edition2018, - // Only issue warnings for `await` if the `async_await` - // feature isn't being used. Otherwise, users need - // to keep using `await` for the macro exposed by std. - "await" if !cx.sess.features_untracked().async_await => Edition::Edition2018, _ => return, } } // There are no new keywords yet for the 2018 edition and beyond. - // However, `await` is a "false" keyword in the 2018 edition, - // and can only be used if the `async_await` feature is enabled. - // Otherwise, we emit an error. - _ => { - if "await" == ident_str - && !cx.sess.features_untracked().async_await - && !is_raw_ident(ident) - { - let mut err = struct_span_err!( - cx.sess, - ident.span, - E0721, - "`await` is a keyword in the {} edition", cur_edition, - ); - err.span_suggestion( - ident.span, - "you can use a raw identifier to stay compatible", - "r#await".to_string(), - Applicability::MachineApplicable, - ); - err.emit(); - } - return - }, + _ => return, }; // don't lint `r#foo` - if is_raw_ident(ident) { + if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) { return; } diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 7a003d14b2bf0..551eded9858a3 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 f4ebfd79fe1db..38b6e2c197939 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 92508ad51f104..c3dfd44ad8572 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 169c5e1371833..a4c7daf088ff2 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 160d4c30c0bad..7f2a1c0b4b1d1 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}; @@ -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 || @@ -783,7 +782,7 @@ impl<'a> CrateLoader<'a> { Sanitizer::Leak => LSAN_SUPPORTED_TARGETS, Sanitizer::Memory => MSAN_SUPPORTED_TARGETS, }; - if !supported_targets.contains(&&*self.sess.target.target.llvm_target) { + if !supported_targets.contains(&&*self.sess.opts.target_triple.triple()) { self.sess.err(&format!("{:?}Sanitizer only works with the `{}` target", sanitizer, supported_targets.join("` or `") @@ -794,7 +793,7 @@ impl<'a> CrateLoader<'a> { // firstyear 2017 - during testing I was unable to access an OSX machine // to make this work on different crate types. As a result, today I have // only been able to test and support linux as a target. - if self.sess.target.target.llvm_target == "x86_64-unknown-linux-gnu" { + if self.sess.opts.target_triple.triple() == "x86_64-unknown-linux-gnu" { if !self.sess.crate_types.borrow().iter().all(|ct| { match *ct { // Link the 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 dfeaeca323f8e..087256a971056 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 ad28f47ba0444..e950c2815e9b4 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -9,8 +9,7 @@ use rustc::hir; use rustc::middle::cstore::LinkagePreference; use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::hir::def::{self, Res, DefKind, CtorOf, CtorKind}; -use rustc::hir::def_id::{CrateNum, DefId, DefIndex, DefIndexAddressSpace, - CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc::hir::map::definitions::DefPathTable; use rustc_data_structures::fingerprint::Fingerprint; use rustc::middle::lang_items; @@ -30,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}; @@ -449,7 +448,7 @@ crate fn proc_macro_def_path_table(crate_root: &CrateRoot, proc_macros: &[(ast::Name, Lrc)]) -> DefPathTable { - let mut definitions = Definitions::new(); + let mut definitions = Definitions::default(); let name = crate_root.name.as_str(); let disambiguator = crate_root.disambiguator; @@ -459,8 +458,7 @@ crate fn proc_macro_def_path_table(crate_root: &CrateRoot, let def_index = definitions.create_def_with_parent( crate_root, ast::DUMMY_NODE_ID, - DefPathData::MacroDef(name.as_interned_str()), - DefIndexAddressSpace::High, + DefPathData::MacroNs(name.as_interned_str()), Mark::root(), DUMMY_SP); debug!("definition for {:?} is {:?}", name, def_index); @@ -843,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 f914184b34f54..0ac03526832b7 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}; @@ -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, @@ -586,8 +586,13 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { let data = VariantData { ctor_kind: variant.ctor_kind, discr: variant.discr, + // FIXME(eddyb) deduplicate these with `encode_enum_variant_ctor`. ctor: variant.ctor_def_id.map(|did| did.index), - ctor_sig: None, + ctor_sig: if variant.ctor_kind == CtorKind::Fn { + variant.ctor_def_id.map(|ctor_def_id| self.lazy(&tcx.fn_sig(ctor_def_id))) + } else { + None + }, }; let enum_id = tcx.hir().as_local_hir_id(enum_did).unwrap(); diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index f9543a18c68a7..4c1e39cd0a9e1 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -1,6 +1,6 @@ use crate::schema::*; -use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace}; +use rustc::hir::def_id::{DefId, DefIndex}; use rustc_serialize::opaque::Encoder; use std::u32; use log::debug; @@ -75,14 +75,13 @@ impl FixedSizeEncoding for u32 { /// appropriate spot by calling `record_position`. We should never /// visit the same index twice. pub struct Index { - positions: [Vec; 2] + positions: Vec, } impl Index { - pub fn new((max_index_lo, max_index_hi): (usize, usize)) -> Index { + pub fn new(max_index: usize) -> Index { Index { - positions: [vec![0xff; max_index_lo * 4], - vec![0xff; max_index_hi * 4]], + positions: vec![0xff; max_index * 4], } } @@ -94,10 +93,9 @@ 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 space_index = item.address_space().index(); let array_index = item.as_array_index(); - let positions = &mut self.positions[space_index]; + let positions = &mut self.positions; assert!(u32::read_from_bytes_at(positions, array_index) == u32::MAX, "recorded position for item {:?} twice, first at {:?} and now at {:?}", item, @@ -111,13 +109,10 @@ impl Index { let pos = buf.position(); // First we write the length of the lower range ... - buf.emit_raw_bytes(&(self.positions[0].len() as u32 / 4).to_le_bytes()); - // ... then the values in the lower range ... - buf.emit_raw_bytes(&self.positions[0]); - // ... then the values in the higher range. - buf.emit_raw_bytes(&self.positions[1]); - LazySeq::with_position_and_length(pos as usize, - (self.positions[0].len() + self.positions[1].len()) / 4 + 1) + buf.emit_raw_bytes(&(self.positions.len() as u32 / 4).to_le_bytes()); + // ... then the values. + buf.emit_raw_bytes(&self.positions); + LazySeq::with_position_and_length(pos as usize, self.positions.len() / 4 + 1) } } @@ -131,16 +126,7 @@ impl<'tcx> LazySeq { def_index, self.len); - let i = def_index.as_array_index() + match def_index.address_space() { - DefIndexAddressSpace::Low => 0, - DefIndexAddressSpace::High => { - // This is a DefIndex in the higher range, so find out where - // that starts: - u32::read_from_bytes_at(bytes, 0) as usize - } - }; - - let position = u32::read_from_bytes_at(bytes, 1 + i); + let position = u32::read_from_bytes_at(bytes, 1 + def_index.as_array_index()); if position == u32::MAX { debug!("Index::lookup: position=u32::MAX"); None diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 8343171b99f4b..e780693a5a92d 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -80,7 +80,7 @@ impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { IndexBuilder { - items: Index::new(ecx.tcx.hir().definitions().def_index_counts_lo_hi()), + items: Index::new(ecx.tcx.hir().definitions().def_index_count()), ecx, } } @@ -185,7 +185,7 @@ macro_rules! read_hir { ($t:ty) => { impl<'tcx> DepGraphRead for &'tcx $t { fn read(&self, tcx: TyCtxt<'_, '_, '_>) { - tcx.hir().read_by_hir_id(self.hir_id); + tcx.hir().read(self.hir_id); } } } @@ -219,6 +219,6 @@ pub struct FromId(pub hir::HirId, pub T); impl DepGraphRead for FromId { fn read(&self, tcx: TyCtxt<'_, '_, '_>) { - tcx.hir().read_by_hir_id(self.0); + tcx.hir().read(self.0); } } diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index 6741b5235db36..f4682465a659a 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 116042c53fb9e..7d7dd1061a959 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}; @@ -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)); } diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index e0665127c0fb0..fee08f421549d 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 ed42326d7d520..1a1000f0bb41d 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( @@ -1814,16 +1829,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ty::Array(ty, _) | ty::Slice(ty) => self.describe_field_from_ty(&ty, field, variant_index), ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { - // Convert the def-id into a node-id. node-ids are only valid for - // the local code in the current crate, so this returns an `Option` in case + // `tcx.upvars(def_id)` returns an `Option`, which is `None` in case // the closure comes from another crate. But in that case we wouldn't // be borrowck'ing it, so we can just unwrap: - let hir_id = self.infcx.tcx.hir().as_local_hir_id(def_id).unwrap(); - let freevar = self.infcx - .tcx - .with_freevars(hir_id, |fv| fv[field.index()]); + let upvar = self.infcx.tcx.upvars(def_id).unwrap()[field.index()]; - self.infcx.tcx.hir().name_by_hir_id(freevar.var_id()).to_string() + self.infcx.tcx.hir().name_by_hir_id(upvar.var_id()).to_string() } _ => { // Might need a revision when the fields in trait RFC is implemented @@ -1843,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={:?}", @@ -2613,28 +2624,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { if let hir::ExprKind::Closure( .., args_span, _ ) = expr { - let var_span = self.infcx.tcx.with_freevars( - hir_id, - |freevars| { - for (v, place) in freevars.iter().zip(places) { - match place { - Operand::Copy(place) | - Operand::Move(place) if target_place == place => { - debug!("closure_span: found captured local {:?}", place); - return Some(v.span); - }, - _ => {} - } - } - - None - }, - )?; + for (v, place) in self.infcx.tcx.upvars(def_id)?.iter().zip(places) { + match place { + Operand::Copy(place) | + Operand::Move(place) if target_place == place => { + debug!("closure_span: found captured local {:?}", place); + return Some((*args_span, v.span)); + }, + _ => {} + } + } - Some((*args_span, var_span)) - } else { - None } + None } /// Helper to retrieve span(s) of given borrow from the current MIR 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 c64d4b4a531e0..35efc6195be39 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 ad43c8ef66f42..fa490c108c896 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 4e197867bfb3e..4ced31593b1ae 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 @@ -34,6 +34,7 @@ crate enum RegionNameSource { MatchedAdtAndSegment(Span), AnonRegionFromUpvar(Span, String), AnonRegionFromOutput(Span, String, String), + AnonRegionFromYieldTy(Span, String), } impl RegionName { @@ -48,7 +49,8 @@ impl RegionName { RegionNameSource::MatchedHirTy(..) | RegionNameSource::MatchedAdtAndSegment(..) | RegionNameSource::AnonRegionFromUpvar(..) | - RegionNameSource::AnonRegionFromOutput(..) => false, + RegionNameSource::AnonRegionFromOutput(..) | + RegionNameSource::AnonRegionFromYieldTy(..) => false, } } @@ -105,6 +107,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 +178,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); @@ -676,10 +689,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,6 +734,57 @@ 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 { diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 713e3fe0218ba..5f444d4ceeb88 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 e745ee0f190dd..fbc4835a6557b 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 4e24b6853d6eb..222ce6d1c968e 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 30ed9cef36f7b..15795a64e3b7d 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 83221aca6c5b3..a9d23a0afeabc 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 5ac1ccd8fade2..50140880a368d 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -516,12 +516,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } }; - let upvars = cx.tcx.with_freevars(expr.hir_id, |freevars| { - freevars.iter() - .zip(substs.upvar_tys(def_id, cx.tcx)) - .map(|(fv, ty)| capture_freevar(cx, expr, fv, ty)) - .collect() - }); + let upvars = cx.tcx.upvars(def_id).iter() + .flat_map(|upvars| upvars.iter()) + .zip(substs.upvar_tys(def_id, cx.tcx)) + .map(|(upvar, ty)| capture_upvar(cx, expr, upvar, ty)) + .collect(); ExprKind::Closure { closure_id: def_id, substs, @@ -602,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()), @@ -1185,12 +1177,12 @@ fn overloaded_place<'a, 'gcx, 'tcx>( ExprKind::Deref { arg: ref_expr.to_ref() } } -fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, +fn capture_upvar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_expr: &'tcx hir::Expr, - freevar: &hir::Freevar, - freevar_ty: Ty<'tcx>) + upvar: &hir::Upvar, + upvar_ty: Ty<'tcx>) -> ExprRef<'tcx> { - let var_hir_id = freevar.var_id(); + let var_hir_id = upvar.var_id(); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, closure_expr_id: cx.tcx.hir().local_def_id_from_hir_id(closure_expr.hir_id).to_local(), @@ -1202,7 +1194,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, temp_lifetime, ty: var_ty, span: closure_expr.span, - kind: convert_var(cx, closure_expr, freevar.res), + kind: convert_var(cx, closure_expr, upvar.res), }; match upvar_capture { ty::UpvarCapture::ByValue => captured_var.to_ref(), @@ -1214,7 +1206,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; Expr { temp_lifetime, - ty: freevar_ty, + ty: upvar_ty, span: closure_expr.span, kind: ExprKind::Borrow { borrow_kind, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 7aed0bace8c0b..e8070b21bb8c7 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 2e53bee3f3d7f..d4f139e103a64 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 edd36abc0b8a4..fd4416fc2b763 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 b08499b981cd7..a1b2e6461e5ba 100644 --- a/src/librustc_mir/hair/pattern/check_match.rs +++ b/src/librustc_mir/hair/pattern/check_match.rs @@ -77,6 +77,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> { hir::LocalSource::Normal => "local binding", hir::LocalSource::ForLoopDesugar => "`for` loop binding", hir::LocalSource::AsyncFn => "async fn binding", + hir::LocalSource::AwaitDesugar => "`await` future binding", }); // Check legality of move bindings and `@` patterns. @@ -207,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 } @@ -286,7 +291,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { PatKind::Path(hir::QPath::Resolved(None, ref path)) if path.segments.len() == 1 && path.segments[0].args.is_none() => { format!("interpreted as {} {} pattern, not new variable", - path.res.article(), path.res.kind_name()) + path.res.article(), path.res.descr()) } _ => format!("pattern `{}` not covered", pattern_string), }; @@ -364,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, @@ -412,8 +418,9 @@ fn check_arms<'a, 'tcx>( err.emit(); } - // Unreachable patterns in try expressions occur when one of the arms - // are an uninhabited type. Which is OK. + // Unreachable patterns in try and await expressions occur when one of + // the arms are an uninhabited type. Which is OK. + hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} } } diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 01b1780a2054f..0576bb53d8f42 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 58e474658ead5..2512525b4bb7e 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 ad4bc6a91f5a1..db827afdb94f4 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -175,6 +175,14 @@ impl<'a, 'mir, 'tcx, M> layout::HasTyCtxt<'tcx> for InterpretCx<'a, 'mir, 'tcx, } } +impl<'a, 'mir, 'tcx, M> layout::HasParamEnv<'tcx> for InterpretCx<'a, 'mir, 'tcx, M> + where M: Machine<'a, 'mir, 'tcx> +{ + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } +} + impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> LayoutOf for InterpretCx<'a, 'mir, 'tcx, M> { diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index bd6f005e8736c..0d3ee830574ba 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -66,6 +66,7 @@ macro_rules! try_validation { pub enum PathElem { Field(Symbol), Variant(Symbol), + GeneratorState(VariantIdx), ClosureVar(Symbol), ArrayElem(usize), TupleElem(usize), @@ -100,6 +101,7 @@ fn path_format(path: &Vec) -> String { match elem { Field(name) => write!(out, ".{}", name), Variant(name) => write!(out, ".", name), + GeneratorState(idx) => write!(out, ".", idx.index()), ClosureVar(name) => write!(out, ".", name), TupleElem(idx) => write!(out, ".{}", idx), ArrayElem(idx) => write!(out, "[{}]", idx), @@ -170,7 +172,7 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ValidityVisitor<'rt, 'a, ' if def_id.is_local() { let tables = self.ecx.tcx.typeck_tables_of(def_id); if let Some(upvars) = tables.upvar_list.get(&def_id) { - // Sometimes the index is beyond the number of freevars (seen + // Sometimes the index is beyond the number of upvars (seen // for a generator). if let Some(upvar_id) = upvars.get(field) { let var_hir_id = upvar_id.var_path.hir_id; @@ -262,8 +264,13 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> variant_id: VariantIdx, new_op: OpTy<'tcx, M::PointerTag> ) -> EvalResult<'tcx> { - let name = old_op.layout.ty.ty_adt_def().unwrap().variants[variant_id].ident.name; - self.visit_elem(new_op, PathElem::Variant(name)) + let name = match old_op.layout.ty.sty { + ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name), + // Generators also have variants + ty::Generator(..) => PathElem::GeneratorState(variant_id), + _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty), + }; + self.visit_elem(new_op, name) } #[inline] diff --git a/src/librustc_mir/interpret/visitor.rs b/src/librustc_mir/interpret/visitor.rs index 05343ac66d966..cf67b0a97bcf8 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/src/librustc_mir/interpret/visitor.rs @@ -147,7 +147,7 @@ macro_rules! make_value_visitor { { Ok(()) } - /// Visits this vale as an aggregate, you are even getting an iterator yielding + /// Visits this value as an aggregate, you are getting an iterator yielding /// all the fields (still in an `EvalResult`, you have to do error handling yourself). /// Recurses into the fields. #[inline(always)] @@ -160,7 +160,8 @@ macro_rules! make_value_visitor { } /// Called each time we recurse down to a field of a "product-like" aggregate - /// (structs, tuples, arrays and the like, but not enums), passing in old and new value. + /// (structs, tuples, arrays and the like, but not enums), passing in old (outer) + /// and new (inner) value. /// This gives the visitor the chance to track the stack of nested fields that /// we are descending through. #[inline(always)] @@ -173,18 +174,6 @@ macro_rules! make_value_visitor { self.visit_value(new_val) } - /// Called for recursing into the field of a generator. These are not known to be - /// initialized, so we treat them like unions. - #[inline(always)] - fn visit_generator_field( - &mut self, - _old_val: Self::V, - _field: usize, - new_val: Self::V, - ) -> EvalResult<'tcx> { - self.visit_union(new_val) - } - /// Called when recursing into an enum variant. #[inline(always)] fn visit_variant( @@ -238,7 +227,7 @@ macro_rules! make_value_visitor { fn walk_value(&mut self, v: Self::V) -> EvalResult<'tcx> { trace!("walk_value: type: {}", v.layout().ty); - // If this is a multi-variant layout, we have find the right one and proceed with + // If this is a multi-variant layout, we have to find the right one and proceed with // that. match v.layout().variants { layout::Variants::Multiple { .. } => { @@ -263,6 +252,13 @@ macro_rules! make_value_visitor { // recurse with the inner type return self.visit_field(v, 0, Value::from_mem_place(inner)); }, + ty::Generator(..) => { + // FIXME: Generator layout is lying: it claims a whole bunch of fields exist + // when really many of them can be uninitialized. + // Just treat them as a union for now, until hopefully the layout + // computation is fixed. + return self.visit_union(v); + } _ => {}, }; @@ -304,34 +300,18 @@ macro_rules! make_value_visitor { // Empty unions are not accepted by rustc. That's great, it means we can // use that as an unambiguous signal for detecting primitives. Make sure // we did not miss any primitive. - debug_assert!(fields > 0); + assert!(fields > 0); self.visit_union(v) }, layout::FieldPlacement::Arbitrary { ref offsets, .. } => { - // Special handling needed for generators: All but the first field - // (which is the state) are actually implicitly `MaybeUninit`, i.e., - // they may or may not be initialized, so we cannot visit them. - match v.layout().ty.sty { - ty::Generator(..) => { - let field = v.project_field(self.ecx(), 0)?; - self.visit_aggregate(v, std::iter::once(Ok(field)))?; - for i in 1..offsets.len() { - let field = v.project_field(self.ecx(), i as u64)?; - self.visit_generator_field(v, i, field)?; - } - Ok(()) - } - _ => { - // FIXME: We collect in a vec because otherwise there are lifetime - // errors: Projecting to a field needs access to `ecx`. - let fields: Vec> = - (0..offsets.len()).map(|i| { - v.project_field(self.ecx(), i as u64) - }) - .collect(); - self.visit_aggregate(v, fields.into_iter()) - } - } + // FIXME: We collect in a vec because otherwise there are lifetime + // errors: Projecting to a field needs access to `ecx`. + let fields: Vec> = + (0..offsets.len()).map(|i| { + v.project_field(self.ecx(), i as u64) + }) + .collect(); + self.visit_aggregate(v, fields.into_iter()) }, layout::FieldPlacement::Array { .. } => { // Let's get an mplace first. diff --git a/src/librustc_mir/monomorphize/item.rs b/src/librustc_mir/monomorphize/item.rs index b001a09529e5b..999e7402afd93 100644 --- a/src/librustc_mir/monomorphize/item.rs +++ b/src/librustc_mir/monomorphize/item.rs @@ -3,7 +3,7 @@ use rustc::hir; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::mir::interpret::ConstValue; use rustc::session::config::OptLevel; -use rustc::ty::{self, Ty, TyCtxt, Const, ClosureSubsts, GeneratorSubsts, ParamConst}; +use rustc::ty::{self, Ty, TyCtxt, Const, ClosureSubsts, GeneratorSubsts}; use rustc::ty::subst::{SubstsRef, InternalSubsts}; use syntax::ast; use syntax::attr::InlineAttr; @@ -240,11 +240,11 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { } // Pushes the type name of the specified type to the provided string. - // If 'debug' is true, printing normally unprintable types is allowed - // (e.g. ty::GeneratorWitness). This parameter should only be set when - // this method is being used for logging purposes (e.g. with debug! or info!) - // When being used for codegen purposes, 'debug' should be set to 'false' - // in order to catch unexpected types that should never end up in a type name + // If `debug` is true, printing normally unprintable types is allowed + // (e.g. `ty::GeneratorWitness`). This parameter should only be set when + // this method is being used for logging purposes (e.g. with `debug!` or `info!`) + // When being used for codegen purposes, `debug` should be set to `false` + // in order to catch unexpected types that should never end up in a type name. pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) { match t.sty { ty::Bool => output.push_str("bool"), @@ -387,22 +387,34 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { if debug { output.push_str(&format!("`{:?}`", t)); } else { - bug!("DefPathBasedNames: Trying to create type name for \ - unexpected type: {:?}", t); + bug!( + "DefPathBasedNames: trying to create type name for unexpected type: {:?}", + t, + ); } } } } - // FIXME(const_generics): handle debug printing. + // Pushes the the name of the specified const to the provided string. + // If `debug` is true, usually-unprintable consts (such as `Infer`) will be printed, + // as well as the unprintable types of constants (see `push_type_name` for more details). pub fn push_const_name(&self, c: &Const<'tcx>, output: &mut String, debug: bool) { match c.val { - ConstValue::Infer(..) | ConstValue::Placeholder(_) => output.push_str("_"), - ConstValue::Param(ParamConst { name, .. }) => { - write!(output, "{}", name).unwrap(); + ConstValue::Scalar(..) | ConstValue::Slice(..) | ConstValue::ByRef(..) => { + // FIXME(const_generics): we could probably do a better job here. + write!(output, "{:?}", c).unwrap() + } + _ => { + if debug { + write!(output, "{:?}", c).unwrap() + } else { + bug!( + "DefPathBasedNames: trying to create const name for unexpected const: {:?}", + c, + ); + } } - ConstValue::Unevaluated(..) => output.push_str("_: _"), - _ => write!(output, "{:?}", c).unwrap(), } output.push_str(": "); self.push_type_name(c.ty, output, debug); diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 368bcc333996f..f321e05d68115 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -99,11 +99,11 @@ use std::sync::Arc; use syntax::symbol::InternedString; use rustc::dep_graph::{WorkProductId, WorkProduct, DepNode, DepConstructor}; use rustc::hir::{CodegenFnAttrFlags, HirId}; +use rustc::hir::def::DefKind; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; -use rustc::hir::map::DefPathData; use rustc::mir::mono::{Linkage, Visibility, CodegenUnitNameBuilder}; use rustc::middle::exported_symbols::SymbolExportLevel; -use rustc::ty::{self, TyCtxt, InstanceDef}; +use rustc::ty::{self, DefIdTree, TyCtxt, InstanceDef}; use rustc::ty::print::characteristic_def_id_of_type; use rustc::ty::query::Providers; use rustc::util::common::time; @@ -805,33 +805,27 @@ fn compute_codegen_unit_name(tcx: TyCtxt<'_, '_, '_>, let mut cgu_def_id = None; // Walk backwards from the item we want to find the module for: loop { - let def_key = tcx.def_key(current_def_id); - - match def_key.disambiguated_data.data { - DefPathData::Module(..) => { - if cgu_def_id.is_none() { - cgu_def_id = Some(current_def_id); - } + if current_def_id.index == CRATE_DEF_INDEX { + if cgu_def_id.is_none() { + // If we have not found a module yet, take the crate root. + cgu_def_id = Some(DefId { + krate: def_id.krate, + index: CRATE_DEF_INDEX, + }); } - DefPathData::CrateRoot { .. } => { - if cgu_def_id.is_none() { - // If we have not found a module yet, take the crate root. - cgu_def_id = Some(DefId { - krate: def_id.krate, - index: CRATE_DEF_INDEX, - }); - } - break - } - _ => { - // If we encounter something that is not a module, throw away - // any module that we've found so far because we now know that - // it is nested within something else. - cgu_def_id = None; + break + } else if tcx.def_kind(current_def_id) == Some(DefKind::Mod) { + if cgu_def_id.is_none() { + cgu_def_id = Some(current_def_id); } + } else { + // If we encounter something that is not a module, throw away + // any module that we've found so far because we now know that + // it is nested within something else. + cgu_def_id = None; } - current_def_id.index = def_key.parent.unwrap(); + current_def_id = tcx.parent(current_def_id).unwrap(); } let cgu_def_id = cgu_def_id.unwrap(); diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 078b347fb3f6b..fab07a2290eb5 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::{Symbol, sym}; use std::ops::Bound; @@ -612,7 +612,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/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9a39e07172114..579f75ba51657 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 246f876235d71..815821f6ff033 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 4563c9f18a3e4..a5dfb736b819c 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/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 856783bcbaa46..98ca7c32675c8 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -10,7 +10,7 @@ use rustc::ty::util::IntTypeExt; use rustc_data_structures::indexed_vec::Idx; use crate::util::patch::MirPatch; -use std::u32; +use std::convert::TryInto; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum DropFlagState { @@ -545,10 +545,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.elaborator.patch().new_block(result) } - /// create a loop that drops an array: - /// - + /// Create a loop that drops an array: /// + /// ```text /// loop-block: /// can_go = cur == length_or_end /// if can_go then succ else drop-block @@ -561,15 +560,16 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> /// cur = cur + 1 /// } /// drop(ptr) - fn drop_loop(&mut self, - succ: BasicBlock, - cur: Local, - length_or_end: &Place<'tcx>, - ety: Ty<'tcx>, - unwind: Unwind, - ptr_based: bool) - -> BasicBlock - { + /// ``` + fn drop_loop( + &mut self, + succ: BasicBlock, + cur: Local, + length_or_end: &Place<'tcx>, + ety: Ty<'tcx>, + unwind: Unwind, + ptr_based: bool, + ) -> BasicBlock { let copy = |place: &Place<'tcx>| Operand::Copy(place.clone()); let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); let tcx = self.tcx(); @@ -591,13 +591,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> elem: ProjectionElem::Deref, })) ), - Rvalue::BinaryOp(BinOp::Offset, copy(&Place::Base(PlaceBase::Local(cur))), one)) + Rvalue::BinaryOp(BinOp::Offset, move_(&Place::Base(PlaceBase::Local(cur))), one)) } else { (Rvalue::Ref( tcx.lifetimes.re_erased, BorrowKind::Mut { allow_two_phase_borrow: false }, self.place.clone().index(cur)), - Rvalue::BinaryOp(BinOp::Add, copy(&Place::Base(PlaceBase::Local(cur))), one)) + Rvalue::BinaryOp(BinOp::Add, move_(&Place::Base(PlaceBase::Local(cur))), one)) }; let drop_block = BasicBlockData { @@ -647,9 +647,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // } if let Some(size) = opt_size { - assert!(size <= (u32::MAX as u64), - "move out check doesn't implemented for array bigger then u32"); - let size = size as u32; + let size: u32 = size.try_into().unwrap_or_else(|_| { + bug!("move out check isn't implemented for array sizes bigger than u32::MAX"); + }); let fields: Vec<(Place<'tcx>, Option)> = (0..size).map(|i| { (self.place.clone().elem(ProjectionElem::ConstantIndex{ offset: i, @@ -667,33 +667,42 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> let move_ = |place: &Place<'tcx>| Operand::Move(place.clone()); let tcx = self.tcx(); - let size = &Place::Base(PlaceBase::Local(self.new_temp(tcx.types.usize))); - let size_is_zero = &Place::Base(PlaceBase::Local(self.new_temp(tcx.types.bool))); + let elem_size = &Place::Base(PlaceBase::Local(self.new_temp(tcx.types.usize))); + let len = &Place::Base(PlaceBase::Local(self.new_temp(tcx.types.usize))); + + static USIZE_SWITCH_ZERO: &[u128] = &[0]; + let base_block = BasicBlockData { statements: vec![ - self.assign(size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), - self.assign(size_is_zero, Rvalue::BinaryOp(BinOp::Eq, - move_(size), - self.constant_usize(0))) + self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), + self.assign(len, Rvalue::Len(self.place.clone())), ], is_cleanup: self.unwind.is_cleanup(), terminator: Some(Terminator { source_info: self.source_info, - kind: TerminatorKind::if_( - tcx, - move_(size_is_zero), - self.drop_loop_pair(ety, false), - self.drop_loop_pair(ety, true) - ) + kind: TerminatorKind::SwitchInt { + discr: move_(elem_size), + switch_ty: tcx.types.usize, + values: From::from(USIZE_SWITCH_ZERO), + targets: vec![ + self.drop_loop_pair(ety, false, len.clone()), + self.drop_loop_pair(ety, true, len.clone()), + ], + }, }) }; self.elaborator.patch().new_block(base_block) } - // create a pair of drop-loops of `place`, which drops its contents - // even in the case of 1 panic. If `ptr_based`, create a pointer loop, - // otherwise create an index loop. - fn drop_loop_pair(&mut self, ety: Ty<'tcx>, ptr_based: bool) -> BasicBlock { + /// Ceates a pair of drop-loops of `place`, which drops its contents, even + /// in the case of 1 panic. If `ptr_based`, creates a pointer loop, + /// otherwise create an index loop. + fn drop_loop_pair( + &mut self, + ety: Ty<'tcx>, + ptr_based: bool, + length: Place<'tcx>, + ) -> BasicBlock { debug!("drop_loop_pair({:?}, {:?})", ety, ptr_based); let tcx = self.tcx(); let iter_ty = if ptr_based { @@ -703,7 +712,6 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> }; let cur = self.new_temp(iter_ty); - let length = Place::Base(PlaceBase::Local(self.new_temp(tcx.types.usize))); let length_or_end = if ptr_based { // FIXME check if we want to make it return a `Place` directly // if all use sites want a `Place::Base` anyway. @@ -722,9 +730,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ptr_based) }); - let succ = self.succ; // FIXME(#43234) let loop_block = self.drop_loop( - succ, + self.succ, cur, &length_or_end, ety, @@ -732,31 +739,32 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> ptr_based); let cur = Place::Base(PlaceBase::Local(cur)); - let zero = self.constant_usize(0); - let mut drop_block_stmts = vec![]; - drop_block_stmts.push(self.assign(&length, Rvalue::Len(self.place.clone()))); - if ptr_based { + let drop_block_stmts = if ptr_based { let tmp_ty = tcx.mk_mut_ptr(self.place_ty(self.place)); let tmp = Place::Base(PlaceBase::Local(self.new_temp(tmp_ty))); // tmp = &mut P; // cur = tmp as *mut T; // end = Offset(cur, len); - drop_block_stmts.push(self.assign(&tmp, Rvalue::Ref( - tcx.lifetimes.re_erased, - BorrowKind::Mut { allow_two_phase_borrow: false }, - self.place.clone() - ))); - drop_block_stmts.push(self.assign(&cur, Rvalue::Cast( - CastKind::Misc, Operand::Move(tmp), iter_ty - ))); - drop_block_stmts.push(self.assign(&length_or_end, - Rvalue::BinaryOp(BinOp::Offset, - Operand::Copy(cur), Operand::Move(length) - ))); + vec![ + self.assign(&tmp, Rvalue::Ref( + tcx.lifetimes.re_erased, + BorrowKind::Mut { allow_two_phase_borrow: false }, + self.place.clone() + )), + self.assign( + &cur, + Rvalue::Cast(CastKind::Misc, Operand::Move(tmp), iter_ty), + ), + self.assign( + &length_or_end, + Rvalue::BinaryOp(BinOp::Offset, Operand::Copy(cur), Operand::Move(length) + )), + ] } else { - // index = 0 (length already pushed) - drop_block_stmts.push(self.assign(&cur, Rvalue::Use(zero))); - } + // cur = 0 (length already pushed) + let zero = self.constant_usize(0); + vec![self.assign(&cur, Rvalue::Use(zero))] + }; let drop_block = self.elaborator.patch().new_block(BasicBlockData { statements: drop_block_stmts, is_cleanup: unwind.is_cleanup(), @@ -768,7 +776,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // FIXME(#34708): handle partially-dropped array/slice elements. let reset_block = self.drop_flag_reset_block(DropFlagMode::Deep, drop_block, unwind); - self.drop_flag_test_block(reset_block, succ, unwind) + self.drop_flag_test_block(reset_block, self.succ, unwind) } /// The slow-path - create an "open", elaborated drop for a type diff --git a/src/librustc_mir/util/graphviz.rs b/src/librustc_mir/util/graphviz.rs index f87714b58c442..188da9a82dc99 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/src/librustc_mir/util/graphviz.rs @@ -25,9 +25,8 @@ pub fn write_mir_graphviz<'tcx, W>(tcx: TyCtxt<'_, '_, 'tcx>, // it does not have to be user friendly. pub fn graphviz_safe_def_name(def_id: DefId) -> String { format!( - "{}_{}_{}", + "{}_{}", def_id.krate.index(), - def_id.index.address_space().index(), def_id.index.as_array_index(), ) } @@ -168,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 1f5a6d7914125..2bea1db841ae9 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -15,13 +15,13 @@ 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}; use syntax_ext::proc_macro_decls::is_proc_macro_attr; use syntax_pos::{Span, MultiSpan}; -use errors::Applicability; +use errors::{Applicability, FatalError}; use log::debug; #[derive(Copy, Clone, Debug)] @@ -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, } @@ -368,6 +368,8 @@ fn validate_generics_order<'a>( let mut max_param: Option = None; let mut out_of_order = FxHashMap::default(); let mut param_idents = vec![]; + let mut found_type = false; + let mut found_const = false; for (kind, bounds, span, ident) in generics { if let Some(ident) = ident { @@ -381,6 +383,11 @@ fn validate_generics_order<'a>( } Some(_) | None => *max_param = Some(kind), }; + match kind { + ParamKindOrd::Type => found_type = true, + ParamKindOrd::Const => found_const = true, + _ => {} + } } let mut ordered_params = "<".to_string(); @@ -408,8 +415,8 @@ fn validate_generics_order<'a>( GenericPosition::Arg => "argument", }; - for (param_ord, (max_param, spans)) in out_of_order { - let mut err = handler.struct_span_err(spans, + for (param_ord, (max_param, spans)) in &out_of_order { + let mut err = handler.struct_span_err(spans.clone(), &format!( "{} {pos}s must be declared prior to {} {pos}s", param_ord, @@ -430,6 +437,13 @@ fn validate_generics_order<'a>( } err.emit(); } + + // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs + // if we don't. Const parameters and type parameters can currently conflict if they + // are out-of-order. + if !out_of_order.is_empty() && found_type && found_const { + FatalError.raise(); + } } impl<'a> Visitor<'a> for AstValidator<'a> { @@ -551,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; } @@ -662,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 6940f8f442ee9..dea5774aa6eb7 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -7,10 +7,12 @@ use rustc::ty::layout::HasTyCtxt; use rustc::ty::layout::LayoutOf; use rustc::ty::layout::TargetDataLayout; use rustc::ty::layout::TyLayout; +use rustc::ty::layout::HasParamEnv; 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 { @@ -31,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); } } @@ -53,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!( @@ -122,6 +124,12 @@ impl<'me, 'tcx> HasTyCtxt<'tcx> for UnwrapLayoutCx<'me, 'tcx> { } } +impl<'me, 'tcx> HasParamEnv<'tcx> for UnwrapLayoutCx<'me, 'tcx> { + fn param_env(&self) -> ParamEnv<'tcx> { + self.param_env + } +} + impl<'me, 'tcx> HasDataLayout for UnwrapLayoutCx<'me, 'tcx> { fn data_layout(&self) -> &TargetDataLayout { self.tcx.data_layout() diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index b6e2aacd55954..37917aaa4a80f 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; @@ -449,7 +450,8 @@ fn check_expr_kind<'a, 'tcx>( let nested_body_promotable = v.check_nested_body(body_id); // Paths in constant contexts cannot refer to local variables, // as there are none, and thus closures can't have upvars there. - if v.tcx.with_freevars(e.hir_id, |fv| !fv.is_empty()) { + let closure_def_id = v.tcx.hir().local_def_id_from_hir_id(e.hir_id); + if !v.tcx.upvars(closure_def_id).map_or(true, |v| v.is_empty()) { NotPromotable } else { nested_body_promotable @@ -517,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 31018a7cd7a3c..8259419c64aeb 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/lib.rs b/src/librustc_plugin/lib.rs index 3775dbb79c6fd..cb6f8ebd82e4e 100644 --- a/src/librustc_plugin/lib.rs +++ b/src/librustc_plugin/lib.rs @@ -47,8 +47,9 @@ //! #![plugin(myplugin)] //! ``` //! -//! See the [`plugin` feature](../unstable-book/language-features/plugin.html) of -//! the Unstable Book for more examples. +//! See the [`plugin` +//! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) +//! of the Unstable Book for more examples. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs index 8b86bddb29f4e..680bdcc4bbe97 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 5c5b6f232b271..c2d1d5fa65af2 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 e561b387389e7..cd21713cddf97 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/Cargo.toml b/src/librustc_resolve/Cargo.toml index 836b4ad38ca88..968a45e241e84 100644 --- a/src/librustc_resolve/Cargo.toml +++ b/src/librustc_resolve/Cargo.toml @@ -20,3 +20,4 @@ errors = { path = "../librustc_errors", package = "rustc_errors" } syntax_pos = { path = "../libsyntax_pos" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_metadata = { path = "../librustc_metadata" } +smallvec = { version = "0.6.7", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3c5760c746fc3..f70ca6f859b98 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( @@ -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/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index bbfc39fc6eaf0..509aa95bb61df 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -41,7 +41,7 @@ impl<'a> Resolver<'a> { let item_str = path.last().unwrap().ident; let code = source.error_code(res.is_some()); let (base_msg, fallback_label, base_span) = if let Some(res) = res { - (format!("expected {}, found {} `{}`", expected, res.kind_name(), path_str), + (format!("expected {}, found {} `{}`", expected, res.descr(), path_str), format!("not a {}", expected), span) } else { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e0892f98d3147..678f4c23d3e9e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -17,6 +17,7 @@ pub use rustc::hir::def::{Namespace, PerNS}; use GenericParameters::*; use RibKind::*; +use smallvec::smallvec; use rustc::hir::map::{Definitions, DefCollector}; use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str}; @@ -24,11 +25,11 @@ use rustc::middle::cstore::CrateStore; use rustc::session::Session; use rustc::lint; use rustc::hir::def::{ - self, DefKind, PathResolution, CtorKind, CtorOf, NonMacroAttrKind, ResMap, ImportMap, ExportMap + self, DefKind, PartialRes, CtorKind, CtorOf, NonMacroAttrKind, ExportMap }; use rustc::hir::def::Namespace::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, DefId}; -use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; +use rustc::hir::{Upvar, UpvarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::ty::{self, DefIdTree}; use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap}; use rustc::{bug, span_bug}; @@ -42,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}; @@ -66,6 +67,7 @@ use std::collections::BTreeSet; use std::mem::replace; use rustc_data_structures::ptr_key::PtrKey; use rustc_data_structures::sync::Lrc; +use smallvec::SmallVec; use diagnostics::{find_span_of_binding_until_next_binding, extend_span_to_previous_binding}; use resolve_imports::{ImportDirective, ImportDirectiveSubclass, NameResolution, ImportResolver}; @@ -821,7 +823,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> { let self_ty = keywords::SelfUpper.ident(); let res = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.id), ty.span) .map_or(Res::Err, |d| d.res()); - self.record_res(ty.id, PathResolution::new(res)); + self.record_partial_res(ty.id, PartialRes::new(res)); } _ => (), } @@ -1071,13 +1073,13 @@ enum RibKind<'a> { /// The resolution keeps a separate stack of ribs as it traverses the AST for each namespace. When /// resolving, the name is looked up from inside out. #[derive(Debug)] -struct Rib<'a> { - bindings: FxHashMap, +struct Rib<'a, R = Res> { + bindings: FxHashMap, kind: RibKind<'a>, } -impl<'a> Rib<'a> { - fn new(kind: RibKind<'a>) -> Rib<'a> { +impl<'a, R> Rib<'a, R> { + fn new(kind: RibKind<'a>) -> Rib<'a, R> { Rib { bindings: Default::default(), kind, @@ -1146,7 +1148,7 @@ impl ModuleOrUniformRoot<'_> { #[derive(Clone, Debug)] enum PathResult<'a> { Module(ModuleOrUniformRoot<'a>), - NonModule(PathResolution), + NonModule(PartialRes), Indeterminate, Failed { span: Span, @@ -1532,7 +1534,7 @@ impl<'a> NameBinding<'a> { } fn descr(&self) -> &'static str { - if self.is_extern_crate() { "extern crate" } else { self.res().kind_name() } + if self.is_extern_crate() { "extern crate" } else { self.res().descr() } } fn article(&self) -> &'static str { @@ -1638,7 +1640,7 @@ pub struct Resolver<'a> { ribs: PerNS>>, /// The current set of local scopes, for labels. - label_ribs: Vec>, + label_ribs: Vec>, /// The trait that the current context can refer to. current_trait_ref: Option<(Module<'a>, TraitRef)>, @@ -1659,10 +1661,15 @@ pub struct Resolver<'a> { /// The idents for the primitive types. primitive_type_table: PrimitiveTypeTable, - res_map: ResMap, - import_map: ImportMap, - pub freevars: FreevarMap, - freevars_seen: NodeMap>, + /// Resolutions for nodes that have a single resolution. + partial_res_map: NodeMap, + /// Resolutions for import nodes, which have multiple resolutions in different namespaces. + import_res_map: NodeMap>>, + /// Resolutions for labels (node IDs of their corresponding blocks or loops). + label_res_map: NodeMap, + + pub upvars: UpvarMap, + upvars_seen: NodeMap>, pub export_map: ExportMap, pub trait_map: TraitMap, @@ -1805,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() { @@ -1818,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::>(); @@ -1830,12 +1837,16 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { self.resolve_hir_path(&path, is_value) } - fn get_resolution(&mut self, id: NodeId) -> Option { - self.res_map.get(&id).cloned() + fn get_partial_res(&mut self, id: NodeId) -> Option { + self.partial_res_map.get(&id).cloned() + } + + fn get_import_res(&mut self, id: NodeId) -> PerNS> { + self.import_res_map.get(&id).cloned().unwrap_or_default() } - fn get_import(&mut self, id: NodeId) -> PerNS> { - self.import_map.get(&id).cloned().unwrap_or_default() + fn get_label_res(&mut self, id: NodeId) -> Option { + self.label_res_map.get(&id).cloned() } fn definitions(&mut self) -> &mut Definitions { @@ -1919,7 +1930,7 @@ impl<'a> Resolver<'a> { let segments: Vec<_> = segments.iter().map(|seg| { let mut hir_seg = hir::PathSegment::from_ident(seg.ident); - hir_seg.res = Some(self.res_map.get(&seg.id).map_or(def::Res::Err, |p| { + hir_seg.res = Some(self.partial_res_map.get(&seg.id).map_or(def::Res::Err, |p| { p.base_res().map_id(|_| panic!("unexpected node_id")) })); hir_seg @@ -1953,13 +1964,13 @@ 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(); module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); - let mut definitions = Definitions::new(); + let mut definitions = Definitions::default(); DefCollector::new(&mut definitions, Mark::root()) .collect_root(crate_name, session.local_crate_disambiguator()); @@ -1967,9 +1978,9 @@ 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") { + if !attr::contains_name(&krate.attrs, sym::no_core) { extern_prelude.insert(Ident::from_str("core"), Default::default()); - if !attr::contains_name(&krate.attrs, "no_std") { + if !attr::contains_name(&krate.attrs, sym::no_std) { extern_prelude.insert(Ident::from_str("std"), Default::default()); if session.rust_2018() { extern_prelude.insert(Ident::from_str("meta"), Default::default()); @@ -2019,10 +2030,11 @@ impl<'a> Resolver<'a> { primitive_type_table: PrimitiveTypeTable::new(), - res_map: Default::default(), - import_map: Default::default(), - freevars: Default::default(), - freevars_seen: Default::default(), + partial_res_map: Default::default(), + import_res_map: Default::default(), + label_res_map: Default::default(), + upvars: Default::default(), + upvars_seen: Default::default(), export_map: FxHashMap::default(), trait_map: Default::default(), module_map, @@ -2487,7 +2499,7 @@ impl<'a> Resolver<'a> { /// /// Stops after meeting a closure. fn search_label(&self, mut ident: Ident, pred: P) -> Option - where P: Fn(&Rib<'_>, Ident) -> Option + where P: Fn(&Rib<'_, NodeId>, Ident) -> Option { for rib in self.label_ribs.iter().rev() { match rib.kind { @@ -2705,7 +2717,7 @@ impl<'a> Resolver<'a> { self.definitions.local_def_id(param.id), ); function_type_rib.bindings.insert(ident, res); - self.record_res(param.id, PathResolution::new(res)); + self.record_partial_res(param.id, PartialRes::new(res)); } GenericParamKind::Const { .. } => { let ident = param.ident.modern(); @@ -2726,7 +2738,7 @@ impl<'a> Resolver<'a> { self.definitions.local_def_id(param.id), ); function_value_rib.bindings.insert(ident, res); - self.record_res(param.id, PathResolution::new(res)); + self.record_partial_res(param.id, PartialRes::new(res)); } } } @@ -2994,7 +3006,8 @@ impl<'a> Resolver<'a> { pat.walk(&mut |pat| { if let PatKind::Ident(binding_mode, ident, ref sub_pat) = pat.node { - if sub_pat.is_some() || match self.res_map.get(&pat.id).map(|res| res.base_res()) { + if sub_pat.is_some() || match self.partial_res_map.get(&pat.id) + .map(|res| res.base_res()) { Some(Res::Local(..)) => true, _ => false, } { @@ -3146,7 +3159,7 @@ impl<'a> Resolver<'a> { outer_pat_id: NodeId, pat_src: PatternSource, bindings: &mut FxHashMap) - -> PathResolution { + -> Res { // Add the binding to the local ribs, if it // doesn't already exist in the bindings map. (We // must not add it if it's in the bindings map @@ -3193,7 +3206,7 @@ impl<'a> Resolver<'a> { } } - PathResolution::new(res) + res } fn resolve_pattern(&mut self, @@ -3213,7 +3226,7 @@ impl<'a> Resolver<'a> { let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None, pat.span) .and_then(LexicalScopeBinding::item); - let resolution = binding.map(NameBinding::res).and_then(|res| { + let res = binding.map(NameBinding::res).and_then(|res| { let is_syntactic_ambiguity = opt_pat.is_none() && bmode == BindingMode::ByValue(Mutability::Immutable); match res { @@ -3222,7 +3235,7 @@ impl<'a> Resolver<'a> { // Disambiguate in favor of a unit struct/variant // or constant pattern. self.record_use(ident, ValueNS, binding.unwrap(), false); - Some(PathResolution::new(res)) + Some(res) } Res::Def(DefKind::Ctor(..), _) | Res::Def(DefKind::Const, _) @@ -3254,7 +3267,7 @@ impl<'a> Resolver<'a> { self.fresh_binding(ident, pat.id, outer_pat_id, pat_src, bindings) }); - self.record_res(pat.id, resolution); + self.record_partial_res(pat.id, PartialRes::new(res)); } PatKind::TupleStruct(ref path, ..) => { @@ -3286,35 +3299,15 @@ impl<'a> Resolver<'a> { id: NodeId, qself: Option<&QSelf>, path: &Path, - source: PathSource<'_>) - -> PathResolution { - self.smart_resolve_path_with_crate_lint(id, qself, path, source, CrateLint::SimplePath(id)) - } - - /// A variant of `smart_resolve_path` where you also specify extra - /// information about where the path came from; this extra info is - /// sometimes needed for the lint that recommends rewriting - /// absolute paths to `crate`, so that it knows how to frame the - /// suggestion. If you are just resolving a path like `foo::bar` - /// that appears in an arbitrary location, then you just want - /// `CrateLint::SimplePath`, which is what `smart_resolve_path` - /// already provides. - fn smart_resolve_path_with_crate_lint( - &mut self, - id: NodeId, - qself: Option<&QSelf>, - path: &Path, - source: PathSource<'_>, - crate_lint: CrateLint - ) -> PathResolution { + source: PathSource<'_>) { self.smart_resolve_path_fragment( id, qself, &Segment::from_path(path), path.span, source, - crate_lint, - ) + CrateLint::SimplePath(id), + ); } fn smart_resolve_path_fragment(&mut self, @@ -3324,7 +3317,7 @@ impl<'a> Resolver<'a> { span: Span, source: PathSource<'_>, crate_lint: CrateLint) - -> PathResolution { + -> PartialRes { let ns = source.namespace(); let is_expected = &|res| source.is_expected(res); @@ -3334,10 +3327,10 @@ impl<'a> Resolver<'a> { let node_id = this.definitions.as_local_node_id(def_id).unwrap(); let better = res.is_some(); this.use_injections.push(UseError { err, candidates, node_id, better }); - err_path_resolution() + PartialRes::new(Res::Err) }; - let resolution = match self.resolve_qpath_anywhere( + let partial_res = match self.resolve_qpath_anywhere( id, qself, path, @@ -3347,14 +3340,14 @@ impl<'a> Resolver<'a> { source.global_by_default(), crate_lint, ) { - Some(resolution) if resolution.unresolved_segments() == 0 => { - if is_expected(resolution.base_res()) || resolution.base_res() == Res::Err { - resolution + Some(partial_res) if partial_res.unresolved_segments() == 0 => { + if is_expected(partial_res.base_res()) || partial_res.base_res() == Res::Err { + partial_res } else { // Add a temporary hack to smooth the transition to new struct ctor // visibility rules. See #38932 for more details. let mut res = None; - if let Res::Def(DefKind::Struct, def_id) = resolution.base_res() { + if let Res::Def(DefKind::Struct, def_id) = partial_res.base_res() { if let Some((ctor_res, ctor_vis)) = self.struct_constructors.get(&def_id).cloned() { if is_expected(ctor_res) && self.is_accessible(ctor_vis) { @@ -3363,15 +3356,15 @@ impl<'a> Resolver<'a> { "private struct constructors are not usable through \ re-exports in outer modules", ); - res = Some(PathResolution::new(ctor_res)); + res = Some(PartialRes::new(ctor_res)); } } } - res.unwrap_or_else(|| report_errors(self, Some(resolution.base_res()))) + res.unwrap_or_else(|| report_errors(self, Some(partial_res.base_res()))) } } - Some(resolution) if source.defer_to_typeck() => { + Some(partial_res) if source.defer_to_typeck() => { // Not fully resolved associated item `T::A::B` or `::A::B` // or `::A::B`. If `B` should be resolved in value namespace then // it needs to be added to the trait map. @@ -3399,16 +3392,16 @@ impl<'a> Resolver<'a> { hm.insert(span, span); } } - resolution + partial_res } _ => report_errors(self, None) }; if let PathSource::TraitItem(..) = source {} else { // Avoid recording definition of `A::B` in `::B::C`. - self.record_res(id, resolution); + self.record_partial_res(id, partial_res); } - resolution + partial_res } /// Only used in a specific case of type ascription suggestions @@ -3523,7 +3516,7 @@ impl<'a> Resolver<'a> { defer_to_typeck: bool, global_by_default: bool, crate_lint: CrateLint, - ) -> Option { + ) -> Option { let mut fin_res = None; // FIXME: can't resolve paths in macro namespace yet, macros are // processed by the little special hack below. @@ -3532,9 +3525,10 @@ impl<'a> Resolver<'a> { match self.resolve_qpath(id, qself, path, ns, span, global_by_default, crate_lint) { // If defer_to_typeck, then resolution > no resolution, // otherwise full resolution > partial resolution > no resolution. - Some(res) if res.unresolved_segments() == 0 || defer_to_typeck => - return Some(res), - res => if fin_res.is_none() { fin_res = res }, + Some(partial_res) if partial_res.unresolved_segments() == 0 || + defer_to_typeck => + return Some(partial_res), + partial_res => if fin_res.is_none() { fin_res = partial_res }, }; } } @@ -3545,7 +3539,7 @@ impl<'a> Resolver<'a> { self.macro_use_prelude.get(&path[0].ident.name).cloned() .and_then(NameBinding::macro_kind) == Some(MacroKind::Bang)) { // Return some dummy definition, it's enough for error reporting. - return Some(PathResolution::new(Res::Def( + return Some(PartialRes::new(Res::Def( DefKind::Macro(MacroKind::Bang), DefId::local(CRATE_DEF_INDEX), ))); @@ -3563,7 +3557,7 @@ impl<'a> Resolver<'a> { span: Span, global_by_default: bool, crate_lint: CrateLint, - ) -> Option { + ) -> Option { debug!( "resolve_qpath(id={:?}, qself={:?}, path={:?}, \ ns={:?}, span={:?}, global_by_default={:?})", @@ -3580,7 +3574,7 @@ impl<'a> Resolver<'a> { // This is a case like `::B`, where there is no // trait to resolve. In that case, we leave the `B` // segment to be resolved by type-check. - return Some(PathResolution::with_unresolved_segments( + return Some(PartialRes::with_unresolved_segments( Res::Def(DefKind::Mod, DefId::local(CRATE_DEF_INDEX)), path.len() )); } @@ -3600,7 +3594,7 @@ impl<'a> Resolver<'a> { // name from a fully qualified path, and this also // contains the full span (the `CrateLint::QPathTrait`). let ns = if qself.position + 1 == path.len() { ns } else { TypeNS }; - let res = self.smart_resolve_path_fragment( + let partial_res = self.smart_resolve_path_fragment( id, None, &path[..=qself.position], @@ -3615,8 +3609,9 @@ impl<'a> Resolver<'a> { // The remaining segments (the `C` in our example) will // have to be resolved by type-check, since that requires doing // trait resolution. - return Some(PathResolution::with_unresolved_segments( - res.base_res(), res.unresolved_segments() + path.len() - qself.position - 1 + return Some(PartialRes::with_unresolved_segments( + partial_res.base_res(), + partial_res.unresolved_segments() + path.len() - qself.position - 1, )); } @@ -3629,7 +3624,7 @@ impl<'a> Resolver<'a> { ) { PathResult::NonModule(path_res) => path_res, PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { - PathResolution::new(module.res().unwrap()) + PartialRes::new(module.res().unwrap()) } // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we // don't report an error right away, but try to fallback to a primitive type. @@ -3649,13 +3644,13 @@ impl<'a> Resolver<'a> { self.primitive_type_table.primitive_types .contains_key(&path[0].ident.name) => { let prim = self.primitive_type_table.primitive_types[&path[0].ident.name]; - PathResolution::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) + PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1) } PathResult::Module(ModuleOrUniformRoot::Module(module)) => - PathResolution::new(module.res().unwrap()), + PartialRes::new(module.res().unwrap()), PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => { resolve_error(self, span, ResolutionError::FailedToResolve { label, suggestion }); - err_path_resolution() + PartialRes::new(Res::Err) } PathResult::Module(..) | PathResult::Failed { .. } => return None, PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), @@ -3731,9 +3726,9 @@ impl<'a> Resolver<'a> { let record_segment_res = |this: &mut Self, res| { if record_used { if let Some(id) = id { - if !this.res_map.contains_key(&id) { + if !this.partial_res_map.contains_key(&id) { assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_res(id, PathResolution::new(res)); + this.record_partial_res(id, PartialRes::new(res)); } } } @@ -3837,7 +3832,7 @@ impl<'a> Resolver<'a> { Some(LexicalScopeBinding::Res(res)) if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => { record_segment_res(self, res); - return PathResult::NonModule(PathResolution::with_unresolved_segments( + return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - 1 )); } @@ -3864,9 +3859,9 @@ impl<'a> Resolver<'a> { ).emit(); } let res = Res::NonMacroAttr(NonMacroAttrKind::Tool); - return PathResult::NonModule(PathResolution::new(res)); + return PathResult::NonModule(PartialRes::new(res)); } else if res == Res::Err { - return PathResult::NonModule(err_path_resolution()); + return PathResult::NonModule(PartialRes::new(Res::Err)); } else if opt_ns.is_some() && (is_last || maybe_assoc) { self.lint_if_path_starts_with_module( crate_lint, @@ -3874,7 +3869,7 @@ impl<'a> Resolver<'a> { path_span, second_binding, ); - return PathResult::NonModule(PathResolution::with_unresolved_segments( + return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - i - 1 )); } else { @@ -3882,7 +3877,7 @@ impl<'a> Resolver<'a> { "`{}` is {} {}, not a module", ident, res.article(), - res.kind_name(), + res.descr(), ); return PathResult::Failed { @@ -3897,7 +3892,7 @@ impl<'a> Resolver<'a> { Err(Determined) => { if let Some(ModuleOrUniformRoot::Module(module)) = module { if opt_ns.is_some() && !module.is_normal() { - return PathResult::NonModule(PathResolution::with_unresolved_segments( + return PathResult::NonModule(PartialRes::with_unresolved_segments( module.res().unwrap(), path.len() - i )); } @@ -3928,7 +3923,7 @@ impl<'a> Resolver<'a> { (format!("maybe a missing `extern crate {};`?", ident), None) } else { // the parser will already have complained about the keyword being used - return PathResult::NonModule(err_path_resolution()); + return PathResult::NonModule(PartialRes::new(Res::Err)); } } else if i == 0 { (format!("use of undeclared type or module `{}`", ident), None) @@ -4059,21 +4054,21 @@ impl<'a> Resolver<'a> { ClosureRibKind(function_id) => { let prev_res = res; - let seen = self.freevars_seen + let seen = self.upvars_seen .entry(function_id) .or_default(); if let Some(&index) = seen.get(&node_id) { res = Res::Upvar(node_id, index, function_id); continue; } - let vec = self.freevars + let vec = self.upvars .entry(function_id) .or_default(); let depth = vec.len(); res = Res::Upvar(node_id, depth, function_id); if record_used { - vec.push(Freevar { + vec.push(Upvar { res: prev_res, span, }); @@ -4177,7 +4172,7 @@ impl<'a> Resolver<'a> { if filter_fn(Res::Local(ast::DUMMY_NODE_ID)) { if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) { // Look for a field with the same name in the current self_type. - if let Some(resolution) = self.res_map.get(&node_id) { + if let Some(resolution) = self.partial_res_map.get(&node_id) { match resolution.base_res() { Res::Def(DefKind::Struct, did) | Res::Def(DefKind::Union, did) if resolution.unresolved_segments() == 0 => { @@ -4234,7 +4229,7 @@ impl<'a> Resolver<'a> { names.push(TypoSuggestion { candidate: ident.name, article: binding.res().article(), - kind: binding.res().kind_name(), + kind: binding.res().descr(), }); } } @@ -4252,7 +4247,7 @@ impl<'a> Resolver<'a> { names.push(TypoSuggestion { candidate: ident.name, article: res.article(), - kind: res.kind_name(), + kind: res.descr(), }); } } @@ -4346,10 +4341,9 @@ impl<'a> Resolver<'a> { { if let Some(label) = label { self.unused_labels.insert(id, label.ident.span); - let res = Res::Label(id); self.with_label_rib(|this| { let ident = label.ident.modern_and_legacy(); - this.label_ribs.last_mut().unwrap().bindings.insert(ident, res); + this.label_ribs.last_mut().unwrap().bindings.insert(ident, id); f(this); }); } else { @@ -4380,10 +4374,10 @@ impl<'a> Resolver<'a> { } ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => { - let res = self.search_label(label.ident, |rib, ident| { + let node_id = self.search_label(label.ident, |rib, ident| { rib.bindings.get(&ident.modern_and_legacy()).cloned() }); - match res { + match node_id { None => { // Search again for close matches... // Picks the first label that is "close enough", which is not necessarily @@ -4398,19 +4392,16 @@ impl<'a> Resolver<'a> { }); find_best_match_for_name(names, &*ident.as_str(), None) }); - self.record_res(expr.id, err_path_resolution()); + self.record_partial_res(expr.id, PartialRes::new(Res::Err)); resolve_error(self, label.ident.span, ResolutionError::UndeclaredLabel(&label.ident.as_str(), close_match)); } - Some(Res::Label(id)) => { + Some(node_id) => { // Since this res is a label, it is never read. - self.record_res(expr.id, PathResolution::new(Res::Label(id))); - self.unused_labels.remove(&id); - } - Some(_) => { - span_bug!(expr.span, "label wasn't mapped to a label res!"); + self.label_res_map.insert(expr.id, node_id); + self.unused_labels.remove(&node_id); } } @@ -4582,7 +4573,7 @@ impl<'a> Resolver<'a> { module.span, ).is_ok() { let def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: def_id, import_id: None }); + found_traits.push(TraitCandidate { def_id: def_id, import_ids: smallvec![] }); } } @@ -4641,37 +4632,34 @@ impl<'a> Resolver<'a> { false, module.span, ).is_ok() { - let import_id = match binding.kind { - NameBindingKind::Import { directive, .. } => { - self.maybe_unused_trait_imports.insert(directive.id); - self.add_to_glob_map(&directive, trait_name); - Some(directive.id) - } - _ => None, - }; + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); let trait_def_id = module.def_id().unwrap(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_id }); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); } } else if let Res::Def(DefKind::TraitAlias, _) = binding.res() { // For now, just treat all trait aliases as possible candidates, since we don't // know if the ident is somewhere in the transitive bounds. - - let import_id = match binding.kind { - NameBindingKind::Import { directive, .. } => { - self.maybe_unused_trait_imports.insert(directive.id); - self.add_to_glob_map(&directive, trait_name); - Some(directive.id) - } - _ => None, - }; + let import_ids = self.find_transitive_imports(&binding.kind, trait_name); let trait_def_id = binding.res().def_id(); - found_traits.push(TraitCandidate { def_id: trait_def_id, import_id }); + found_traits.push(TraitCandidate { def_id: trait_def_id, import_ids }); } else { bug!("candidate is not trait or trait alias?") } } } + fn find_transitive_imports(&mut self, mut kind: &NameBindingKind<'_>, + trait_name: Ident) -> SmallVec<[NodeId; 1]> { + let mut import_ids = smallvec![]; + while let NameBindingKind::Import { directive, binding, .. } = kind { + self.maybe_unused_trait_imports.insert(directive.id); + self.add_to_glob_map(&directive, trait_name); + import_ids.push(directive.id); + kind = &binding.kind; + }; + import_ids + } + fn lookup_import_candidates_from_module(&mut self, lookup_ident: Ident, namespace: Namespace, @@ -4858,9 +4846,9 @@ impl<'a> Resolver<'a> { }) } - fn record_res(&mut self, node_id: NodeId, resolution: PathResolution) { + fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) { debug!("(recording res) recording {:?} for {}", resolution, node_id); - if let Some(prev_res) = self.res_map.insert(node_id, resolution) { + if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) { panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution); } } @@ -5483,10 +5471,6 @@ fn module_to_string(module: Module<'_>) -> Option { .collect::>())) } -fn err_path_resolution() -> PathResolution { - PathResolution::new(Res::Err) -} - #[derive(Copy, Clone, Debug)] enum CrateLint { /// Do not issue the lint. diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 18573a4594f4c..9f3e1c308f637 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -6,8 +6,7 @@ use crate::ModuleOrUniformRoot; use crate::Namespace::*; use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; use crate::resolve_imports::ImportResolver; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX, DefIndex, - CrateNum, DefIndexAddressSpace}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::map::{self, DefCollector}; use rustc::{ty, lint}; @@ -23,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}; @@ -173,8 +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(), - DefIndexAddressSpace::Low), + index: DefIndex::from_array_index(self.macro_map.len()), }; let kind = ext.kind(); self.macro_map.insert(def_id, ext); @@ -315,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 \ @@ -325,7 +324,7 @@ impl<'a> Resolver<'a> { path.span, &name, &msg, - "custom_attribute", + sym::custom_attribute, ); } } @@ -333,7 +332,7 @@ impl<'a> Resolver<'a> { // Not only attributes, but anything in macro namespace can result in // `Res::NonMacroAttr` definition (e.g., `inline!()`), so we must report // an error for those cases. - let msg = format!("expected a macro, found {}", res.kind_name()); + let msg = format!("expected a macro, found {}", res.descr()); self.session.span_err(path.span, &msg); return Err(Determinacy::Determined); } @@ -347,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, @@ -695,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); @@ -913,7 +912,7 @@ impl<'a> Resolver<'a> { // (which is a best effort error recovery tool, basically), so we can't // promise their resolution won't change later. let msg = format!("inconsistent resolution for a macro: first {}, then {}", - initial_res.kind_name(), res.kind_name()); + initial_res.descr(), res.descr()); this.session.span_err(span, &msg); } else { span_bug!(span, "inconsistent resolution for a macro"); @@ -983,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(); } } @@ -1011,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. @@ -1024,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| { @@ -1034,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) }); @@ -1093,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`"); } @@ -1108,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 { @@ -1126,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 522a49ee2c1ea..4058f0bce0f95 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -21,7 +21,7 @@ use rustc::lint::builtin::{ UNUSED_IMPORTS, }; use rustc::hir::def_id::{CrateNum, DefId}; -use rustc::hir::def::{self, DefKind, PathResolution, Export}; +use rustc::hir::def::{self, DefKind, PartialRes, Export}; use rustc::session::DiagnosticMessageId; use rustc::util::nodemap::FxHashSet; use rustc::{bug, span_bug}; @@ -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()); @@ -1233,8 +1235,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { res = Res::Err; } } - let import = this.import_map.entry(directive.id).or_default(); - import[ns] = Some(PathResolution::new(res)); + this.import_res_map.entry(directive.id).or_default()[ns] = Some(res); }); self.check_for_redundant_imports( @@ -1371,7 +1372,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } // Record the destination of this import - self.record_res(directive.id, PathResolution::new(module.res().unwrap())); + self.record_partial_res(directive.id, PartialRes::new(module.res().unwrap())); } // Miscellaneous post-processing, including recording re-exports, @@ -1393,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.name.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 a45e32ddb6690..1e65f868ebac0 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 c242b4d6a4123..e03da2ed608be 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -796,7 +796,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } Res::PrimTy(..) | Res::SelfTy(..) | - Res::Label(..) | Res::Def(HirDefKind::Macro(..), _) | Res::ToolMod | Res::NonMacroAttr(..) | @@ -880,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())); @@ -890,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()); @@ -1198,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_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs index 4f759b8a73fcc..fa12d9c49dfc3 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/src/librustc_save_analysis/sig.rs @@ -579,7 +579,7 @@ impl Sig for ast::Path { let res = scx.get_path_res(id.ok_or("Missing id for Path")?); let (name, start, end) = match res { - Res::Label(..) | Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => { + Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => { return Ok(Signature { text: pprust::path_to_string(self), defs: vec![], diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 59eda97a2f9f5..4b61057e5cf6c 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -910,6 +910,28 @@ pub trait LayoutOf { fn layout_of(&self, ty: Self::Ty) -> Self::TyLayout; } +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum PointerKind { + /// Most general case, we know no restrictions to tell LLVM. + Shared, + + /// `&T` where `T` contains no `UnsafeCell`, is `noalias` and `readonly`. + Frozen, + + /// `&mut T`, when we know `noalias` is safe for LLVM. + UniqueBorrowed, + + /// `Box`, unlike `UniqueBorrowed`, it also has `noalias` on returns. + UniqueOwned +} + +#[derive(Copy, Clone)] +pub struct PointeeInfo { + pub size: Size, + pub align: Align, + pub safe: Option, +} + pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { fn for_variant( this: TyLayout<'a, Self>, @@ -917,6 +939,11 @@ pub trait TyLayoutMethods<'a, C: LayoutOf>: Sized { variant_index: VariantIdx, ) -> TyLayout<'a, Self>; fn field(this: TyLayout<'a, Self>, cx: &C, i: usize) -> C::TyLayout; + fn pointee_info_at( + this: TyLayout<'a, Self>, + cx: &C, + offset: Size, + ) -> Option; } impl<'a, Ty> TyLayout<'a, Ty> { @@ -928,6 +955,10 @@ impl<'a, Ty> TyLayout<'a, Ty> { where Ty: TyLayoutMethods<'a, C>, C: LayoutOf { Ty::field(self, cx, i) } + pub fn pointee_info_at(self, cx: &C, offset: Size) -> Option + where Ty: TyLayoutMethods<'a, C>, C: LayoutOf { + Ty::pointee_info_at(self, cx, offset) + } } impl<'a, Ty> TyLayout<'a, Ty> { diff --git a/src/librustc_target/spec/apple_base.rs b/src/librustc_target/spec/apple_base.rs index c21f7f38ca5a3..9dd343b6c8de8 100644 --- a/src/librustc_target/spec/apple_base.rs +++ b/src/librustc_target/spec/apple_base.rs @@ -14,13 +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 deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok(); - let version = deployment_target.as_ref().and_then(|s| { - let mut i = s.splitn(2, '.'); - i.next().and_then(|a| i.next().map(|b| (a, b))) - }).and_then(|(a, b)| { - a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok() - }).unwrap_or((10, 7)); + let version = macos_deployment_target().unwrap_or((10, 7)); TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections @@ -40,3 +34,27 @@ pub fn opts() -> TargetOptions { .. Default::default() } } + +fn macos_deployment_target() -> Option<(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, '.'); + i.next().and_then(|a| i.next().map(|b| (a, b))) + }).and_then(|(a, b)| { + a.parse::().and_then(|a| b.parse::().map(|b| (a, b))).ok() + }); + + version +} + +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 +} diff --git a/src/librustc_target/spec/i686_apple_darwin.rs b/src/librustc_target/spec/i686_apple_darwin.rs index 58c59cc872846..7d804ea53fb31 100644 --- a/src/librustc_target/spec/i686_apple_darwin.rs +++ b/src/librustc_target/spec/i686_apple_darwin.rs @@ -8,8 +8,14 @@ pub fn target() -> TargetResult { base.stack_probes = true; base.eliminate_frame_pointer = false; + // Clang automatically chooses a more specific target based on + // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work + // correctly, we do too. + let arch = "i686"; + let llvm_target = super::apple_base::macos_llvm_target(&arch); + Ok(Target { - llvm_target: "i686-apple-darwin".to_string(), + llvm_target: llvm_target, target_endian: "little".to_string(), target_pointer_width: "32".to_string(), target_c_int_width: "32".to_string(), diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 46fefd78f4519..b30a4fe76a2da 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -444,7 +444,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 0412635bfe2db..bb33493a77333 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_apple_darwin.rs b/src/librustc_target/spec/x86_64_apple_darwin.rs index c54181741b3cc..182103440f035 100644 --- a/src/librustc_target/spec/x86_64_apple_darwin.rs +++ b/src/librustc_target/spec/x86_64_apple_darwin.rs @@ -8,13 +8,19 @@ pub fn target() -> TargetResult { base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]); base.stack_probes = true; + // Clang automatically chooses a more specific target based on + // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work + // correctly, we do too. + let arch = "x86_64"; + let llvm_target = super::apple_base::macos_llvm_target(&arch); + Ok(Target { - llvm_target: "x86_64-apple-darwin".to_string(), + llvm_target: llvm_target, target_endian: "little".to_string(), target_pointer_width: "64".to_string(), target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(), - arch: "x86_64".to_string(), + arch: arch.to_string(), target_os: "macos".to_string(), target_env: String::new(), target_vendor: "apple".to_string(), diff --git a/src/librustc_traits/lowering/mod.rs b/src/librustc_traits/lowering/mod.rs index c3cbdb0376251..580b1571e52bb 100644 --- a/src/librustc_traits/lowering/mod.rs +++ b/src/librustc_traits/lowering/mod.rs @@ -1,5 +1,6 @@ mod environment; +use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc::hir::map::definitions::DefPathData; @@ -20,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; @@ -157,13 +159,27 @@ crate fn program_clauses_for<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, ) -> Clauses<'tcx> { + // FIXME(eddyb) this should only be using `def_kind`. match tcx.def_key(def_id).disambiguated_data.data { - DefPathData::Trait(_) | - DefPathData::TraitAlias(_) => program_clauses_for_trait(tcx, def_id), + DefPathData::TypeNs(..) => match tcx.def_kind(def_id) { + Some(DefKind::Trait) + | Some(DefKind::TraitAlias) => program_clauses_for_trait(tcx, def_id), + // FIXME(eddyb) deduplicate this `associated_item` call with + // `program_clauses_for_associated_type_{value,def}`. + Some(DefKind::AssociatedTy) => match tcx.associated_item(def_id).container { + ty::AssociatedItemContainer::ImplContainer(_) => + program_clauses_for_associated_type_value(tcx, def_id), + ty::AssociatedItemContainer::TraitContainer(_) => + program_clauses_for_associated_type_def(tcx, def_id) + }, + Some(DefKind::Struct) + | Some(DefKind::Enum) + | Some(DefKind::TyAlias) + | Some(DefKind::Union) + | Some(DefKind::Existential) => program_clauses_for_type_def(tcx, def_id), + _ => List::empty(), + }, DefPathData::Impl => program_clauses_for_impl(tcx, def_id), - DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id), - DefPathData::AssocTypeInTrait(..) => program_clauses_for_associated_type_def(tcx, def_id), - DefPathData::TypeNs(..) => program_clauses_for_type_def(tcx, def_id), _ => List::empty(), } } @@ -625,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 4932d77ef0477..caefe12421155 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; @@ -553,7 +554,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.intern_substs(&substs) } - /// Given the type/region arguments provided to some path (along with + /// Given the type/lifetime/const arguments provided to some path (along with /// an implicit `Self`, if this is a trait reference) returns the complete /// set of substitutions. This may involve applying defaulted type parameters. /// @@ -678,7 +679,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { GenericParamDefKind::Const => { // FIXME(const_generics:defaults) // We've already errored above about the mismatch. - tcx.types.err.into() + tcx.consts.err.into() } } }, @@ -802,7 +803,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 +1903,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 62afbc44d07b6..a69f639e8941f 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,73 +600,26 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); ) -> Ty<'tcx> { let tcx = self.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). - // - // arielb1 [writes here in this comment thread][c] that there - // is certainly *some* potential danger, e.g., for an example - // like: - // - // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956 - // - // ``` - // let Foo(x) = f()[0]; - // ``` - // - // Then if the pattern matches by reference, we want to match - // `f()[0]` as a lexpr, so we can't allow it to be - // coerced. But if the pattern matches by value, `f()[0]` is - // still syntactically a lexpr, but we *do* want to allow - // coercions. - // - // However, *likely* we are ok with allowing coercions to - // happen if there are no explicit ref mut patterns - all - // implicit ref mut patterns must occur behind a reference, so - // they will have the "correct" variance and lifetime. - // - // This does mean that the following pattern would be legal: - // - // ``` - // struct Foo(Bar); - // struct Bar(u32); - // impl Deref for Foo { - // type Target = Bar; - // fn deref(&self) -> &Bar { &self.0 } - // } - // impl DerefMut for Foo { - // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 } - // } - // fn foo(x: &mut Foo) { - // { - // let Bar(z): &mut Bar = x; - // *z = 42; - // } - // assert_eq!(foo.0.0, 42); - // } - // ``` - // - // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which - // is problematic as the HIR is being scraped, but ref bindings may be - // implicit after #42640. We need to make sure that pat_adjustments - // (once introduced) is populated by the time we get here. - // - // See #44848. - let contains_ref_bindings = arms.iter() - .filter_map(|a| a.contains_explicit_ref_binding()) - .max_by_key(|m| match *m { - 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)); + 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 { - // ...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)); - self.check_expr_has_type_or_error(discrim, discrim_ty); + self.demand_discriminant_type(arms, discrim) }; // If there are no arms, that is a diverging match; a special case. @@ -670,11 +628,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); return tcx.types.never; } - if self.diverges.get().always() { - for arm in arms { - self.warn_if_unreachable(arm.body.hir_id, arm.body.span, "arm"); - } - } + self.warn_arms_when_scrutinee_diverges(arms, source_if); // Otherwise, we have to union together the types that the // arms produce and so forth. @@ -687,12 +641,8 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); 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), - ); + 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(); } @@ -734,7 +684,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); 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 { + 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), @@ -745,43 +695,44 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); 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() + 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); + } } - _ => 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 { + 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. - self.cause(arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)) - } else { - self.cause(expr.span, ObligationCauseCode::MatchExpressionArm { + 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); + other_arms.push(arm_span); + if other_arms.len() > 5 { + other_arms.remove(0); + } } prior_arm_ty = Some(arm_ty); } @@ -792,6 +743,251 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); 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). + // + // arielb1 [writes here in this comment thread][c] that there + // is certainly *some* potential danger, e.g., for an example + // like: + // + // [c]: https://github.com/rust-lang/rust/pull/43399#discussion_r130223956 + // + // ``` + // let Foo(x) = f()[0]; + // ``` + // + // Then if the pattern matches by reference, we want to match + // `f()[0]` as a lexpr, so we can't allow it to be + // coerced. But if the pattern matches by value, `f()[0]` is + // still syntactically a lexpr, but we *do* want to allow + // coercions. + // + // However, *likely* we are ok with allowing coercions to + // happen if there are no explicit ref mut patterns - all + // implicit ref mut patterns must occur behind a reference, so + // they will have the "correct" variance and lifetime. + // + // This does mean that the following pattern would be legal: + // + // ``` + // struct Foo(Bar); + // struct Bar(u32); + // impl Deref for Foo { + // type Target = Bar; + // fn deref(&self) -> &Bar { &self.0 } + // } + // impl DerefMut for Foo { + // fn deref_mut(&mut self) -> &mut Bar { &mut self.0 } + // } + // fn foo(x: &mut Foo) { + // { + // let Bar(z): &mut Bar = x; + // *z = 42; + // } + // assert_eq!(foo.0.0, 42); + // } + // ``` + // + // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which + // is problematic as the HIR is being scraped, but ref bindings may be + // implicit after #42640. We need to make sure that pat_adjustments + // (once introduced) is populated by the time we get here. + // + // See #44848. + let contains_ref_bindings = arms.iter() + .filter_map(|a| a.contains_explicit_ref_binding()) + .max_by_key(|m| match *m { + hir::MutMutable => 1, + hir::MutImmutable => 0, + }); + + if let Some(m) = contains_ref_bindings { + 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. + let discrim_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(discrim.span)); + self.check_expr_has_type_or_error(discrim, discrim_ty); + discrim_ty + } + } + fn check_pat_struct( &self, pat: &'gcx hir::Pat, @@ -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) @@ -884,7 +1075,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); }; let report_unexpected_res = |res: Res| { let msg = format!("expected tuple struct/variant, found {} `{}`", - res.kind_name(), + res.descr(), hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg) .span_label(pat.span, "not a tuple variant or struct").emit(); @@ -947,7 +1138,7 @@ https://doc.rust-lang.org/reference/types.html#trait-objects"); let fields_ending = if variant.fields.len() == 1 { "" } else { "s" }; struct_span_err!(tcx.sess, pat.span, E0023, "this pattern has {} field{}, but the corresponding {} has {} field{}", - subpats.len(), subpats_ending, res.kind_name(), + subpats.len(), subpats_ending, res.descr(), variant.fields.len(), fields_ending) .span_label(pat.span, format!("expected {} field{}, found {}", variant.fields.len(), fields_ending, subpats.len())) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 838874cc2bf07..3fa192f16f32e 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } /// Given a projection like "::Result == Y", we can deduce - /// everything we need to know about a closure. + /// everything we need to know about a closure or generator. /// /// The `cause_span` should be the span that caused us to /// have this expected signature, or `None` if we can't readily @@ -262,37 +262,50 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let trait_ref = projection.to_poly_trait_ref(tcx); - if tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_none() { + let is_fn = tcx.lang_items().fn_trait_kind(trait_ref.def_id()).is_some(); + let gen_trait = tcx.lang_items().gen_trait().unwrap(); + let is_gen = gen_trait == trait_ref.def_id(); + if !is_fn && !is_gen { + debug!("deduce_sig_from_projection: not fn or generator"); return None; } - let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); - let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); - debug!( - "deduce_sig_from_projection: arg_param_ty {:?}", - arg_param_ty - ); + if is_gen { + // Check that we deduce the signature from the `<_ as std::ops::Generator>::Return` + // associated item and not yield. + let return_assoc_item = self.tcx.associated_items(gen_trait).nth(1).unwrap().def_id; + if return_assoc_item != projection.projection_def_id() { + debug!("deduce_sig_from_projection: not return assoc item of generator"); + return None; + } + } + + let input_tys = if is_fn { + let arg_param_ty = trait_ref.skip_binder().substs.type_at(1); + let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty); + debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); - let input_tys = match arg_param_ty.sty { - ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()), - _ => return None, + match arg_param_ty.sty { + ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::>(), + _ => return None, + } + } else { + // Generators cannot have explicit arguments. + vec![] }; let ret_param_ty = projection.skip_binder().ty; let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty); - debug!( - "deduce_sig_from_projection: ret_param_ty {:?}", - ret_param_ty - ); + debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty); let sig = self.tcx.mk_fn_sig( - input_tys, - ret_param_ty, + input_tys.iter(), + &ret_param_ty, false, hir::Unsafety::Normal, Abi::Rust, ); - debug!("deduce_sig_from_projection: sig {:?}", sig); + debug!("deduce_sig_from_projection: sig={:?}", sig); Some(ExpectedSig { cause_span, sig }) } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 85eb0f9d49966..90b2643d165be 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); @@ -721,9 +722,8 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let b = self.shallow_resolve(b); - let hir_id_a = self.tcx.hir().as_local_hir_id(def_id_a).unwrap(); match b.sty { - ty::FnPtr(fn_ty) if self.tcx.with_freevars(hir_id_a, |v| v.is_empty()) => { + ty::FnPtr(fn_ty) if self.tcx.upvars(def_id_a).map_or(true, |v| v.is_empty()) => { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` // to @@ -1249,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 1699447886aef..8d68179b495c6 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/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index bbdc7df4441e8..a4b1687ea5301 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -195,8 +195,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ProbeScope::TraitsInScope )?; - if let Some(import_id) = pick.import_id { - let import_def_id = self.tcx.hir().local_def_id_from_hir_id(import_id); + for import_id in &pick.import_ids { + let import_def_id = self.tcx.hir().local_def_id_from_hir_id(*import_id); debug!("used_trait_import: {:?}", import_def_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) .unwrap().insert(import_def_id); @@ -434,7 +434,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let pick = self.probe_for_name(span, probe::Mode::Path, method_name, IsSuggestion(false), self_ty, expr_id, ProbeScope::TraitsInScope)?; debug!("resolve_ufcs: pick={:?}", pick); - if let Some(import_id) = pick.import_id { + for import_id in pick.import_ids { let import_def_id = tcx.hir().local_def_id_from_hir_id(import_id); debug!("resolve_ufcs: used_trait_import: {:?}", import_def_id); Lrc::get_mut(&mut self.tables.borrow_mut().used_trait_imports) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 8c61a127d1014..251400e65f383 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -35,6 +35,8 @@ use std::mem; use std::ops::Deref; use std::cmp::max; +use smallvec::{smallvec, SmallVec}; + use self::CandidateKind::*; pub use self::PickKind::*; @@ -121,7 +123,7 @@ struct Candidate<'tcx> { xform_ret_ty: Option>, item: ty::AssociatedItem, kind: CandidateKind<'tcx>, - import_id: Option, + import_ids: SmallVec<[hir::HirId; 1]>, } #[derive(Debug)] @@ -146,7 +148,7 @@ enum ProbeResult { pub struct Pick<'tcx> { pub item: ty::AssociatedItem, pub kind: PickKind<'tcx>, - pub import_id: Option, + pub import_ids: SmallVec<[hir::HirId; 1]>, // Indicates that the source expression should be autoderef'd N times // @@ -716,7 +718,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.push_candidate(Candidate { xform_self_ty, xform_ret_ty, item, kind: InherentImplCandidate(impl_substs, obligations), - import_id: None + import_ids: smallvec![] }, true); } } @@ -750,13 +752,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { this.push_candidate(Candidate { xform_self_ty, xform_ret_ty, item, kind: ObjectCandidate, - import_id: None + import_ids: smallvec![] }, true); }); } - fn assemble_inherent_candidates_from_param(&mut self, - param_ty: ty::ParamTy) { + fn assemble_inherent_candidates_from_param(&mut self, param_ty: ty::ParamTy) { // FIXME -- Do we want to commit to this behavior for param bounds? let bounds = self.param_env @@ -799,7 +800,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { this.push_candidate(Candidate { xform_self_ty, xform_ret_ty, item, kind: WhereClauseCandidate(poly_trait_ref), - import_id: None + import_ids: smallvec![] }, true); }); } @@ -838,9 +839,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { for trait_candidate in applicable_traits.iter() { let trait_did = trait_candidate.def_id; if duplicates.insert(trait_did) { - let import_id = trait_candidate.import_id.map(|node_id| - self.fcx.tcx.hir().node_to_hir_id(node_id)); - let result = self.assemble_extension_candidates_for_trait(import_id, trait_did); + let import_ids = trait_candidate.import_ids.iter().map(|node_id| + self.fcx.tcx.hir().node_to_hir_id(*node_id)).collect(); + let result = self.assemble_extension_candidates_for_trait(import_ids, + trait_did); result?; } } @@ -852,7 +854,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let mut duplicates = FxHashSet::default(); for trait_info in suggest::all_traits(self.tcx) { if duplicates.insert(trait_info.def_id) { - self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?; + self.assemble_extension_candidates_for_trait(smallvec![], trait_info.def_id)?; } } Ok(()) @@ -890,7 +892,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } fn assemble_extension_candidates_for_trait(&mut self, - import_id: Option, + import_ids: SmallVec<[hir::HirId; 1]>, trait_def_id: DefId) -> Result<(), MethodError<'tcx>> { debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", @@ -907,7 +909,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(&item, new_trait_ref.self_ty(), new_trait_ref.substs); this.push_candidate(Candidate { - xform_self_ty, xform_ret_ty, item, import_id, + xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(), kind: TraitCandidate(new_trait_ref), }, true); }); @@ -924,7 +926,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(&item, trait_ref.self_ty(), trait_substs); self.push_candidate(Candidate { - xform_self_ty, xform_ret_ty, item, import_id, + xform_self_ty, xform_ret_ty, item, import_ids: import_ids.clone(), kind: TraitCandidate(trait_ref), }, false); } @@ -1413,7 +1415,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Some(Pick { item: probes[0].0.item.clone(), kind: TraitPick, - import_id: probes[0].0.import_id, + import_ids: probes[0].0.import_ids.clone(), autoderefs: 0, autoref: None, unsize: None, @@ -1652,7 +1654,7 @@ impl<'tcx> Candidate<'tcx> { WhereClausePick(trait_ref.clone()) } }, - import_id: self.import_id, + import_ids: self.import_ids.clone(), autoderefs: 0, autoref: None, unsize: None, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b57ae361eb69e..77d2ffab8efb4 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 4ae75511322b6..362b6f0504d99 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"); @@ -1902,7 +1899,7 @@ fn report_unexpected_variant_res<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, qpath: &QPath) { span_err!(tcx.sess, span, E0533, "expected unit struct/variant or constant, found {} `{}`", - res.kind_name(), + res.descr(), hir::print::to_string(tcx.hir(), |s| s.print_qpath(qpath, false))); } @@ -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") } @@ -4168,9 +3978,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { oprnd_t = self.make_overloaded_place_return_type(method).ty; self.write_method_call(expr.hir_id, method); } else { - type_error_struct!(tcx.sess, expr.span, oprnd_t, E0614, - "type `{}` cannot be dereferenced", - oprnd_t).emit(); + let mut err = type_error_struct!( + tcx.sess, + expr.span, + oprnd_t, + E0614, + "type `{}` cannot be dereferenced", + oprnd_t, + ); + let sp = tcx.sess.source_map().start_point(expr.span); + if let Some(sp) = tcx.sess.parse_sess.ambiguous_block_expr_parse + .borrow().get(&sp) + { + tcx.sess.parse_sess.expr_parentheses_needed( + &mut err, + *sp, + None, + ); + } + err.emit(); oprnd_t = tcx.types.err; } } @@ -4371,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); } } @@ -4428,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 @@ -5245,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(..) | @@ -5653,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, + )); } } } @@ -5677,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 } @@ -5785,8 +5608,6 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty ); - // FIXME(const_generics): we probably want to check the bounds for const parameters too. - if own_counts.types == 0 { return; } @@ -5795,9 +5616,9 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut types_used = vec![false; own_counts.types]; for leaf_ty in ty.walk() { - if let ty::Param(ty::ParamTy { idx, .. }) = leaf_ty.sty { - debug!("Found use of ty param num {}", idx); - types_used[idx as usize - own_counts.lifetimes] = true; + if let ty::Param(ty::ParamTy { index, .. }) = leaf_ty.sty { + debug!("Found use of ty param num {}", index); + types_used[index as usize - own_counts.lifetimes] = true; } else if let ty::Error = leaf_ty.sty { // If there is already another error, do not emit // an error for not using a type Parameter. diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index dc66c6c93d0e0..c3861f964e453 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -121,28 +121,28 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None }; - self.tcx.with_freevars(closure_hir_id, |freevars| { - let mut freevar_list: Vec = Vec::with_capacity(freevars.len()); - for freevar in freevars { + if let Some(upvars) = self.tcx.upvars(closure_def_id) { + let mut upvar_list: Vec = Vec::with_capacity(upvars.len()); + for upvar in upvars.iter() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { - hir_id: freevar.var_id(), + hir_id: upvar.var_id(), }, closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; debug!("seed upvar_id {:?}", upvar_id); // Adding the upvar Id to the list of Upvars, which will be added // to the map for the closure at the end of the for loop. - freevar_list.push(upvar_id); + upvar_list.push(upvar_id); let capture_kind = match capture_clause { hir::CaptureByValue => ty::UpvarCapture::ByValue, hir::CaptureByRef => { let origin = UpvarRegion(upvar_id, span); - let freevar_region = self.next_region_var(origin); + let upvar_region = self.next_region_var(origin); let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, - region: freevar_region, + region: upvar_region, }; ty::UpvarCapture::ByRef(upvar_borrow) } @@ -153,16 +153,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .upvar_capture_map .insert(upvar_id, capture_kind); } - // Add the vector of freevars to the map keyed with the closure id. + // Add the vector of upvars to the map keyed with the closure id. // This gives us an easier access to them without having to call - // with_freevars again.. - if !freevar_list.is_empty() { + // tcx.upvars again.. + if !upvar_list.is_empty() { self.tables .borrow_mut() .upvar_list - .insert(closure_def_id, freevar_list); + .insert(closure_def_id, upvar_list); } - }); + } let body_owner_def_id = self.tcx.hir().body_owner_def_id(body.id()); let region_scope_tree = &self.tcx.region_scope_tree(body_owner_def_id); @@ -244,38 +244,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // This may change if abstract return types of some sort are // implemented. let tcx = self.tcx; - let closure_def_index = tcx.hir().local_def_id_from_hir_id(closure_id); + let closure_def_id = tcx.hir().local_def_id_from_hir_id(closure_id); - tcx.with_freevars(closure_id, |freevars| { - freevars + tcx.upvars(closure_def_id).iter().flat_map(|upvars| { + upvars .iter() - .map(|freevar| { - let var_hir_id = freevar.var_id(); - let freevar_ty = self.node_ty(var_hir_id); + .map(|upvar| { + let var_hir_id = upvar.var_id(); + let upvar_ty = self.node_ty(var_hir_id); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: LocalDefId::from_def_id(closure_def_index), + closure_expr_id: LocalDefId::from_def_id(closure_def_id), }; let capture = self.tables.borrow().upvar_capture(upvar_id); debug!( - "var_id={:?} freevar_ty={:?} capture={:?}", - var_hir_id, freevar_ty, capture + "var_id={:?} upvar_ty={:?} capture={:?}", + var_hir_id, upvar_ty, capture ); match capture { - ty::UpvarCapture::ByValue => freevar_ty, + ty::UpvarCapture::ByValue => upvar_ty, ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( borrow.region, ty::TypeAndMut { - ty: freevar_ty, + ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy(), }, ), } }) - .collect() }) + .collect() } } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 8ee30c0d2d31d..b009c8ea6dce1 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; @@ -421,8 +422,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( return_ty: Option>, ) { let predicates = fcx.tcx.predicates_of(def_id); - let generics = tcx.generics_of(def_id); + let is_our_default = |def: &ty::GenericParamDef| { match def.kind { GenericParamDefKind::Type { has_default, .. } => { @@ -465,6 +466,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // All regions are identity. fcx.tcx.mk_param_from_def(param) } + GenericParamDefKind::Type { .. } => { // If the param has a default, if is_our_default(param) { @@ -478,25 +480,24 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // Mark unwanted params as err. fcx.tcx.types.err.into() } + GenericParamDefKind::Const => { // FIXME(const_generics:defaults) - fcx.tcx.types.err.into() + fcx.tcx.consts.err.into() } } }); + // Now we build the substituted predicates. let default_obligations = predicates.predicates.iter().flat_map(|&(pred, _)| { #[derive(Default)] struct CountParams { params: FxHashSet } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.sty { - ty::Param(p) => { - self.params.insert(p.idx); - t.super_visit_with(self) - } - _ => t.super_visit_with(self) + if let ty::Param(param) = t.sty { + self.params.insert(param.index); } + t.super_visit_with(self) } fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool { @@ -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 f9d83146e30c3..ecb8e09ec2461 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 { @@ -611,26 +612,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(), - }; - - 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, - ); + 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, + ); + } } + } else { + self.tcx().sess.delay_span_bug( + span, + "cannot lift `opaque_defn` substs to global type context", + ); } } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ed8ac89912c12..6527e8655b5ef 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::{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) @@ -1093,8 +1093,8 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty }), ); - tcx.with_freevars(hir_id, |fv| { - params.extend(fv.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| { + if let Some(upvars) = tcx.upvars(def_id) { + params.extend(upvars.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| { ty::GenericParamDef { index: type_start + i, name: Symbol::intern("").as_interned_str(), @@ -1107,7 +1107,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty }, } })); - }); + } } let param_def_id_to_index = params @@ -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/constrained_generic_params.rs b/src/librustc_typeck/constrained_generic_params.rs index 18bf66ceb3501..49910e39fed20 100644 --- a/src/librustc_typeck/constrained_generic_params.rs +++ b/src/librustc_typeck/constrained_generic_params.rs @@ -8,7 +8,7 @@ use syntax::source_map::Span; pub struct Parameter(pub u32); impl From for Parameter { - fn from(param: ty::ParamTy) -> Self { Parameter(param.idx) } + fn from(param: ty::ParamTy) -> Self { Parameter(param.index) } } impl From for Parameter { diff --git a/src/librustc_typeck/outlives/mod.rs b/src/librustc_typeck/outlives/mod.rs index e3e2fe7106a08..a6b5b99982ec6 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 e10c836120718..54fd4fad1d195 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/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 5079a3bb55f89..4f82978f01a5d 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -324,7 +324,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::Param(ref data) => { - self.add_constraint(current, data.idx, variance); + self.add_constraint(current, data.index, variance); } ty::FnPtr(sig) => { diff --git a/src/librustc_typeck/variance/test.rs b/src/librustc_typeck/variance/test.rs index d04b1b276a2cc..b5195826b8631 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 69445451503cc..c795b2dcd7a43 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, } } @@ -414,10 +414,11 @@ impl<'a> fmt::Display for Html<'a> { mod test { use super::Cfg; - use syntax::symbol::Symbol; + use syntax_pos::DUMMY_SP; use syntax::ast::*; + use syntax::attr; use syntax::source_map::dummy_spanned; - use syntax_pos::DUMMY_SP; + use syntax::symbol::Symbol; use syntax::with_globals; fn word_cfg(s: &str) -> Cfg { @@ -592,14 +593,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 +624,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 d9d6b8e07e994..15108a7dbb91c 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 de74a6a540055..f9a43ccfbace1 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,8 +926,8 @@ 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)); @@ -938,7 +939,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 +1040,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) } } @@ -1706,9 +1707,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, } Some(param.clean(cx)) } - ty::GenericParamDefKind::Const { .. } => { - unimplemented!() // FIXME(const_generics) - } + ty::GenericParamDefKind::Const { .. } => None, }).collect::>(); let mut where_predicates = preds.predicates.iter() @@ -2135,7 +2134,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, @@ -3895,8 +3894,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, } }); @@ -3937,15 +3936,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 { @@ -4384,7 +4383,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(); @@ -4409,7 +4408,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/core.rs b/src/librustdoc/core.rs index 5555ea302c96f..428f4f328b907 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,6 +1,6 @@ use rustc_lint; use rustc::session::{self, config}; -use rustc::hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CrateNum, LOCAL_CRATE}; +use rustc::hir::def_id::{DefId, DefIndex, CrateNum, LOCAL_CRATE}; use rustc::hir::HirId; use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::AccessLevels; @@ -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; @@ -112,8 +113,8 @@ impl<'tcx> DocContext<'tcx> { // registered after the AST is constructed would require storing the defid mapping in a // RefCell, decreasing the performance for normal compilation for very little gain. // - // Instead, we construct 'fake' def ids, which start immediately after the last DefId in - // DefIndexAddressSpace::Low. In the Debug impl for clean::Item, we explicitly check for fake + // Instead, we construct 'fake' def ids, which start immediately after the last DefId. + // In the Debug impl for clean::Item, we explicitly check for fake // def ids, as we'll end up with a panic if we use the DefId Debug impl for fake DefIds pub fn next_def_id(&self, crate_num: CrateNum) -> DefId { let start_def_id = { @@ -122,11 +123,11 @@ impl<'tcx> DocContext<'tcx> { .hir() .definitions() .def_path_table() - .next_id(DefIndexAddressSpace::Low) + .next_id() } else { self.cstore .def_path_table(crate_num) - .next_id(DefIndexAddressSpace::Low) + .next_id() }; DefId { @@ -142,10 +143,7 @@ impl<'tcx> DocContext<'tcx> { crate_num, DefId { krate: crate_num, - index: DefIndex::from_array_index( - def_id.index.as_array_index() + 1, - def_id.index.address_space(), - ), + index: DefIndex::from_array_index(def_id.index.as_array_index() + 1), }, ); @@ -370,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(); @@ -418,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"); @@ -448,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/html/highlight.rs b/src/librustdoc/html/highlight.rs index d66455f91ba1a..5bb06516ac49e 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/render.rs b/src/librustdoc/html/render.rs index f4af362a55702..0207fcda9e880 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -50,6 +50,7 @@ use syntax::ast; 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; @@ -571,24 +572,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; } _ => {} @@ -1388,8 +1389,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 +1780,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()) @@ -3410,7 +3411,7 @@ fn render_stability_since_raw<'a, T: fmt::Write>( ) -> fmt::Result { if let Some(v) = ver { if containing_ver != ver && v.len() > 0 { - write!(w, "
{0}
", v)? + write!(w, "{0}", v)? } } Ok(()) @@ -3761,22 +3762,22 @@ 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 { 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()) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 358549117a307..880b824335517 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -914,7 +914,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { height: 12px; } -span.since { +.out-of-band > span.since { position: initial; font-size: 20px; margin-right: 5px; @@ -1052,6 +1052,10 @@ span.since { height: 45px; } + .rustdoc.source > .sidebar > .sidebar-menu { + display: none; + } + .sidebar-elems { position: fixed; z-index: 1; diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index fe407fa24d93e..4ee09f7096b61 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 705b222efe805..9e108e605c8bb 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(()) }; @@ -513,18 +513,18 @@ fn ambiguity_error( msg += &format!( "both {} {} and {} {}", first_def.article(), - first_def.kind_name(), + first_def.descr(), second_def.article(), - second_def.kind_name(), + second_def.descr(), ); } _ => { let mut candidates = candidates.iter().peekable(); while let Some((res, _)) = candidates.next() { if candidates.peek().is_some() { - msg += &format!("{} {}, ", res.article(), res.kind_name()); + msg += &format!("{} {}, ", res.article(), res.descr()); } else { - msg += &format!("and {} {}", res.article(), res.kind_name()); + msg += &format!("and {} {}", res.article(), res.descr()); } } } @@ -575,7 +575,7 @@ fn ambiguity_error( diag.span_suggestion( sp, - &format!("to link to the {}, {}", res.kind_name(), action), + &format!("to link to the {}, {}", res.descr(), action), suggestion, Applicability::MaybeIncorrect, ); diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 8d33cd72e29aa..70cd4b72199bc 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/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 240299c212abc..da8977544f64b 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 5c0a4da1cd7ef..e40dbe52ffe64 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)); diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 94d2d7ffdb8c2..eb9de43e38861 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 326c9a10f7df8..2547e3a06e9ef 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/libserialize/serialize.rs b/src/libserialize/serialize.rs index 8ef8c2b4c0a22..36a1628014ddb 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -764,12 +764,18 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -impl Encodable for path::PathBuf { +impl Encodable for path::Path { fn encode(&self, e: &mut S) -> Result<(), S::Error> { self.to_str().unwrap().encode(e) } } +impl Encodable for path::PathBuf { + fn encode(&self, e: &mut S) -> Result<(), S::Error> { + path::Path::encode(self, e) + } +} + impl Decodable for path::PathBuf { fn decode(d: &mut D) -> Result { let bytes: String = Decodable::decode(d)?; diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index ac1aff845d8c9..ad5d62f667ac9 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -19,7 +19,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true } panic_abort = { path = "../libpanic_abort" } core = { path = "../libcore" } libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.9" } +compiler_builtins = { version = "0.1.12" } profiler_builtins = { path = "../libprofiler_builtins", optional = true } unwind = { path = "../libunwind" } hashbrown = { version = "0.3.0", features = ['rustc-dep-of-std'] } diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index 64f8659b8f8fe..a94176e710005 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -72,7 +72,7 @@ use core::convert::TryInto; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct Cursor { inner: T, pos: u64, @@ -265,6 +265,7 @@ impl BufRead for Cursor where T: AsRef<[u8]> { } // Non-resizing write implementation +#[inline] fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result { let pos = cmp::min(*pos_mut, slice.len() as u64); let amt = (&mut slice[(pos as usize)..]).write(buf)?; @@ -272,6 +273,7 @@ fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result { slice_write_vectored(&mut self.pos, self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -354,6 +357,7 @@ impl Write for Cursor<&mut Vec> { vec_write_vectored(&mut self.pos, self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -367,6 +371,7 @@ impl Write for Cursor> { vec_write_vectored(&mut self.pos, &mut self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -382,6 +387,7 @@ impl Write for Cursor> { slice_write_vectored(&mut self.pos, &mut self.inner, bufs) } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 215f1bbc971af..2401946536ffa 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 @@ -259,7 +260,6 @@ #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] #![feature(external_doc)] -#![feature(fixed_size_array)] #![feature(fn_traits)] #![feature(fnbox)] #![feature(generator_trait)] @@ -435,6 +435,8 @@ pub use core::char; pub use core::u128; #[stable(feature = "core_hint", since = "1.27.0")] pub use core::hint; +#[stable(feature = "core_array", since = "1.36.0")] +pub use core::array; pub mod f32; pub mod f64; diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 9eba76cc04a64..03aebeda47c48 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -357,29 +357,6 @@ macro_rules! dbg { }; } -/// Awaits the completion of an async call. -#[macro_export] -#[unstable(feature = "await_macro", issue = "50547")] -#[allow_internal_unstable(gen_future, generators)] -#[allow_internal_unsafe] -macro_rules! r#await { - ($e:expr) => { { - let mut pinned = $e; - loop { - if let $crate::task::Poll::Ready(x) = - $crate::future::poll_with_tls_context(unsafe { - $crate::pin::Pin::new_unchecked(&mut pinned) - }) - { - break x; - } - // FIXME(cramertj) prior to stabilizing await, we have to ensure that this - // can't be used to create a generator on stable via `|| await!()`. - yield - } - } } -} - /// 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 diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 94fece10e0fbc..24f728158c472 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -279,7 +279,7 @@ mod prim_never { } /// /// As always, remember that a human intuition for 'character' may not map to /// Unicode's definitions. For example, despite looking similar, the 'é' -/// character is one Unicode code point while 'é' is two Unicode code points: +/// character is one Unicode code point while 'é' is two Unicode code points: /// /// ``` /// let mut chars = "é".chars(); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 33b8c76bb531a..d12240655e628 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}; @@ -80,12 +81,6 @@ impl PartialEq for Path { } } -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)) @@ -1065,6 +1060,7 @@ impl Expr { ExprKind::Block(..) => ExprPrecedence::Block, ExprKind::TryBlock(..) => ExprPrecedence::TryBlock, ExprKind::Async(..) => ExprPrecedence::Async, + ExprKind::Await(..) => ExprPrecedence::Await, ExprKind::Assign(..) => ExprPrecedence::Assign, ExprKind::AssignOp(..) => ExprPrecedence::AssignOp, ExprKind::Field(..) => ExprPrecedence::Field, @@ -1186,6 +1182,9 @@ pub enum ExprKind { /// created during lowering cannot be made the parent of any other /// preexisting defs. Async(CaptureBy, NodeId, P), + /// An await expression (`my_future.await`). + Await(AwaitOrigin, P), + /// A try block (`try { ... }`). TryBlock(P), @@ -1287,6 +1286,15 @@ pub enum Movability { Movable, } +/// Whether an `await` comes from `await!` or `.await` syntax. +/// FIXME: this should be removed when support for legacy `await!` is removed. +/// https://github.com/rust-lang/rust/issues/60610 +#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, Copy)] +pub enum AwaitOrigin { + FieldLike, + MacroLike, +} + pub type Mac = Spanned; /// Represents a macro invocation. The `Path` indicates which macro @@ -1337,8 +1345,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 db821f4e5369d..65ca96afab129 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 e00f91e395280..d94a3165b0f1d 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}; 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 } @@ -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,7 +409,8 @@ 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, @@ -428,28 +421,28 @@ pub fn mk_sugared_doc_attr(id: AttrId, text: Symbol, span: Span) -> Attribute { } } -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 18173628a2602..c82936afa3d9f 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/entry.rs b/src/libsyntax/entry.rs index 09e26e29d86a8..0b6cf30bd27d2 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 452cc2f2c65cc..0a88d2f8824d3 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; } @@ -998,6 +998,7 @@ pub fn expr_to_spanned_string<'a>( Err(match expr.node { ast::ExprKind::Lit(ref l) => match l.node { ast::LitKind::Str(s, style) => return Ok(respan(expr.span, (s, style))), + ast::LitKind::Err(_) => None, _ => Some(cx.struct_span_err(l.span, err_msg)) }, ast::ExprKind::Err => None, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 40dd187ed28a7..d24106f697e19 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 6df369133d01d..a24e09f127eae 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 82358679c0e82..a286fd83e3c20 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; } diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 549de1628eb55..e1cb90d9e71d6 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_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index ab5823eaca52a..084a69f4cda0f 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -554,7 +554,10 @@ fn inner_parse_loop<'root, 'tt>( match item.top_elts.get_tt(idx) { // Need to descend into a sequence TokenTree::Sequence(sp, seq) => { - // Examine the case where there are 0 matches of this sequence + // Examine the case where there are 0 matches of this sequence. We are + // implicitly disallowing OneOrMore from having 0 matches here. Thus, that will + // result in a "no rules expected token" error by virtue of this matcher not + // working. if seq.op == quoted::KleeneOp::ZeroOrMore || seq.op == quoted::KleeneOp::ZeroOrOne { diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index b1b9d25b3d56b..06651750de741 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; @@ -151,7 +151,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>, let rhs_spans = rhs.iter().map(|t| t.span()).collect::>(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = transcribe(cx, Some(named_matches), rhs); + let mut tts = transcribe(cx, &named_matches, rhs); // Replace all the tokens for the corresponding positions in the macro, to maintain // proper positions in error reporting, while maintaining the macro_backtrace. @@ -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/quoted.rs b/src/libsyntax/ext/tt/quoted.rs index b24edb57e527e..ed8395f11ad50 100644 --- a/src/libsyntax/ext/tt/quoted.rs +++ b/src/libsyntax/ext/tt/quoted.rs @@ -73,6 +73,7 @@ pub enum KleeneOp { ZeroOrMore, /// Kleene plus (`+`) for one or more repetitions OneOrMore, + /// Kleene optional (`?`) for zero or one reptitions ZeroOrOne, } diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index bd2adb5ac13ba..e3586c1854c17 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -1,10 +1,10 @@ use crate::ast::Ident; use crate::ext::base::ExtCtxt; use crate::ext::expand::Marker; -use crate::ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal}; +use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use crate::ext::tt::quoted; use crate::mut_visit::noop_visit_tt; -use crate::parse::token::{self, Token, NtTT}; +use crate::parse::token::{self, NtTT, Token}; use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; use smallvec::{smallvec, SmallVec}; @@ -13,24 +13,16 @@ use syntax_pos::DUMMY_SP; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::mem; -use std::ops::Add; use std::rc::Rc; -// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). +/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`). enum Frame { - Delimited { - forest: Lrc, - idx: usize, - span: DelimSpan, - }, - Sequence { - forest: Lrc, - idx: usize, - sep: Option, - }, + Delimited { forest: Lrc, idx: usize, span: DelimSpan }, + Sequence { forest: Lrc, idx: usize, sep: Option }, } impl Frame { + /// Construct a new frame around the delimited set of tokens. fn new(tts: Vec) -> Frame { let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts: tts }); Frame::Delimited { forest: forest, idx: 0, span: DelimSpan::dummy() } @@ -54,84 +46,159 @@ impl Iterator for Frame { } } -/// This can do Macro-By-Example transcription. On the other hand, if -/// `src` contains no `TokenTree::{Sequence, MetaVar, MetaVarDecl}`s, `interp` can -/// (and should) be None. -pub fn transcribe(cx: &ExtCtxt<'_>, - interp: Option>>, - src: Vec) - -> TokenStream { +/// This can do Macro-By-Example transcription. +/// - `interp` is a map of meta-variables to the tokens (non-terminals) they matched in the +/// invocation. We are assuming we already know there is a match. +/// - `src` is the RHS of the MBE, that is, the "example" we are filling in. +/// +/// For example, +/// +/// ```rust +/// macro_rules! foo { +/// ($id:ident) => { println!("{}", stringify!($id)); } +/// } +/// +/// foo!(bar); +/// ``` +/// +/// `interp` would contain `$id => bar` and `src` would contain `println!("{}", stringify!($id));`. +/// +/// `transcribe` would return a `TokenStream` containing `println!("{}", stringify!(bar));`. +/// +/// Along the way, we do some additional error checking. +pub fn transcribe( + cx: &ExtCtxt<'_>, + interp: &FxHashMap>, + src: Vec, +) -> TokenStream { + // Nothing for us to transcribe... + if src.is_empty() { + return TokenStream::empty(); + } + + // We descend into the RHS (`src`), expanding things as we go. This stack contains the things + // we have yet to expand/are still expanding. We start the stack off with the whole RHS. let mut stack: SmallVec<[Frame; 1]> = smallvec![Frame::new(src)]; - let interpolations = interp.unwrap_or_else(FxHashMap::default); /* just a convenience */ + + // As we descend in the RHS, we will need to be able to match nested sequences of matchers. + // `repeats` keeps track of where we are in matching at each level, with the last element being + // the most deeply nested sequence. This is used as a stack. let mut repeats = Vec::new(); + + // `result` contains resulting token stream from the TokenTree we just finished processing. At + // the end, this will contain the full result of transcription, but at arbitrary points during + // `transcribe`, `result` will contain subsets of the final result. + // + // Specifically, as we descend into each TokenTree, we will push the existing results onto the + // `result_stack` and clear `results`. We will then produce the results of transcribing the + // TokenTree into `results`. Then, as we unwind back out of the `TokenTree`, we will pop the + // `result_stack` and append `results` too it to produce the new `results` up to that point. + // + // Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level + // again, and we are done transcribing. let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); loop { + // Look at the last frame on the stack. let tree = if let Some(tree) = stack.last_mut().unwrap().next() { + // If it still has a TokenTree we have not looked at yet, use that tree. tree - } else { + } + // The else-case never produces a value for `tree` (it `continue`s or `return`s). + else { + // Otherwise, if we have just reached the end of a sequence and we can keep repeating, + // go back to the beginning of the sequence. if let Frame::Sequence { ref mut idx, ref sep, .. } = *stack.last_mut().unwrap() { let (ref mut repeat_idx, repeat_len) = *repeats.last_mut().unwrap(); *repeat_idx += 1; if *repeat_idx < repeat_len { *idx = 0; if let Some(sep) = sep.clone() { - // repeat same span, I guess let prev_span = match result.last() { Some((tt, _)) => tt.span(), None => DUMMY_SP, }; result.push(TokenTree::Token(prev_span, sep).into()); } - continue + continue; } } + // We are done with the top of the stack. Pop it. Depending on what it was, we do + // different things. Note that the outermost item must be the delimited, wrapped RHS + // that was passed in originally to `transcribe`. match stack.pop().unwrap() { + // Done with a sequence. Pop from repeats. Frame::Sequence { .. } => { repeats.pop(); } + + // We are done processing a Delimited. If this is the top-level delimited, we are + // done. Otherwise, we unwind the result_stack to append what we have produced to + // any previous results. Frame::Delimited { forest, span, .. } => { if result_stack.is_empty() { + // No results left to compute! We are back at the top-level. return TokenStream::new(result); } - let tree = TokenTree::Delimited( - span, - forest.delim, - TokenStream::new(result).into(), - ); + + // Step back into the parent Delimited. + let tree = + TokenTree::Delimited(span, forest.delim, TokenStream::new(result).into()); result = result_stack.pop().unwrap(); result.push(tree.into()); } } - continue + continue; }; + // At this point, we know we are in the middle of a TokenTree (the last one on `stack`). + // `tree` contains the next `TokenTree` to be processed. match tree { - quoted::TokenTree::Sequence(sp, seq) => { - // FIXME(pcwalton): Bad copy. - match lockstep_iter_size("ed::TokenTree::Sequence(sp, seq.clone()), - &interpolations, - &repeats) { + // We are descending into a sequence. We first make sure that the matchers in the RHS + // and the matches in `interp` have the same shape. Otherwise, either the caller or the + // macro writer has made a mistake. + seq @ quoted::TokenTree::Sequence(..) => { + match lockstep_iter_size(&seq, interp, &repeats) { LockstepIterSize::Unconstrained => { - cx.span_fatal(sp.entire(), /* blame macro writer */ - "attempted to repeat an expression \ - containing no syntax \ - variables matched as repeating at this depth"); + cx.span_fatal( + seq.span(), /* blame macro writer */ + "attempted to repeat an expression containing no syntax variables \ + matched as repeating at this depth", + ); } + LockstepIterSize::Contradiction(ref msg) => { - // FIXME #2887 blame macro invoker instead - cx.span_fatal(sp.entire(), &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, _) => { + // We do this to avoid an extra clone above. We know that this is a + // sequence already. + let (sp, seq) = if let quoted::TokenTree::Sequence(sp, seq) = seq { + (sp, seq) + } else { + unreachable!() + }; + + // Is the repetition empty? if len == 0 { if seq.op == quoted::KleeneOp::OneOrMore { - // 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. repeats.push((0, len)); + + // The first time we encounter the sequence we push it to the stack. It + // then gets reused (see the beginning of the loop) until we are done + // repeating. stack.push(Frame::Sequence { idx: 0, sep: seq.separator.clone(), @@ -141,10 +208,16 @@ pub fn transcribe(cx: &ExtCtxt<'_>, } } } - // FIXME #2887: think about span stuff here + + // Replace the meta-var with the matched token tree from the invocation. quoted::TokenTree::MetaVar(mut sp, ident) => { - if let Some(cur_matched) = lookup_cur_matched(ident, &interpolations, &repeats) { + // Find the matched nonterminal from the macro invocation, and use it to replace + // the meta-var. + if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { if let MatchedNonterminal(ref nt) = *cur_matched { + // FIXME #2887: why do we apply a mark when matching a token tree meta-var + // (e.g. `$x:tt`), but not when we are matching any other type of token + // tree? if let NtTT(ref tt) = **nt { result.push(tt.clone().into()); } else { @@ -153,10 +226,15 @@ pub fn transcribe(cx: &ExtCtxt<'_>, result.push(token.into()); } } else { - cx.span_fatal(sp, /* blame the macro writer */ - &format!("variable '{}' is still repeating at this depth", ident)); + // We were unable to descend far enough. This is an error. + cx.span_fatal( + sp, /* blame the macro writer */ + &format!("variable '{}' is still repeating at this depth", ident), + ); } } else { + // If we aren't able to match the meta-var, we push it back into the result but + // with modified syntax context. (I believe this supports nested macros). let ident = Ident::new(ident.name, ident.span.apply_mark(cx.current_expansion.mark)); sp = sp.apply_mark(cx.current_expansion.mark); @@ -164,26 +242,44 @@ pub fn transcribe(cx: &ExtCtxt<'_>, result.push(TokenTree::Token(sp, token::Token::from_ast_ident(ident)).into()); } } + + // If we are entering a new delimiter, we push its contents to the `stack` to be + // processed, and we push all of the currently produced results to the `result_stack`. + // We will produce all of the results of the inside of the `Delimited` and then we will + // jump back out of the Delimited, pop the result_stack and add the new results back to + // the previous results (from outside the Delimited). quoted::TokenTree::Delimited(mut span, delimited) => { span = span.apply_mark(cx.current_expansion.mark); stack.push(Frame::Delimited { forest: delimited, idx: 0, span: span }); result_stack.push(mem::replace(&mut result, Vec::new())); } + + // Nothing much to do here. Just push the token to the result, being careful to + // preserve syntax context. quoted::TokenTree::Token(sp, tok) => { let mut marker = Marker(cx.current_expansion.mark); let mut tt = TokenTree::Token(sp, tok); noop_visit_tt(&mut tt, &mut marker); result.push(tt.into()); } + + // There should be no meta-var declarations in the invocation of a macro. quoted::TokenTree::MetaVarDecl(..) => panic!("unexpected `TokenTree::MetaVarDecl"), } } } -fn lookup_cur_matched(ident: Ident, - interpolations: &FxHashMap>, - repeats: &[(usize, usize)]) - -> Option> { +/// Lookup the meta-var named `ident` and return the matched token tree from the invocation using +/// the set of matches `interpolations`. +/// +/// See the definition of `repeats` in the `transcribe` function. `repeats` is used to descend +/// into the right place in nested matchers. If we attempt to descend too far, the macro writer has +/// made a mistake, and we return `None`. +fn lookup_cur_matched( + ident: Ident, + interpolations: &FxHashMap>, + repeats: &[(usize, usize)], +) -> Option> { interpolations.get(&ident).map(|matched| { let mut matched = matched.clone(); for &(idx, _) in repeats { @@ -198,17 +294,30 @@ fn lookup_cur_matched(ident: Ident, }) } +/// An accumulator over a TokenTree to be used with `fold`. During transcription, we need to make +/// sure that the size of each sequence and all of its nested sequences are the same as the sizes +/// of all the matched (nested) sequences in the macro invocation. If they don't match, somebody +/// has made a mistake (either the macro writer or caller). #[derive(Clone)] enum LockstepIterSize { + /// No constraints on length of matcher. This is true for any TokenTree variants except a + /// `MetaVar` with an actual `MatchedSeq` (as opposed to a `MatchedNonterminal`). Unconstrained, + + /// A `MetaVar` with an actual `MatchedSeq`. The length of the match and the name of the + /// meta-var are returned. Constraint(usize, Ident), + + /// Two `Constraint`s on the same sequence had different lengths. This is an error. Contradiction(String), } -impl Add for LockstepIterSize { - type Output = LockstepIterSize; - - fn add(self, other: LockstepIterSize) -> LockstepIterSize { +impl LockstepIterSize { + /// Find incompatibilities in matcher/invocation sizes. + /// - `Unconstrained` is compatible with everything. + /// - `Contradiction` is incompatible with everything. + /// - `Constraint(len)` is only compatible with other constraints of the same length. + fn with(self, other: LockstepIterSize) -> LockstepIterSize { match self { LockstepIterSize::Unconstrained => other, LockstepIterSize::Contradiction(_) => self, @@ -217,9 +326,11 @@ impl Add for LockstepIterSize { LockstepIterSize::Contradiction(_) => other, LockstepIterSize::Constraint(r_len, _) if l_len == r_len => self, LockstepIterSize::Constraint(r_len, r_id) => { - let msg = format!("inconsistent lockstep iteration: \ - '{}' has {} items, but '{}' has {}", - l_id, l_len, r_id, r_len); + let msg = format!( + "inconsistent lockstep iteration: \ + '{}' has {} items, but '{}' has {}", + l_id, l_len, r_id, r_len + ); LockstepIterSize::Contradiction(msg) } }, @@ -227,30 +338,38 @@ impl Add for LockstepIterSize { } } -fn lockstep_iter_size(tree: "ed::TokenTree, - interpolations: &FxHashMap>, - repeats: &[(usize, usize)]) - -> LockstepIterSize { +/// Given a `tree`, make sure that all sequences have the same length as the matches for the +/// appropriate meta-vars in `interpolations`. +/// +/// Note that if `repeats` does not match the exact correct depth of a meta-var, +/// `lookup_cur_matched` will return `None`, which is why this still works even in the presnece of +/// multiple nested matcher sequences. +fn lockstep_iter_size( + tree: "ed::TokenTree, + interpolations: &FxHashMap>, + repeats: &[(usize, usize)], +) -> LockstepIterSize { use quoted::TokenTree; match *tree { TokenTree::Delimited(_, ref delimed) => { delimed.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { - size + lockstep_iter_size(tt, interpolations, repeats) + size.with(lockstep_iter_size(tt, interpolations, repeats)) }) - }, + } TokenTree::Sequence(_, ref seq) => { seq.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| { - size + lockstep_iter_size(tt, interpolations, repeats) + size.with(lockstep_iter_size(tt, interpolations, repeats)) }) - }, - TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => + } + TokenTree::MetaVar(_, name) | TokenTree::MetaVarDecl(_, name, _) => { match lookup_cur_matched(name, interpolations, repeats) { Some(matched) => match *matched { MatchedNonterminal(_) => LockstepIterSize::Unconstrained, MatchedSeq(ref ads, _) => LockstepIterSize::Constraint(ads.len(), name), }, - _ => LockstepIterSize::Unconstrained - }, + _ => LockstepIterSize::Unconstrained, + } + } TokenTree::Token(..) => LockstepIterSize::Unconstrained, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2a1f3c4801406..8a066f3f4a093 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)),+ ]; } } @@ -108,8 +108,8 @@ macro_rules! declare_features { // was set. This is most important for knowing when a particular feature became // stable (active). // -// Note that the features should be grouped into internal/user-facing -// and then sorted by version inside those groups. This is inforced with tidy. +// Note that the features are grouped into internal/user-facing and then +// sorted by version inside those groups. This is inforced with tidy. // // N.B., `tools/tidy/src/features.rs` parses this information directly out of the // source, so take care when modifying it. @@ -119,7 +119,7 @@ declare_features! ( // feature-group-start: internal feature gates // ------------------------------------------------------------------------- - // no tracking issue START + // no-tracking-issue-start // Allows using the `rust-intrinsic`'s "ABI". (active, intrinsics, "1.0.0", None, None), @@ -152,7 +152,7 @@ declare_features! ( // lets a function to be `const` when opted into with `#![feature(foo)]`. (active, rustc_const_unstable, "1.0.0", None, None), - // no tracking issue END + // no-tracking-issue-end // Allows using `#[link_name="llvm.*"]`. (active, link_llvm_intrinsics, "1.0.0", Some(29602), None), @@ -187,20 +187,17 @@ declare_features! ( // Allows using `box` in patterns (RFC 469). (active, box_patterns, "1.0.0", Some(29641), None), - // no tracking issue START + // no-tracking-issue-start // Allows using `#[prelude_import]` on glob `use` items. (active, prelude_import, "1.2.0", None, None), - // no tracking issue END + // no-tracking-issue-end // Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (active, dropck_parametricity, "1.3.0", Some(28498), None), - // FIXME(Centril): Investigate whether this gate actually has any effect. - (active, needs_allocator, "1.4.0", Some(27389), None), - - // no tracking issue START + // no-tracking-issue-start // Allows using `#[omit_gdb_pretty_printer_section]`. (active, omit_gdb_pretty_printer_section, "1.5.0", None, None), @@ -208,7 +205,7 @@ declare_features! ( // Allows using the `vectorcall` ABI. (active, abi_vectorcall, "1.7.0", None, None), - // no tracking issue END + // no-tracking-issue-end // Allows using `#[structural_match]` which indicates that a type is structurally matchable. (active, structural_match, "1.8.0", Some(31434), None), @@ -222,7 +219,7 @@ declare_features! ( // Allows declaring with `#![needs_panic_runtime]` that a panic runtime is needed. (active, needs_panic_runtime, "1.10.0", Some(32837), None), - // no tracking issue START + // no-tracking-issue-start // Allows identifying the `compiler_builtins` crate. (active, compiler_builtins, "1.13.0", None, None), @@ -245,7 +242,7 @@ declare_features! ( // Allows using the `format_args_nl` macro. (active, format_args_nl, "1.29.0", None, None), - // no tracking issue END + // no-tracking-issue-end // Added for testing E0705; perma-unstable. (active, test_2018_feature, "1.31.0", Some(0), Some(Edition::Edition2018)), @@ -485,6 +482,10 @@ declare_features! ( // Allows async and await syntax. (active, async_await, "1.28.0", Some(50547), None), + // Allows await! macro-like syntax. + // This will likely be removed prior to stabilization of async/await. + (active, await_macro, "1.28.0", Some(50547), None), + // Allows reinterpretation of the bits of a value of one type as another type during const eval. (active, const_transmute, "1.29.0", Some(53605), None), @@ -561,12 +562,17 @@ 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! ( + // ------------------------------------------------------------------------- + // feature-group-start: removed features + // ------------------------------------------------------------------------- + (removed, import_shadowing, "1.0.0", None, None, None), (removed, managed_boxes, "1.0.0", None, None, None), // Allows use of unary negate on unsigned integers, e.g., -e for e: u8 @@ -581,7 +587,6 @@ declare_features! ( (removed, unsafe_no_drop_flag, "1.0.0", None, None, None), // Allows using items which are missing stability attributes (removed, unmarked_api, "1.0.0", None, None, None), - (removed, pushpop_unsafe, "1.2.0", None, None, None), (removed, allocator, "1.0.0", None, None, None), (removed, simd, "1.0.0", Some(27731), None, Some("removed in favor of `#[repr(simd)]`")), @@ -589,6 +594,9 @@ declare_features! ( Some("merged into `#![feature(slice_patterns)]`")), (removed, macro_reexport, "1.0.0", Some(29638), None, Some("subsumed by `pub use`")), + (removed, pushpop_unsafe, "1.2.0", None, None, None), + (removed, needs_allocator, "1.4.0", Some(27389), None, + Some("subsumed by `#![feature(allocator_internals)]`")), (removed, proc_macro_mod, "1.27.0", Some(54727), None, Some("subsumed by `#![feature(proc_macro_hygiene)]`")), (removed, proc_macro_expr, "1.27.0", Some(54727), None, @@ -600,12 +608,16 @@ declare_features! ( (removed, panic_implementation, "1.28.0", Some(44489), None, Some("subsumed by `#[panic_handler]`")), // Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. - (removed, custom_derive, "1.0.0", Some(29644), None, + (removed, custom_derive, "1.32.0", Some(29644), None, Some("subsumed by `#[proc_macro_derive]`")), // Paths of the form: `extern::foo::bar` (removed, extern_in_paths, "1.33.0", Some(55600), None, Some("subsumed by `::foo::bar` paths")), - (removed, quote, "1.0.0", Some(29601), None, None), + (removed, quote, "1.33.0", Some(29601), None, None), + + // ------------------------------------------------------------------------- + // feature-group-end: removed features + // ------------------------------------------------------------------------- ); declare_features! ( @@ -613,6 +625,10 @@ declare_features! ( ); declare_features! ( + // ------------------------------------------------------------------------- + // feature-group-start: for testing purposes + // ------------------------------------------------------------------------- + // A temporary feature gate used to enable parser extensions needed // to bootstrap fix for #5723. (accepted, issue_5723_bootstrap, "1.0.0", None, None), @@ -620,6 +636,14 @@ declare_features! ( // they don't actually mean anything. (accepted, test_accepted_feature, "1.0.0", None, None), + // ------------------------------------------------------------------------- + // feature-group-end: for testing purposes + // ------------------------------------------------------------------------- + + // ------------------------------------------------------------------------- + // feature-group-start: accepted features + // ------------------------------------------------------------------------- + // Allows using associated `type`s in `trait`s. (accepted, associated_types, "1.0.0", None, None), // Allows using assigning a default type to type parameters in algebraic data type definitions. @@ -809,6 +833,10 @@ declare_features! ( (accepted, extern_crate_self, "1.34.0", Some(56409), None), // Allows arbitrary delimited token streams in non-macro attributes. (accepted, unrestricted_attribute_tokens, "1.34.0", Some(55208), None), + + // ------------------------------------------------------------------------- + // feature-group-end: accepted features + // ------------------------------------------------------------------------- ); // If you change this, please modify `src/doc/unstable-book` as well. You must @@ -833,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, @@ -935,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), - - (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::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), + + (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, Normal, 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", @@ -1168,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 \ @@ -1224,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 @@ -1296,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, @@ -1393,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))), ]; @@ -1476,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)] @@ -1513,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 { @@ -1532,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) }; } @@ -1555,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" ); @@ -1567,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. @@ -1577,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); @@ -1602,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 @@ -1634,7 +1663,7 @@ pub enum GateStrength { pub fn emit_feature_err( sess: &ParseSess, - feature: &str, + feature: Symbol, span: Span, issue: GateIssue, explain: &str, @@ -1644,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, @@ -1654,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, @@ -1742,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) } }} @@ -1814,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) { @@ -1866,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" ); @@ -1919,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"); } @@ -1930,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 \ @@ -1949,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"); } @@ -1960,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"); } @@ -2024,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 @@ -2104,6 +2133,20 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::Async(..) => { gate_feature_post!(&self, async_await, e.span, "async blocks are unstable"); } + ast::ExprKind::Await(origin, _) => { + match origin { + ast::AwaitOrigin::FieldLike => + gate_feature_post!(&self, async_await, e.span, "async/await is unstable"), + ast::AwaitOrigin::MacroLike => + gate_feature_post!( + &self, + await_macro, + e.span, + "`await!()` macro syntax is unstable, and will soon be removed \ + in favor of `.await` syntax." + ), + } + } _ => {} } visit::walk_expr(self, e); @@ -2262,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); } } @@ -2270,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); } } } @@ -2278,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 } @@ -2314,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); } } } @@ -2323,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 } @@ -2397,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 { @@ -2455,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/json.rs b/src/libsyntax/json.rs index 65f8d0e77d7be..2dd2ecb749300 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -19,6 +19,7 @@ use errors::emitter::{Emitter, HumanReadableErrorType}; use syntax_pos::{MacroBacktrace, Span, SpanLabel, MultiSpan}; use rustc_data_structures::sync::{self, Lrc}; use std::io::{self, Write}; +use std::path::Path; use std::vec; use std::sync::{Arc, Mutex}; @@ -91,15 +92,15 @@ impl Emitter for JsonEmitter { } } - fn maybe_emit_json_directive(&mut self, directive: String) { - let data = Directive { directive }; + fn emit_artifact_notification(&mut self, path: &Path) { + let data = ArtifactNotification { artifact: path }; let result = if self.pretty { writeln!(&mut self.dst, "{}", as_pretty_json(&data)) } else { writeln!(&mut self.dst, "{}", as_json(&data)) }; if let Err(e) = result { - panic!("failed to print message: {:?}", e); + panic!("failed to print notification: {:?}", e); } } } @@ -181,9 +182,9 @@ struct DiagnosticCode { } #[derive(RustcEncodable)] -struct Directive { - /// The directive itself. - directive: String, +struct ArtifactNotification<'a> { + /// The path of the artifact. + artifact: &'a Path, } impl Diagnostic { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 2e09235ca77b0..f587e63e12b94 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| { @@ -1185,6 +1181,7 @@ pub fn noop_visit_expr(Expr { node, id, span, attrs }: &mut Expr, vis.visit_id(node_id); vis.visit_block(body); } + ExprKind::Await(_origin, expr) => vis.visit_expr(expr), ExprKind::Assign(el, er) => { vis.visit_expr(el); vis.visit_expr(er); diff --git a/src/libsyntax/parse/classify.rs b/src/libsyntax/parse/classify.rs index b4103440e3577..dfd6f451c28d7 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/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs index 74fff3324eacf..97d3fc002e9b0 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 cf8f8abe2ab50..e76605cde32ab 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -1,8 +1,10 @@ use crate::ast::{self, Ident}; use crate::parse::{token, ParseSess}; use crate::symbol::Symbol; +use crate::parse::unescape; +use crate::parse::unescape_error_reporting::{emit_unescape_error, push_escaped_char}; -use errors::{Applicability, FatalError, Diagnostic, DiagnosticBuilder}; +use errors::{FatalError, Diagnostic, DiagnosticBuilder}; use syntax_pos::{BytePos, Pos, Span, NO_EXPANSION}; use core::unicode::property::Pattern_White_Space; @@ -260,18 +262,6 @@ impl<'a> StringReader<'a> { } } - 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> { @@ -334,25 +324,12 @@ impl<'a> StringReader<'a> { self.err_span(self.mk_sp(from_pos, to_pos), m) } - /// Pushes a character to a message string for error reporting - fn push_escaped_char_for_msg(m: &mut String, c: char) { - match c { - '\u{20}'..='\u{7e}' => { - // Don't escape \, ' or " for user-facing messages - m.push(c); - } - _ => { - m.extend(c.escape_default()); - } - } - } - /// Report a lexical error spanning [`from_pos`, `to_pos`), appending an /// escaped character to the error message fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError { let mut m = m.to_string(); m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); + push_escaped_char(&mut m, c); self.fatal_span_(from_pos, to_pos, &m[..]) } @@ -368,7 +345,7 @@ impl<'a> StringReader<'a> { { let mut m = m.to_string(); m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); + push_escaped_char(&mut m, c); self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..]) } @@ -378,29 +355,10 @@ impl<'a> StringReader<'a> { fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) { let mut m = m.to_string(); m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); + push_escaped_char(&mut m, c); self.err_span_(from_pos, to_pos, &m[..]); } - fn struct_err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) - -> DiagnosticBuilder<'a> - { - let mut m = m.to_string(); - m.push_str(": "); - Self::push_escaped_char_for_msg(&mut m, c); - - self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..]) - } - - /// Report a lexical error spanning [`from_pos`, `to_pos`), appending the - /// offending string to the error message - fn fatal_span_verbose(&self, from_pos: BytePos, to_pos: BytePos, mut m: String) -> FatalError { - m.push_str(": "); - m.push_str(&self.src[self.src_index(from_pos)..self.src_index(to_pos)]); - - self.fatal_span_(from_pos, to_pos, &m[..]) - } - /// Advance peek_tok and peek_span to refer to the next token, and /// possibly update the interner. fn advance_token(&mut self) -> Result<(), ()> { @@ -863,271 +821,6 @@ impl<'a> StringReader<'a> { } } - /// Scan over `n_digits` hex digits, stopping at `delim`, reporting an - /// error if too many or too few digits are encountered. - fn scan_hex_digits(&mut self, n_digits: usize, delim: char, below_0x7f_only: bool) -> bool { - debug!("scanning {} digits until {:?}", n_digits, delim); - let start_bpos = self.pos; - let mut accum_int = 0; - - let mut valid = true; - for _ in 0..n_digits { - if self.is_eof() { - let last_bpos = self.pos; - self.fatal_span_(start_bpos, - last_bpos, - "unterminated numeric character escape").raise(); - } - if self.ch_is(delim) { - let last_bpos = self.pos; - self.err_span_(start_bpos, - last_bpos, - "numeric character escape is too short"); - valid = false; - break; - } - let c = self.ch.unwrap_or('\x00'); - accum_int *= 16; - accum_int += c.to_digit(16).unwrap_or_else(|| { - self.err_span_char(self.pos, - self.next_pos, - "invalid character in numeric character escape", - c); - - valid = false; - 0 - }); - self.bump(); - } - - if below_0x7f_only && accum_int >= 0x80 { - self.err_span_(start_bpos, - self.pos, - "this form of character escape may only be used with characters in \ - the range [\\x00-\\x7f]"); - valid = false; - } - - match char::from_u32(accum_int) { - Some(_) => valid, - None => { - let last_bpos = self.pos; - self.err_span_(start_bpos, last_bpos, "invalid numeric character escape"); - false - } - } - } - - /// Scan for a single (possibly escaped) byte or char - /// in a byte, (non-raw) byte string, char, or (non-raw) string literal. - /// `start` is the position of `first_source_char`, which is already consumed. - /// - /// Returns `true` if there was a valid char/byte. - fn scan_char_or_byte(&mut self, - start: BytePos, - first_source_char: char, - ascii_only: bool, - delim: char) - -> bool - { - match first_source_char { - '\\' => { - // '\X' for some X must be a character constant: - let escaped = self.ch; - let escaped_pos = self.pos; - self.bump(); - match escaped { - None => {} // EOF here is an error that will be checked later. - Some(e) => { - return match e { - 'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true, - 'x' => self.scan_byte_escape(delim, !ascii_only), - 'u' => { - let valid = if self.ch_is('{') { - self.scan_unicode_escape(delim) && !ascii_only - } else { - let span = self.mk_sp(start, self.pos); - let mut suggestion = "\\u{".to_owned(); - let msg = "incorrect unicode escape sequence"; - let mut err = self.sess.span_diagnostic.struct_span_err( - span, - msg, - ); - let mut i = 0; - while let (Some(ch), true) = (self.ch, i < 6) { - if ch.is_digit(16) { - suggestion.push(ch); - self.bump(); - i += 1; - } else { - break; - } - } - if i != 0 { - suggestion.push('}'); - err.span_suggestion( - self.mk_sp(start, self.pos), - "format of unicode escape sequences uses braces", - suggestion, - Applicability::MaybeIncorrect, - ); - } else { - err.span_label(span, msg); - err.help( - "format of unicode escape sequences is `\\u{...}`", - ); - } - err.emit(); - false - }; - if ascii_only { - self.err_span_(start, - self.pos, - "unicode escape sequences cannot be used as a \ - byte or in a byte string"); - } - valid - - } - '\n' if delim == '"' => { - self.consume_whitespace(); - true - } - '\r' if delim == '"' && self.ch_is('\n') => { - self.consume_whitespace(); - true - } - c => { - let pos = self.pos; - let msg = if ascii_only { - "unknown byte escape" - } else { - "unknown character escape" - }; - let mut err = self.struct_err_span_char(escaped_pos, pos, msg, c); - err.span_label(self.mk_sp(escaped_pos, pos), msg); - if e == '\r' { - err.help( - "this is an isolated carriage return; consider checking \ - your editor and version control settings", - ); - } - if (e == '{' || e == '}') && !ascii_only { - err.help( - "if used in a formatting string, curly braces are escaped \ - with `{{` and `}}`", - ); - } - err.emit(); - false - } - } - } - } - } - '\t' | '\n' | '\r' | '\'' if delim == '\'' => { - let pos = self.pos; - self.err_span_char(start, - pos, - if ascii_only { - "byte constant must be escaped" - } else { - "character constant must be escaped" - }, - first_source_char); - return false; - } - '\r' => { - if self.ch_is('\n') { - self.bump(); - return true; - } else { - self.err_span_(start, - self.pos, - "bare CR not allowed in string, use \\r instead"); - return false; - } - } - _ => { - if ascii_only && first_source_char > '\x7F' { - let pos = self.pos; - self.err_span_(start, - pos, - "byte constant must be ASCII. Use a \\xHH escape for a \ - non-ASCII byte"); - return false; - } - } - } - true - } - - /// Scan over a `\u{...}` escape - /// - /// At this point, we have already seen the `\` and the `u`, the `{` is the current character. - /// We will read a hex number (with `_` separators), with 1 to 6 actual digits, - /// and pass over the `}`. - fn scan_unicode_escape(&mut self, delim: char) -> bool { - self.bump(); // past the { - let start_bpos = self.pos; - let mut valid = true; - - if let Some('_') = self.ch { - // disallow leading `_` - self.err_span_(self.pos, - self.next_pos, - "invalid start of unicode escape"); - valid = false; - } - - let count = self.scan_digits(16, 16); - - if count > 6 { - self.err_span_(start_bpos, - self.pos, - "overlong unicode escape (must have at most 6 hex digits)"); - valid = false; - } - - loop { - match self.ch { - Some('}') => { - if valid && count == 0 { - self.err_span_(start_bpos, - self.pos, - "empty unicode escape (must have at least 1 hex digit)"); - valid = false; - } - self.bump(); // past the ending `}` - break; - }, - Some(c) => { - if c == delim { - self.err_span_(self.pos, - self.pos, - "unterminated unicode escape (needed a `}`)"); - valid = false; - break; - } else if valid { - self.err_span_char(start_bpos, - self.pos, - "invalid character in unicode escape", - c); - valid = false; - } - }, - None => { - self.fatal_span_(start_bpos, - self.pos, - "unterminated unicode escape (found EOF)").raise(); - } - } - self.bump(); - } - - valid - } - /// Scan over a float exponent. fn scan_float_exponent(&mut self) { if self.ch_is('e') || self.ch_is('E') { @@ -1393,26 +1086,21 @@ impl<'a> StringReader<'a> { self.bump(); let start = self.pos; - // the eof will be picked up by the final `'` check below - let c2 = self.ch.unwrap_or('\x00'); - self.bump(); - // If the character is an ident start not followed by another single // quote, then this is a lifetime name: - if (ident_start(Some(c2)) || c2.is_numeric()) && !self.ch_is('\'') { + let starts_with_number = self.ch.unwrap_or('\x00').is_numeric(); + if (ident_start(self.ch) || starts_with_number) && !self.nextch_is('\'') { + self.bump(); while ident_continue(self.ch) { self.bump(); } // lifetimes shouldn't end with a single quote // if we find one, then this is an invalid character literal if self.ch_is('\'') { - self.err_span_( - start_with_quote, - self.next_pos, - "character literal may only contain one codepoint"); + let id = self.name_from(start); self.bump(); - return Ok(token::Literal(token::Err(Symbol::intern("??")), None)) - + self.validate_char_escape(start_with_quote); + return Ok(token::Literal(token::Char(id), None)) } // Include the leading `'` in the real identifier, for macro @@ -1422,7 +1110,7 @@ impl<'a> StringReader<'a> { self.mk_ident(lifetime_name) }); - if c2.is_numeric() { + if starts_with_number { // this is a recovered lifetime written `'1`, error but accept it self.err_span_( start_with_quote, @@ -1433,58 +1121,30 @@ impl<'a> StringReader<'a> { return Ok(token::Lifetime(ident)); } - - let valid = self.scan_char_or_byte(start, c2, /* ascii_only */ false, '\''); - - if !self.ch_is('\'') { - let pos = self.pos; - - loop { - self.bump(); - if self.ch_is('\'') { - let start = self.src_index(start); - let end = self.src_index(self.pos); - self.bump(); - let span = self.mk_sp(start_with_quote, self.pos); - self.sess.span_diagnostic - .struct_span_err(span, - "character literal may only contain one codepoint") - .span_suggestion( - span, - "if you meant to write a `str` literal, use double quotes", - format!("\"{}\"", &self.src[start..end]), - Applicability::MachineApplicable - ).emit(); - return Ok(token::Literal(token::Err(Symbol::intern("??")), None)) - } - if self.ch_is('\n') || self.is_eof() || self.ch_is('/') { - // Only attempt to infer single line string literals. If we encounter - // a slash, bail out in order to avoid nonsensical suggestion when - // involving comments. - break; - } - } - - self.fatal_span_verbose(start_with_quote, pos, - String::from("character literal may only contain one codepoint")).raise(); - } - - let id = if valid { - self.name_from(start) - } else { - Symbol::intern("0") - }; - - self.bump(); // advance ch past token + let msg = "unterminated character literal"; + let id = self.scan_single_quoted_string(start_with_quote, msg); + self.validate_char_escape(start_with_quote); let suffix = self.scan_optional_raw_name(); - Ok(token::Literal(token::Char(id), suffix)) } 'b' => { self.bump(); let lit = match self.ch { - Some('\'') => self.scan_byte(), - Some('"') => self.scan_byte_string(), + Some('\'') => { + let start_with_quote = self.pos; + self.bump(); + let msg = "unterminated byte constant"; + let id = self.scan_single_quoted_string(start_with_quote, msg); + self.validate_byte_escape(start_with_quote); + token::Byte(id) + }, + Some('"') => { + let start_with_quote = self.pos; + let msg = "unterminated double quote byte string"; + let id = self.scan_double_quoted_string(msg); + self.validate_byte_str_escape(start_with_quote); + token::ByteStr(id) + }, Some('r') => self.scan_raw_byte_string(), _ => unreachable!(), // Should have been a token::Ident above. }; @@ -1493,32 +1153,11 @@ impl<'a> StringReader<'a> { Ok(token::Literal(lit, suffix)) } '"' => { - let start_bpos = self.pos; - let mut valid = true; - self.bump(); - - while !self.ch_is('"') { - if self.is_eof() { - let last_bpos = self.pos; - self.fatal_span_(start_bpos, - last_bpos, - "unterminated double quote string").raise(); - } - - let ch_start = self.pos; - let ch = self.ch.unwrap(); - self.bump(); - valid &= self.scan_char_or_byte(ch_start, ch, /* ascii_only */ false, '"'); - } - // adjust for the ASCII " at the start of the literal - let id = if valid { - self.name_from(start_bpos + BytePos(1)) - } else { - Symbol::intern("??") - }; - self.bump(); + let start_with_quote = self.pos; + let msg = "unterminated double quote string"; + let id = self.scan_double_quoted_string(msg); + self.validate_str_escape(start_with_quote); let suffix = self.scan_optional_raw_name(); - Ok(token::Literal(token::Str_(id), suffix)) } 'r' => { @@ -1659,12 +1298,6 @@ impl<'a> StringReader<'a> { } } - fn consume_whitespace(&mut self) { - while is_pattern_whitespace(self.ch) && !self.is_eof() { - self.bump(); - } - } - fn read_to_eol(&mut self) -> String { let mut val = String::new(); while !self.ch_is('\n') && !self.is_eof() { @@ -1698,73 +1331,63 @@ impl<'a> StringReader<'a> { (self.ch_is('#') && self.nextch_is('!') && !self.nextnextch_is('[')) } - fn scan_byte(&mut self) -> token::Lit { - self.bump(); + fn scan_single_quoted_string(&mut self, + start_with_quote: BytePos, + unterminated_msg: &str) -> ast::Name { + // assumes that first `'` is consumed let start = self.pos; - - // the eof will be picked up by the final `'` check below - let c2 = self.ch.unwrap_or('\x00'); - self.bump(); - - let valid = self.scan_char_or_byte(start, - c2, - // ascii_only = - true, - '\''); - if !self.ch_is('\'') { - // Byte offsetting here is okay because the - // character before position `start` are an - // ascii single quote and ascii 'b'. - let pos = self.pos; - self.fatal_span_verbose(start - BytePos(2), - pos, - "unterminated byte constant".to_string()).raise(); - } - - let id = if valid { - self.name_from(start) + // lex `'''` as a single char, for recovery + if self.ch_is('\'') && self.nextch_is('\'') { + self.bump(); } else { - Symbol::intern("?") - }; - self.bump(); // advance ch past token - - token::Byte(id) - } + let mut first = true; + loop { + if self.ch_is('\'') { + break; + } + if self.ch_is('\\') && (self.nextch_is('\'') || self.nextch_is('\\')) { + self.bump(); + self.bump(); + } else { + // Only attempt to infer single line string literals. If we encounter + // a slash, bail out in order to avoid nonsensical suggestion when + // involving comments. + if self.is_eof() + || (self.ch_is('/') && !first) + || (self.ch_is('\n') && !self.nextch_is('\'')) { + + self.fatal_span_(start_with_quote, self.pos, unterminated_msg.into()) + .raise() + } + self.bump(); + } + first = false; + } + } - #[inline] - fn scan_byte_escape(&mut self, delim: char, below_0x7f_only: bool) -> bool { - self.scan_hex_digits(2, delim, below_0x7f_only) + let id = self.name_from(start); + self.bump(); + id } - fn scan_byte_string(&mut self) -> token::Lit { + fn scan_double_quoted_string(&mut self, unterminated_msg: &str) -> ast::Name { + debug_assert!(self.ch_is('\"')); + let start_with_quote = self.pos; self.bump(); let start = self.pos; - let mut valid = true; - while !self.ch_is('"') { if self.is_eof() { let pos = self.pos; - self.fatal_span_(start, pos, "unterminated double quote byte string").raise(); + self.fatal_span_(start_with_quote, pos, unterminated_msg).raise(); + } + if self.ch_is('\\') && (self.nextch_is('\\') || self.nextch_is('"')) { + self.bump(); } - - let ch_start = self.pos; - let ch = self.ch.unwrap(); self.bump(); - valid &= self.scan_char_or_byte(ch_start, - ch, - // ascii_only = - true, - '"'); } - - let id = if valid { - self.name_from(start) - } else { - Symbol::intern("??") - }; + let id = self.name_from(start); self.bump(); - - token::ByteStr(id) + id } fn scan_raw_byte_string(&mut self) -> token::Lit { @@ -1826,6 +1449,70 @@ impl<'a> StringReader<'a> { token::ByteStrRaw(self.name_from_to(content_start_bpos, content_end_bpos), hash_count) } + + fn validate_char_escape(&self, start_with_quote: BytePos) { + self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| { + if let Err((off, err)) = unescape::unescape_char(lit) { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::Char, + 0..off, + err, + ) + } + }); + } + + fn validate_byte_escape(&self, start_with_quote: BytePos) { + self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| { + if let Err((off, err)) = unescape::unescape_byte(lit) { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::Byte, + 0..off, + err, + ) + } + }); + } + + fn validate_str_escape(&self, start_with_quote: BytePos) { + self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| { + unescape::unescape_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::Str, + range, + err, + ) + } + }) + }); + } + + fn validate_byte_str_escape(&self, start_with_quote: BytePos) { + self.with_str_from_to(start_with_quote + BytePos(1), self.pos - BytePos(1), |lit| { + unescape::unescape_byte_str(lit, &mut |range, c| { + if let Err(err) = c { + emit_unescape_error( + &self.sess.span_diagnostic, + lit, + self.mk_sp(start_with_quote, self.pos), + unescape::Mode::ByteStr, + range, + err, + ) + } + }) + }); + } } // This tests the character for the unicode property 'PATTERN_WHITE_SPACE' which @@ -1899,7 +1586,7 @@ mod tests { use std::io; use std::path::PathBuf; use syntax_pos::{BytePos, Span, NO_EXPANSION}; - use rustc_data_structures::fx::FxHashSet; + use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_data_structures::sync::Lock; fn mk_sess(sm: Lrc) -> ParseSess { @@ -1918,6 +1605,7 @@ mod tests { raw_identifier_spans: Lock::new(Vec::new()), registered_diagnostics: Lock::new(ErrorMap::new()), buffered_lints: Lock::new(vec![]), + ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), } } @@ -1927,7 +1615,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/literal.rs b/src/libsyntax/parse/literal.rs new file mode 100644 index 0000000000000..53195421ddcee --- /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 85a74df235738..655baafcd2d5d 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -5,20 +5,17 @@ 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; use crate::print::pprust::token_to_string; -use errors::{FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder}; +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; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use std::borrow::Cow; -use std::iter; use std::path::{Path, PathBuf}; use std::str; @@ -26,13 +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; +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 { @@ -48,6 +47,10 @@ pub struct ParseSess { included_mod_stack: Lock>, source_map: Lrc, pub buffered_lints: Lock>, + /// Contains the spans of block expressions that could have been incomplete based on the + /// operation token that followed it, but that the parser cannot identify without further + /// analysis. + pub ambiguous_block_expr_parse: Lock>, } impl ParseSess { @@ -71,6 +74,7 @@ impl ParseSess { included_mod_stack: Lock::new(vec![]), source_map, buffered_lints: Lock::new(vec![]), + ambiguous_block_expr_parse: Lock::new(FxHashMap::default()), } } @@ -94,6 +98,24 @@ impl ParseSess { }); }); } + + /// Extend an error with a suggestion to wrap an expression with parentheses to allow the + /// parser to continue parsing the following operation as part of the same expression. + pub fn expr_parentheses_needed( + &self, + err: &mut DiagnosticBuilder<'_>, + span: Span, + alt_snippet: Option, + ) { + if let Some(snippet) = self.source_map().span_to_snippet(span).ok().or(alt_snippet) { + err.span_suggestion( + span, + "parentheses are required to parse this as an expression", + format!("({})", snippet), + Applicability::MachineApplicable, + ); + } + } } #[derive(Clone)] @@ -307,463 +329,6 @@ pub fn stream_to_parser(sess: &ParseSess, stream: TokenStream) -> Parser<'_> { Parser::new(sess, stream, None, true, false) } -/// Parses a string representing a character literal into its final form. -/// Rather than just accepting/rejecting a given literal, unescapes it as -/// well. Can take any slice prefixed by a character escape. Returns the -/// character and the number of characters consumed. -fn char_lit(lit: &str, diag: Option<(Span, &Handler)>) -> (char, isize) { - use std::char; - - // Handle non-escaped chars first. - if lit.as_bytes()[0] != b'\\' { - // If the first byte isn't '\\' it might part of a multi-byte char, so - // get the char with chars(). - let c = lit.chars().next().unwrap(); - return (c, 1); - } - - // Handle escaped chars. - match lit.as_bytes()[1] as char { - '"' => ('"', 2), - 'n' => ('\n', 2), - 'r' => ('\r', 2), - 't' => ('\t', 2), - '\\' => ('\\', 2), - '\'' => ('\'', 2), - '0' => ('\0', 2), - 'x' => { - let v = u32::from_str_radix(&lit[2..4], 16).unwrap(); - let c = char::from_u32(v).unwrap(); - (c, 4) - } - 'u' => { - assert_eq!(lit.as_bytes()[2], b'{'); - let idx = lit.find('}').unwrap(); - - // All digits and '_' are ascii, so treat each byte as a char. - let mut v: u32 = 0; - for c in lit[3..idx].bytes() { - let c = char::from(c); - if c != '_' { - let x = c.to_digit(16).unwrap(); - v = v.checked_mul(16).unwrap().checked_add(x).unwrap(); - } - } - let c = char::from_u32(v).unwrap_or_else(|| { - if let Some((span, diag)) = diag { - let mut diag = diag.struct_span_err(span, "invalid unicode character escape"); - if v > 0x10FFFF { - diag.help("unicode escape must be at most 10FFFF").emit(); - } else { - diag.help("unicode escape must not be a surrogate").emit(); - } - } - '\u{FFFD}' - }); - (c, (idx + 1) as isize) - } - _ => panic!("lexer should have rejected a bad character escape {}", lit) - } -} - -/// Parses a string representing a string literal into its final form. Does unescaping. -fn str_lit(lit: &str, diag: Option<(Span, &Handler)>) -> String { - debug!("str_lit: given {}", lit.escape_default()); - let mut res = String::with_capacity(lit.len()); - - let error = |i| format!("lexer should have rejected {} at {}", lit, i); - - /// Eat everything up to a non-whitespace. - fn eat<'a>(it: &mut iter::Peekable>) { - loop { - match it.peek().map(|x| x.1) { - Some(' ') | Some('\n') | Some('\r') | Some('\t') => { - it.next(); - }, - _ => { break; } - } - } - } - - let mut chars = lit.char_indices().peekable(); - while let Some((i, c)) = chars.next() { - match c { - '\\' => { - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch == '\n' { - eat(&mut chars); - } else if ch == '\r' { - chars.next(); - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch != '\n' { - panic!("lexer accepted bare CR"); - } - eat(&mut chars); - } else { - // otherwise, a normal escape - let (c, n) = char_lit(&lit[i..], diag); - for _ in 0..n - 1 { // we don't need to move past the first \ - chars.next(); - } - res.push(c); - } - }, - '\r' => { - let ch = chars.peek().unwrap_or_else(|| { - panic!("{}", error(i)) - }).1; - - if ch != '\n' { - panic!("lexer accepted bare CR"); - } - chars.next(); - res.push('\n'); - } - c => res.push(c), - } - } - - res.shrink_to_fit(); // probably not going to do anything, unless there was an escape. - debug!("parse_str_lit: returning {}", res); - res -} - -/// 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) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))), - token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str(), diag).0))), - 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 s = &sym.as_str(); - if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') { - sym = Symbol::intern(&str_lit(s, diag)); - } - (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) => { - (true, Some(LitKind::ByteStr(byte_str_lit(&i.as_str())))) - } - 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) -} - -/// Parses a string representing a byte literal into its final form. Similar to `char_lit`. -fn byte_lit(lit: &str) -> (u8, usize) { - let err = |i| format!("lexer accepted invalid byte literal {} step {}", lit, i); - - if lit.len() == 1 { - (lit.as_bytes()[0], 1) - } else { - assert_eq!(lit.as_bytes()[0], b'\\', "{}", err(0)); - let b = match lit.as_bytes()[1] { - b'"' => b'"', - b'n' => b'\n', - b'r' => b'\r', - b't' => b'\t', - b'\\' => b'\\', - b'\'' => b'\'', - b'0' => b'\0', - _ => { - match u64::from_str_radix(&lit[2..4], 16).ok() { - Some(c) => - if c > 0xFF { - panic!(err(2)) - } else { - return (c as u8, 4) - }, - None => panic!(err(3)) - } - } - }; - (b, 2) - } -} - -fn byte_str_lit(lit: &str) -> Lrc> { - let mut res = Vec::with_capacity(lit.len()); - - let error = |i| panic!("lexer should have rejected {} at {}", lit, i); - - /// Eat everything up to a non-whitespace. - fn eat>(it: &mut iter::Peekable) { - loop { - match it.peek().map(|x| x.1) { - Some(b' ') | Some(b'\n') | Some(b'\r') | Some(b'\t') => { - it.next(); - }, - _ => { break; } - } - } - } - - // byte string literals *must* be ASCII, but the escapes don't have to be - let mut chars = lit.bytes().enumerate().peekable(); - loop { - match chars.next() { - Some((i, b'\\')) => { - match chars.peek().unwrap_or_else(|| error(i)).1 { - b'\n' => eat(&mut chars), - b'\r' => { - chars.next(); - if chars.peek().unwrap_or_else(|| error(i)).1 != b'\n' { - panic!("lexer accepted bare CR"); - } - eat(&mut chars); - } - _ => { - // otherwise, a normal escape - let (c, n) = byte_lit(&lit[i..]); - // we don't need to move past the first \ - for _ in 0..n - 1 { - chars.next(); - } - res.push(c); - } - } - }, - Some((i, b'\r')) => { - if chars.peek().unwrap_or_else(|| error(i)).1 != b'\n' { - panic!("lexer accepted bare CR"); - } - chars.next(); - res.push(b'\n'); - } - Some((_, c)) => res.push(c), - None => break, - } - } - - Lrc::new(res) -} - -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. @@ -826,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[..]; @@ -838,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)) { ( @@ -856,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::>(); @@ -866,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), } }, @@ -1010,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); @@ -1031,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 d46feeab33599..2d6c8c5407583 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,11 +46,14 @@ 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}; -use syntax_pos::{Span, MultiSpan, BytePos, FileName}; +use syntax_pos::{ + Span, MultiSpan, BytePos, FileName, + hygiene::CompilerDesugaringKind, +}; use log::{debug, trace}; use std::borrow::Cow; @@ -186,6 +189,7 @@ enum PrevTokenKind { Interpolated, Eof, Ident, + BitOr, Other, } @@ -609,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 { @@ -617,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), @@ -1105,43 +1104,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 @@ -1375,6 +1338,7 @@ impl<'a> Parser<'a> { token::DocComment(..) => PrevTokenKind::DocComment, token::Comma => PrevTokenKind::Comma, token::BinOp(token::Plus) => PrevTokenKind::Plus, + token::BinOp(token::Or) => PrevTokenKind::BitOr, token::Interpolated(..) => PrevTokenKind::Interpolated, token::Eof => PrevTokenKind::Eof, token::Ident(..) => PrevTokenKind::Ident, @@ -1418,7 +1382,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 } @@ -1447,9 +1411,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) } @@ -1576,7 +1537,7 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let d = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { + let mut decl = self.parse_fn_decl_with_self(|p: &mut Parser<'a>| { // This is somewhat dubious; We don't want to allow // argument names to be left off if there is a // definition... @@ -1585,7 +1546,7 @@ impl<'a> Parser<'a> { p.parse_arg_general(p.span.rust_2018(), true, false) })?; generics.where_clause = self.parse_where_clause()?; - self.construct_async_arguments(&mut asyncness, &d); + self.construct_async_arguments(&mut asyncness, &mut decl); let sig = ast::MethodSig { header: FnHeader { @@ -1594,7 +1555,7 @@ impl<'a> Parser<'a> { abi, asyncness, }, - decl: d, + decl, }; let body = match self.token { @@ -1872,7 +1833,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), @@ -1920,8 +1881,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"); @@ -2064,88 +2023,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); @@ -2319,7 +2196,8 @@ impl<'a> Parser<'a> { let ident = self.parse_path_segment_ident()?; let is_args_start = |token: &token::Token| match *token { - token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) => true, + token::Lt | token::BinOp(token::Shl) | token::OpenDelim(token::Paren) + | token::LArrow => true, _ => false, }; let check_args_start = |this: &mut Self| { @@ -2465,27 +2343,27 @@ impl<'a> Parser<'a> { }) } - fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec) -> P { + 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) @@ -2497,7 +2375,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) } @@ -2637,13 +2515,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); @@ -2751,6 +2628,14 @@ impl<'a> Parser<'a> { db.span_label(self.span, "expected expression"); 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); } else if self.token.is_path_start() { let path = self.parse_path(PathStyle::Expr)?; @@ -2797,6 +2682,12 @@ impl<'a> Parser<'a> { let msg = format!("expected expression, found {}", self.this_token_descr()); let mut err = self.fatal(&msg); + let sp = self.sess.source_map().start_point(self.span); + if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow() + .get(&sp) + { + self.sess.expr_parentheses_needed(&mut err, *sp, None); + } err.span_label(self.span, "expected expression"); return Err(err); } @@ -2836,7 +2727,7 @@ impl<'a> Parser<'a> { "struct literals are not allowed here", ); err.multipart_suggestion( - "surround the struct literal with parenthesis", + "surround the struct literal with parentheses", vec![ (lo.shrink_to_lo(), "(".to_string()), (expr.span.shrink_to_hi(), ")".to_string()), @@ -3014,6 +2905,15 @@ impl<'a> Parser<'a> { // Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P, lo: Span) -> PResult<'a, P> { + if self.span.rust_2018() && self.eat_keyword(keywords::Await) { + let span = lo.to(self.prev_span); + let await_expr = self.mk_expr( + span, + ExprKind::Await(ast::AwaitOrigin::FieldLike, self_arg), + ThinVec::new(), + ); + return Ok(await_expr); + } let segment = self.parse_path_segment(PathStyle::Expr)?; self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren)); @@ -3488,9 +3388,42 @@ impl<'a> Parser<'a> { } }; - if self.expr_is_complete(&lhs) { - // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 - return Ok(lhs); + match (self.expr_is_complete(&lhs), AssocOp::from_token(&self.token)) { + (true, None) => { + // Semi-statement forms are odd. See https://github.com/rust-lang/rust/issues/29071 + return Ok(lhs); + } + (false, _) => {} // continue parsing the expression + // An exhaustive check is done in the following block, but these are checked first + // because they *are* ambiguous but also reasonable looking incorrect syntax, so we + // want to keep their span info to improve diagnostics in these cases in a later stage. + (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` + (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` + (true, Some(AssocOp::Add)) => { // `{ 42 } + 42 + // These cases are ambiguous and can't be identified in the parser alone + let sp = self.sess.source_map().start_point(self.span); + self.sess.ambiguous_block_expr_parse.borrow_mut().insert(sp, lhs.span); + return Ok(lhs); + } + (true, Some(ref op)) if !op.can_continue_expr_unambiguously() => { + return Ok(lhs); + } + (true, Some(_)) => { + // We've found an expression that would be parsed as a statement, but the next + // token implies this should be parsed as an expression. + // For example: `if let Some(x) = x { x } else { 0 } / 2` + let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &format!( + "expected expression, found `{}`", + pprust::token_to_string(&self.token), + )); + err.span_label(self.span, "expected expression"); + self.sess.expr_parentheses_needed( + &mut err, + lhs.span, + Some(pprust::expr_to_string(&lhs), + )); + err.emit(); + } } self.expected_tokens.push(TokenType::Operator); while let Some(op) = AssocOp::from_token(&self.token) { @@ -3512,7 +3445,8 @@ impl<'a> Parser<'a> { } else { self.restrictions }; - if op.precedence() < min_prec { + let prec = op.precedence(); + if prec < min_prec { break; } // Check for deprecated `...` syntax @@ -3553,8 +3487,7 @@ impl<'a> Parser<'a> { // We have 2 alternatives here: `x..y`/`x..=y` and `x..`/`x..=` The other // two variants are handled with `parse_prefix_range_expr` call above. let rhs = if self.is_at_start_of_range_notation_rhs() { - Some(self.parse_assoc_expr_with(op.precedence() + 1, - LhsExpr::NotYetParsed)?) + Some(self.parse_assoc_expr_with(prec + 1, LhsExpr::NotYetParsed)?) } else { None }; @@ -3574,28 +3507,18 @@ impl<'a> Parser<'a> { break } - let rhs = match op.fixity() { - Fixity::Right => self.with_res( - restrictions - Restrictions::STMT_EXPR, - |this| { - this.parse_assoc_expr_with(op.precedence(), - LhsExpr::NotYetParsed) - }), - Fixity::Left => self.with_res( - restrictions - Restrictions::STMT_EXPR, - |this| { - this.parse_assoc_expr_with(op.precedence() + 1, - LhsExpr::NotYetParsed) - }), + let fixity = op.fixity(); + let prec_adjustment = match fixity { + Fixity::Right => 0, + Fixity::Left => 1, // We currently have no non-associative operators that are not handled above by // the special cases. The code is here only for future convenience. - Fixity::None => self.with_res( - restrictions - Restrictions::STMT_EXPR, - |this| { - this.parse_assoc_expr_with(op.precedence() + 1, - LhsExpr::NotYetParsed) - }), - }?; + Fixity::None => 1, + }; + let rhs = self.with_res( + restrictions - Restrictions::STMT_EXPR, + |this| this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed) + )?; // Make sure that the span of the parent node is larger than the span of lhs and rhs, // including the attributes. @@ -3641,7 +3564,7 @@ impl<'a> Parser<'a> { } }; - if op.fixity() == Fixity::None { break } + if let Fixity::None = fixity { break } } Ok(lhs) } @@ -3778,7 +3701,7 @@ impl<'a> Parser<'a> { /// Produce an error if comparison operators are chained (RFC #558). /// We only need to check lhs, not rhs, because all comparison ops /// have same precedence and are left-associative - fn check_no_chained_comparison(&mut self, lhs: &Expr, outer_op: &AssocOp) { + fn check_no_chained_comparison(&self, lhs: &Expr, outer_op: &AssocOp) { debug_assert!(outer_op.is_comparison(), "check_no_chained_comparison: {:?} is not comparison", outer_op); @@ -4117,8 +4040,6 @@ impl<'a> Parser<'a> { } crate fn parse_arm(&mut self) -> PResult<'a, Arm> { - maybe_whole!(self, NtArm, |x| x); - let attrs = self.parse_outer_attributes()?; let pats = self.parse_pats()?; let guard = if self.eat_keyword(keywords::If) { @@ -4801,6 +4722,10 @@ impl<'a> Parser<'a> { ); let mut err = self.fatal(&msg); err.span_label(self.span, format!("expected {}", expected)); + let sp = self.sess.source_map().start_point(self.span); + if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) { + self.sess.expr_parentheses_needed(&mut err, *sp, None); + } return Err(err); } } @@ -5071,7 +4996,7 @@ impl<'a> Parser<'a> { }) } - fn is_async_block(&mut self) -> bool { + fn is_async_block(&self) -> bool { self.token.is_keyword(keywords::Async) && ( ( // `async move {` @@ -5083,19 +5008,19 @@ impl<'a> Parser<'a> { ) } - fn is_async_fn(&mut self) -> bool { + fn is_async_fn(&self) -> bool { self.token.is_keyword(keywords::Async) && self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) } - fn is_do_catch_block(&mut self) -> bool { + fn is_do_catch_block(&self) -> bool { self.token.is_keyword(keywords::Do) && self.look_ahead(1, |t| t.is_keyword(keywords::Catch)) && self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) && !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL) } - fn is_try_block(&mut self) -> bool { + fn is_try_block(&self) -> bool { self.token.is_keyword(keywords::Try) && self.look_ahead(1, |t| *t == token::OpenDelim(token::Brace)) && self.span.rust_2018() && @@ -5117,7 +5042,7 @@ impl<'a> Parser<'a> { self.look_ahead(1, |t| t.is_keyword(keywords::Type)) } - fn is_auto_trait_item(&mut self) -> bool { + fn is_auto_trait_item(&self) -> bool { // auto trait (self.token.is_keyword(keywords::Auto) && self.look_ahead(1, |t| t.is_keyword(keywords::Trait))) @@ -5159,7 +5084,7 @@ impl<'a> Parser<'a> { (ident, ast::MacroDef { tokens: tokens.into(), legacy: false }) } - token::Ident(ident, _) if ident.name == "macro_rules" && + token::Ident(ident, _) if ident.name == sym::macro_rules && self.look_ahead(1, |t| *t == token::Not) => { let prev_span = self.prev_span; self.complain_if_pub_macro(&vis.node, prev_span); @@ -5379,7 +5304,7 @@ impl<'a> Parser<'a> { } /// Checks if this expression is a successfully parsed statement. - fn expr_is_complete(&mut self, e: &Expr) -> bool { + fn expr_is_complete(&self, e: &Expr) -> bool { self.restrictions.contains(Restrictions::STMT_EXPR) && !classify::expr_requires_semi_to_be_stmt(e) } @@ -5849,8 +5774,6 @@ impl<'a> Parser<'a> { /// | ( < lifetimes , typaramseq ( , )? > ) /// where typaramseq = ( typaram ) | ( typaram , typaramseq ) fn parse_generics(&mut self) -> PResult<'a, ast::Generics> { - maybe_whole!(self, NtGenerics, |x| x); - let span_lo = self.span; if self.eat_lt() { let params = self.parse_generic_params()?; @@ -6045,10 +5968,6 @@ impl<'a> Parser<'a> { }); assoc_ty_bindings.push(span); } else if self.check_const_arg() { - // FIXME(const_generics): to distinguish between idents for types and consts, - // we should introduce a GenericArg::Ident in the AST and distinguish when - // lowering to the HIR. For now, idents for const args are not permitted. - // Parse const argument. let expr = if let token::OpenDelim(token::Brace) = self.token { self.parse_block_expr(None, self.span, BlockCheckMode::Default, ThinVec::new())? @@ -6060,8 +5979,6 @@ impl<'a> Parser<'a> { self.fatal("identifiers may currently not be used for const generics") ); } else { - // FIXME(const_generics): this currently conflicts with emplacement syntax - // with negative integer literals. self.parse_literal_maybe_minus()? }; let value = AnonConst { @@ -6109,8 +6026,6 @@ impl<'a> Parser<'a> { /// where T : Trait + 'b, 'a : 'b /// ``` fn parse_where_clause(&mut self) -> PResult<'a, WhereClause> { - maybe_whole!(self, NtWhereClause, |x| x); - let mut where_clause = WhereClause { id: ast::DUMMY_NODE_ID, predicates: Vec::new(), @@ -6457,7 +6372,7 @@ impl<'a> Parser<'a> { Ok((id, generics)) } - fn mk_item(&mut self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, + fn mk_item(&self, span: Span, ident: Ident, node: ItemKind, vis: Visibility, attrs: Vec) -> P { P(Item { ident, @@ -6479,17 +6394,17 @@ impl<'a> Parser<'a> { -> PResult<'a, ItemInfo> { let (ident, mut generics) = self.parse_fn_header()?; let allow_c_variadic = abi == Abi::C && unsafety == Unsafety::Unsafe; - let decl = self.parse_fn_decl(allow_c_variadic)?; + let mut decl = self.parse_fn_decl(allow_c_variadic)?; generics.where_clause = self.parse_where_clause()?; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; - self.construct_async_arguments(&mut asyncness, &decl); + self.construct_async_arguments(&mut asyncness, &mut decl); let header = FnHeader { unsafety, asyncness, constness, abi }; Ok((ident, ItemKind::Fn(decl, header, generics, body), Some(inner_attrs))) } /// Returns `true` if we are looking at `const ID` /// (returns `false` for things like `const fn`, etc.). - fn is_const_item(&mut self) -> bool { + fn is_const_item(&self) -> bool { self.token.is_keyword(keywords::Const) && !self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) && !self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe)) @@ -6597,7 +6512,7 @@ impl<'a> Parser<'a> { }) } - fn complain_if_pub_macro(&mut self, vis: &VisibilityKind, sp: Span) { + fn complain_if_pub_macro(&self, vis: &VisibilityKind, sp: Span) { match *vis { VisibilityKind::Inherited => {} _ => { @@ -6626,7 +6541,7 @@ impl<'a> Parser<'a> { } } - fn missing_assoc_item_kind_err(&mut self, item_type: &str, prev_span: Span) + fn missing_assoc_item_kind_err(&self, item_type: &str, prev_span: Span) -> DiagnosticBuilder<'a> { let expected_kinds = if item_type == "extern" { @@ -6666,9 +6581,9 @@ impl<'a> Parser<'a> { let (constness, unsafety, mut asyncness, abi) = self.parse_fn_front_matter()?; let ident = self.parse_ident()?; let mut generics = self.parse_generics()?; - let decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; + let mut decl = self.parse_fn_decl_with_self(|p| p.parse_arg())?; generics.where_clause = self.parse_where_clause()?; - self.construct_async_arguments(&mut asyncness, &decl); + self.construct_async_arguments(&mut asyncness, &mut decl); *at_end = true; let (inner_attrs, body) = self.parse_inner_attrs_and_block()?; let header = ast::FnHeader { abi, unsafety, constness, asyncness }; @@ -7329,7 +7244,7 @@ impl<'a> Parser<'a> { } fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) { - if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") { + if let Some(path) = attr::first_attr_value_str_by_name(attrs, sym::path) { self.directory.path.to_mut().push(&path.as_str()); self.directory.ownership = DirectoryOwnership::Owned { relative: None }; } else { @@ -7349,7 +7264,7 @@ impl<'a> Parser<'a> { } pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option { - if let Some(s) = attr::first_attr_value_str_by_name(attrs, "path") { + if let Some(s) = attr::first_attr_value_str_by_name(attrs, sym::path) { let s = s.as_str(); // On windows, the base path might have the form @@ -8714,9 +8629,13 @@ impl<'a> Parser<'a> { /// /// The arguments of the function are replaced in HIR lowering with the arguments created by /// this function and the statements created here are inserted at the top of the closure body. - fn construct_async_arguments(&mut self, asyncness: &mut Spanned, decl: &FnDecl) { + fn construct_async_arguments(&mut self, asyncness: &mut Spanned, decl: &mut FnDecl) { + // FIXME(davidtwco): This function should really live in the HIR lowering but because + // the types constructed here need to be used in parts of resolve so that the correct + // locals are considered upvars, it is currently easier for it to live here in the parser, + // where it can be constructed once. if let IsAsync::Async { ref mut arguments, .. } = asyncness.node { - for (index, input) in decl.inputs.iter().enumerate() { + for (index, input) in decl.inputs.iter_mut().enumerate() { let id = ast::DUMMY_NODE_ID; let span = input.pat.span; @@ -8728,8 +8647,19 @@ impl<'a> Parser<'a> { // `let = __argN;` statement, instead just adding a `let = ;` // statement. let (binding_mode, ident, is_simple_pattern) = match input.pat.node { - PatKind::Ident(binding_mode, ident, _) => (binding_mode, ident, true), - _ => (BindingMode::ByValue(Mutability::Immutable), ident, false), + PatKind::Ident(binding_mode @ BindingMode::ByValue(_), ident, _) => { + // Simple patterns like this don't have a generated argument, but they are + // moved into the closure with a statement, so any `mut` bindings on the + // argument will be unused. This binding mode can't be removed, because + // this would affect the input to procedural macros, but they can have + // their span marked as being the result of a compiler desugaring so + // that they aren't linted against. + input.pat.span = self.sess.source_map().mark_span_with_reason( + CompilerDesugaringKind::Async, span, None); + + (binding_mode, ident, true) + } + _ => (BindingMode::ByValue(Mutability::Mutable), ident, false), }; // Construct an argument representing `__argN: ` to replace the argument of the diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 2fa4f5263fbc5..049fb6cb78b84 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -61,6 +61,7 @@ impl DelimToken { #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum Lit { + Bool(ast::Name), // AST only, must never appear in a `Token` Byte(ast::Name), Char(ast::Name), Err(ast::Name), @@ -72,9 +73,13 @@ pub enum Lit { ByteStrRaw(ast::Name, u16), /* raw byte str delimited by n hash symbols */ } +#[cfg(target_arch = "x86_64")] +static_assert!(MEM_SIZE_OF_LIT: mem::size_of::() == 8); + impl Lit { crate fn literal_name(&self) -> &'static str { match *self { + Bool(_) => panic!("literal token contains `Lit::Bool`"), Byte(_) => "byte literal", Char(_) => "char literal", Err(_) => "invalid literal", @@ -85,6 +90,13 @@ impl Lit { } } + crate fn may_have_suffix(&self) -> bool { + match *self { + Integer(..) | Float(..) => true, + _ => false, + } + } + // See comments in `Nonterminal::to_tokenstream` for why we care about // *probably* equal here rather than actual equality fn probably_equal_for_proc_macro(&self, other: &Lit) -> bool { @@ -99,6 +111,11 @@ pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool { ident_token.is_path_segment_keyword() || [ keywords::Async.name(), + + // FIXME: remove when `await!(..)` syntax is removed + // https://github.com/rust-lang/rust/issues/60610 + keywords::Await.name(), + keywords::Do.name(), keywords::Box.name(), keywords::Break.name(), @@ -580,14 +597,12 @@ pub enum Nonterminal { NtPath(ast::Path), NtVis(ast::Visibility), NtTT(TokenTree), - // These are not exposed to macros, but are used by quasiquote. - NtArm(ast::Arm), - NtImplItem(ast::ImplItem), + // Used only for passing items to proc macro attributes (they are not + // strictly necessary for that, `Annotatable` can be converted into + // tokens directly, but doing that naively regresses pretty-printing). NtTraitItem(ast::TraitItem), + NtImplItem(ast::ImplItem), NtForeignItem(ast::ForeignItem), - NtGenerics(ast::Generics), - NtWhereClause(ast::WhereClause), - NtArg(ast::Arg), } impl PartialEq for Nonterminal { @@ -620,13 +635,9 @@ impl fmt::Debug for Nonterminal { NtMeta(..) => f.pad("NtMeta(..)"), NtPath(..) => f.pad("NtPath(..)"), NtTT(..) => f.pad("NtTT(..)"), - NtArm(..) => f.pad("NtArm(..)"), NtImplItem(..) => f.pad("NtImplItem(..)"), NtTraitItem(..) => f.pad("NtTraitItem(..)"), NtForeignItem(..) => f.pad("NtForeignItem(..)"), - NtGenerics(..) => f.pad("NtGenerics(..)"), - NtWhereClause(..) => f.pad("NtWhereClause(..)"), - NtArg(..) => f.pad("NtArg(..)"), NtVis(..) => f.pad("NtVis(..)"), NtLifetime(..) => f.pad("NtLifetime(..)"), } diff --git a/src/libsyntax/parse/unescape.rs b/src/libsyntax/parse/unescape.rs new file mode 100644 index 0000000000000..90ee549db017b --- /dev/null +++ b/src/libsyntax/parse/unescape.rs @@ -0,0 +1,515 @@ +//! Utilities for validating string and char literals and turning them into +//! values they represent. + +use std::str::Chars; +use std::ops::Range; + +#[derive(Debug, PartialEq, Eq)] +pub(crate) enum EscapeError { + ZeroChars, + MoreThanOneChar, + + LoneSlash, + InvalidEscape, + BareCarriageReturn, + EscapeOnlyChar, + + TooShortHexEscape, + InvalidCharInHexEscape, + OutOfRangeHexEscape, + + NoBraceInUnicodeEscape, + InvalidCharInUnicodeEscape, + EmptyUnicodeEscape, + UnclosedUnicodeEscape, + LeadingUnderscoreUnicodeEscape, + OverlongUnicodeEscape, + LoneSurrogateUnicodeEscape, + OutOfRangeUnicodeEscape, + + UnicodeEscapeInByte, + NonAsciiCharInByte, +} + +/// Takes a contents of a char literal (without quotes), and returns an +/// unescaped char or an error +pub(crate) fn unescape_char(literal_text: &str) -> Result { + let mut chars = literal_text.chars(); + unescape_char_or_byte(&mut chars, Mode::Char) + .map_err(|err| (literal_text.len() - chars.as_str().len(), err)) +} + +/// Takes a contents of a string literal (without quotes) and produces a +/// sequence of escaped characters or errors. +pub(crate) fn unescape_str(literal_text: &str, callback: &mut F) +where + F: FnMut(Range, Result), +{ + unescape_str_or_byte_str(literal_text, Mode::Str, callback) +} + +pub(crate) fn unescape_byte(literal_text: &str) -> Result { + let mut chars = literal_text.chars(); + unescape_char_or_byte(&mut chars, Mode::Byte) + .map(byte_from_char) + .map_err(|err| (literal_text.len() - chars.as_str().len(), err)) +} + +/// Takes a contents of a string literal (without quotes) and produces a +/// sequence of escaped characters or errors. +pub(crate) fn unescape_byte_str(literal_text: &str, callback: &mut F) +where + F: FnMut(Range, Result), +{ + unescape_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| { + callback(range, char.map(byte_from_char)) + }) +} + +#[derive(Debug, Clone, Copy)] +pub(crate) enum Mode { + Char, + Str, + Byte, + ByteStr, +} + +impl Mode { + fn in_single_quotes(self) -> bool { + match self { + Mode::Char | Mode::Byte => true, + Mode::Str | Mode::ByteStr => false, + } + } + + pub(crate) fn in_double_quotes(self) -> bool { + !self.in_single_quotes() + } + + pub(crate) fn is_bytes(self) -> bool { + match self { + Mode::Byte | Mode::ByteStr => true, + Mode::Char | Mode::Str => false, + } + } +} + + +fn scan_escape(first_char: char, chars: &mut Chars<'_>, mode: Mode) -> Result { + if first_char != '\\' { + return match first_char { + '\t' | '\n' => Err(EscapeError::EscapeOnlyChar), + '\r' => Err(if chars.clone().next() == Some('\n') { + EscapeError::EscapeOnlyChar + } else { + EscapeError::BareCarriageReturn + }), + '\'' if mode.in_single_quotes() => Err(EscapeError::EscapeOnlyChar), + '"' if mode.in_double_quotes() => Err(EscapeError::EscapeOnlyChar), + _ => { + if mode.is_bytes() && !first_char.is_ascii() { + return Err(EscapeError::NonAsciiCharInByte); + } + Ok(first_char) + } + }; + } + + let second_char = chars.next().ok_or(EscapeError::LoneSlash)?; + + let res = match second_char { + '"' => '"', + 'n' => '\n', + 'r' => '\r', + 't' => '\t', + '\\' => '\\', + '\'' => '\'', + '0' => '\0', + + 'x' => { + let hi = chars.next().ok_or(EscapeError::TooShortHexEscape)?; + let hi = hi.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?; + + let lo = chars.next().ok_or(EscapeError::TooShortHexEscape)?; + let lo = lo.to_digit(16).ok_or(EscapeError::InvalidCharInHexEscape)?; + + let value = hi * 16 + lo; + + if !mode.is_bytes() && !is_ascii(value) { + return Err(EscapeError::OutOfRangeHexEscape); + } + let value = value as u8; + + value as char + } + + 'u' => { + if chars.next() != Some('{') { + return Err(EscapeError::NoBraceInUnicodeEscape); + } + + let mut n_digits = 1; + let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? { + '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape), + '}' => return Err(EscapeError::EmptyUnicodeEscape), + c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?, + }; + + loop { + match chars.next() { + None => return Err(EscapeError::UnclosedUnicodeEscape), + Some('_') => continue, + Some('}') => { + if n_digits > 6 { + return Err(EscapeError::OverlongUnicodeEscape); + } + if mode.is_bytes() { + return Err(EscapeError::UnicodeEscapeInByte); + } + + break std::char::from_u32(value).ok_or_else(|| { + if value > 0x10FFFF { + EscapeError::OutOfRangeUnicodeEscape + } else { + EscapeError::LoneSurrogateUnicodeEscape + } + })?; + } + Some(c) => { + let digit = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?; + n_digits += 1; + if n_digits > 6 { + continue; + } + let digit = digit as u32; + value = value * 16 + digit; + } + }; + } + } + _ => return Err(EscapeError::InvalidEscape), + }; + Ok(res) +} + +fn unescape_char_or_byte(chars: &mut Chars<'_>, mode: Mode) -> Result { + let first_char = chars.next().ok_or(EscapeError::ZeroChars)?; + let res = scan_escape(first_char, chars, mode)?; + if chars.next().is_some() { + return Err(EscapeError::MoreThanOneChar); + } + Ok(res) +} + +/// Takes a contents of a string literal (without quotes) and produces a +/// sequence of escaped characters or errors. +fn unescape_str_or_byte_str(src: &str, mode: Mode, callback: &mut F) +where + F: FnMut(Range, Result), +{ + assert!(mode.in_double_quotes()); + let initial_len = src.len(); + let mut chars = src.chars(); + while let Some(first_char) = chars.next() { + let start = initial_len - chars.as_str().len() - first_char.len_utf8(); + + let unescaped_char = match first_char { + '\\' => { + let (second_char, third_char) = { + let mut chars = chars.clone(); + (chars.next(), chars.next()) + }; + match (second_char, third_char) { + (Some('\n'), _) | (Some('\r'), Some('\n')) => { + skip_ascii_whitespace(&mut chars); + continue; + } + _ => scan_escape(first_char, &mut chars, mode), + } + } + '\r' => { + let second_char = chars.clone().next(); + if second_char == Some('\n') { + chars.next(); + Ok('\n') + } else { + scan_escape(first_char, &mut chars, mode) + } + } + '\n' => Ok('\n'), + '\t' => Ok('\t'), + _ => scan_escape(first_char, &mut chars, mode), + }; + let end = initial_len - chars.as_str().len(); + callback(start..end, unescaped_char); + } + + fn skip_ascii_whitespace(chars: &mut Chars<'_>) { + let str = chars.as_str(); + let first_non_space = str + .bytes() + .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r') + .unwrap_or(str.len()); + *chars = str[first_non_space..].chars() + } +} + +fn byte_from_char(c: char) -> u8 { + let res = c as u32; + assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::Byte"); + res as u8 +} + +fn is_ascii(x: u32) -> bool { + x <= 0x7F +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_unescape_char_bad() { + fn check(literal_text: &str, expected_error: EscapeError) { + let actual_result = unescape_char(literal_text).map_err(|(_offset, err)| err); + assert_eq!(actual_result, Err(expected_error)); + } + + check("", EscapeError::ZeroChars); + check(r"\", EscapeError::LoneSlash); + + check("\n", EscapeError::EscapeOnlyChar); + check("\r\n", EscapeError::EscapeOnlyChar); + check("\t", EscapeError::EscapeOnlyChar); + check("'", EscapeError::EscapeOnlyChar); + check("\r", EscapeError::BareCarriageReturn); + + check("spam", EscapeError::MoreThanOneChar); + check(r"\x0ff", EscapeError::MoreThanOneChar); + check(r#"\"a"#, EscapeError::MoreThanOneChar); + check(r"\na", EscapeError::MoreThanOneChar); + check(r"\ra", EscapeError::MoreThanOneChar); + check(r"\ta", EscapeError::MoreThanOneChar); + check(r"\\a", EscapeError::MoreThanOneChar); + check(r"\'a", EscapeError::MoreThanOneChar); + check(r"\0a", EscapeError::MoreThanOneChar); + check(r"\u{0}x", EscapeError::MoreThanOneChar); + check(r"\u{1F63b}}", EscapeError::MoreThanOneChar); + + check(r"\v", EscapeError::InvalidEscape); + check(r"\💩", EscapeError::InvalidEscape); + check(r"\●", EscapeError::InvalidEscape); + + check(r"\x", EscapeError::TooShortHexEscape); + check(r"\x0", EscapeError::TooShortHexEscape); + check(r"\xf", EscapeError::TooShortHexEscape); + check(r"\xa", EscapeError::TooShortHexEscape); + check(r"\xx", EscapeError::InvalidCharInHexEscape); + check(r"\xы", EscapeError::InvalidCharInHexEscape); + check(r"\x🦀", EscapeError::InvalidCharInHexEscape); + check(r"\xtt", EscapeError::InvalidCharInHexEscape); + check(r"\xff", EscapeError::OutOfRangeHexEscape); + check(r"\xFF", EscapeError::OutOfRangeHexEscape); + check(r"\x80", EscapeError::OutOfRangeHexEscape); + + check(r"\u", EscapeError::NoBraceInUnicodeEscape); + check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape); + check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape); + check(r"\u{", EscapeError::UnclosedUnicodeEscape); + check(r"\u{0000", EscapeError::UnclosedUnicodeEscape); + check(r"\u{}", EscapeError::EmptyUnicodeEscape); + check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape); + check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape); + check(r"\u{FFFFFF}", EscapeError::OutOfRangeUnicodeEscape); + check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape); + check(r"\u{ffffff}", EscapeError::OutOfRangeUnicodeEscape); + + check(r"\u{DC00}", EscapeError::LoneSurrogateUnicodeEscape); + check(r"\u{DDDD}", EscapeError::LoneSurrogateUnicodeEscape); + check(r"\u{DFFF}", EscapeError::LoneSurrogateUnicodeEscape); + + check(r"\u{D800}", EscapeError::LoneSurrogateUnicodeEscape); + check(r"\u{DAAA}", EscapeError::LoneSurrogateUnicodeEscape); + check(r"\u{DBFF}", EscapeError::LoneSurrogateUnicodeEscape); + } + + #[test] + fn test_unescape_char_good() { + fn check(literal_text: &str, expected_char: char) { + let actual_result = unescape_char(literal_text); + assert_eq!(actual_result, Ok(expected_char)); + } + + check("a", 'a'); + check("ы", 'ы'); + check("🦀", '🦀'); + + check(r#"\""#, '"'); + check(r"\n", '\n'); + check(r"\r", '\r'); + check(r"\t", '\t'); + check(r"\\", '\\'); + check(r"\'", '\''); + check(r"\0", '\0'); + + check(r"\x00", '\0'); + check(r"\x5a", 'Z'); + check(r"\x5A", 'Z'); + check(r"\x7f", 127 as char); + + check(r"\u{0}", '\0'); + check(r"\u{000000}", '\0'); + check(r"\u{41}", 'A'); + check(r"\u{0041}", 'A'); + check(r"\u{00_41}", 'A'); + check(r"\u{4__1__}", 'A'); + check(r"\u{1F63b}", '😻'); + } + + #[test] + fn test_unescape_str_good() { + fn check(literal_text: &str, expected: &str) { + let mut buf = Ok(String::with_capacity(literal_text.len())); + unescape_str(literal_text, &mut |range, c| { + if let Ok(b) = &mut buf { + match c { + Ok(c) => b.push(c), + Err(e) => buf = Err((range, e)), + } + } + }); + let buf = buf.as_ref().map(|it| it.as_ref()); + assert_eq!(buf, Ok(expected)) + } + + check("foo", "foo"); + check("", ""); + check(" \t\n\r\n", " \t\n\n"); + + check("hello \\\n world", "hello world"); + check("hello \\\r\n world", "hello world"); + check("thread's", "thread's") + } + + #[test] + fn test_unescape_byte_bad() { + fn check(literal_text: &str, expected_error: EscapeError) { + let actual_result = unescape_byte(literal_text).map_err(|(_offset, err)| err); + assert_eq!(actual_result, Err(expected_error)); + } + + check("", EscapeError::ZeroChars); + check(r"\", EscapeError::LoneSlash); + + check("\n", EscapeError::EscapeOnlyChar); + check("\r\n", EscapeError::EscapeOnlyChar); + check("\t", EscapeError::EscapeOnlyChar); + check("'", EscapeError::EscapeOnlyChar); + check("\r", EscapeError::BareCarriageReturn); + + check("spam", EscapeError::MoreThanOneChar); + check(r"\x0ff", EscapeError::MoreThanOneChar); + check(r#"\"a"#, EscapeError::MoreThanOneChar); + check(r"\na", EscapeError::MoreThanOneChar); + check(r"\ra", EscapeError::MoreThanOneChar); + check(r"\ta", EscapeError::MoreThanOneChar); + check(r"\\a", EscapeError::MoreThanOneChar); + check(r"\'a", EscapeError::MoreThanOneChar); + check(r"\0a", EscapeError::MoreThanOneChar); + + check(r"\v", EscapeError::InvalidEscape); + check(r"\💩", EscapeError::InvalidEscape); + check(r"\●", EscapeError::InvalidEscape); + + check(r"\x", EscapeError::TooShortHexEscape); + check(r"\x0", EscapeError::TooShortHexEscape); + check(r"\xa", EscapeError::TooShortHexEscape); + check(r"\xf", EscapeError::TooShortHexEscape); + check(r"\xx", EscapeError::InvalidCharInHexEscape); + check(r"\xы", EscapeError::InvalidCharInHexEscape); + check(r"\x🦀", EscapeError::InvalidCharInHexEscape); + check(r"\xtt", EscapeError::InvalidCharInHexEscape); + + check(r"\u", EscapeError::NoBraceInUnicodeEscape); + check(r"\u[0123]", EscapeError::NoBraceInUnicodeEscape); + check(r"\u{0x}", EscapeError::InvalidCharInUnicodeEscape); + check(r"\u{", EscapeError::UnclosedUnicodeEscape); + check(r"\u{0000", EscapeError::UnclosedUnicodeEscape); + check(r"\u{}", EscapeError::EmptyUnicodeEscape); + check(r"\u{_0000}", EscapeError::LeadingUnderscoreUnicodeEscape); + check(r"\u{0000000}", EscapeError::OverlongUnicodeEscape); + + check("ы", EscapeError::NonAsciiCharInByte); + check("🦀", EscapeError::NonAsciiCharInByte); + + check(r"\u{0}", EscapeError::UnicodeEscapeInByte); + check(r"\u{000000}", EscapeError::UnicodeEscapeInByte); + check(r"\u{41}", EscapeError::UnicodeEscapeInByte); + check(r"\u{0041}", EscapeError::UnicodeEscapeInByte); + check(r"\u{00_41}", EscapeError::UnicodeEscapeInByte); + check(r"\u{4__1__}", EscapeError::UnicodeEscapeInByte); + check(r"\u{1F63b}", EscapeError::UnicodeEscapeInByte); + check(r"\u{0}x", EscapeError::UnicodeEscapeInByte); + check(r"\u{1F63b}}", EscapeError::UnicodeEscapeInByte); + check(r"\u{FFFFFF}", EscapeError::UnicodeEscapeInByte); + check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte); + check(r"\u{ffffff}", EscapeError::UnicodeEscapeInByte); + check(r"\u{DC00}", EscapeError::UnicodeEscapeInByte); + check(r"\u{DDDD}", EscapeError::UnicodeEscapeInByte); + check(r"\u{DFFF}", EscapeError::UnicodeEscapeInByte); + check(r"\u{D800}", EscapeError::UnicodeEscapeInByte); + check(r"\u{DAAA}", EscapeError::UnicodeEscapeInByte); + check(r"\u{DBFF}", EscapeError::UnicodeEscapeInByte); + } + + #[test] + fn test_unescape_byte_good() { + fn check(literal_text: &str, expected_byte: u8) { + let actual_result = unescape_byte(literal_text); + assert_eq!(actual_result, Ok(expected_byte)); + } + + check("a", b'a'); + + check(r#"\""#, b'"'); + check(r"\n", b'\n'); + check(r"\r", b'\r'); + check(r"\t", b'\t'); + check(r"\\", b'\\'); + check(r"\'", b'\''); + check(r"\0", b'\0'); + + check(r"\x00", b'\0'); + check(r"\x5a", b'Z'); + check(r"\x5A", b'Z'); + check(r"\x7f", 127); + check(r"\x80", 128); + check(r"\xff", 255); + check(r"\xFF", 255); + } + + #[test] + fn test_unescape_byte_str_good() { + fn check(literal_text: &str, expected: &[u8]) { + let mut buf = Ok(Vec::with_capacity(literal_text.len())); + unescape_byte_str(literal_text, &mut |range, c| { + if let Ok(b) = &mut buf { + match c { + Ok(c) => b.push(c), + Err(e) => buf = Err((range, e)), + } + } + }); + let buf = buf.as_ref().map(|it| it.as_ref()); + assert_eq!(buf, Ok(expected)) + } + + check("foo", b"foo"); + check("", b""); + check(" \t\n\r\n", b" \t\n\n"); + + check("hello \\\n world", b"hello world"); + check("hello \\\r\n world", b"hello world"); + check("thread's", b"thread's") + } +} diff --git a/src/libsyntax/parse/unescape_error_reporting.rs b/src/libsyntax/parse/unescape_error_reporting.rs new file mode 100644 index 0000000000000..22777c0884f47 --- /dev/null +++ b/src/libsyntax/parse/unescape_error_reporting.rs @@ -0,0 +1,200 @@ +//! Utilities for rendering escape sequence errors as diagnostics. + +use std::ops::Range; +use std::iter::once; + +use syntax_pos::{Span, BytePos}; + +use crate::errors::{Handler, Applicability}; + +use super::unescape::{EscapeError, Mode}; + +pub(crate) fn emit_unescape_error( + handler: &Handler, + // interior part of the literal, without quotes + lit: &str, + // full span of the literal, including quotes + span_with_quotes: Span, + mode: Mode, + // range of the error inside `lit` + range: Range, + error: EscapeError, +) { + log::debug!("emit_unescape_error: {:?}, {:?}, {:?}, {:?}, {:?}", + lit, span_with_quotes, mode, range, error); + let span = { + let Range { start, end } = range; + let (start, end) = (start as u32, end as u32); + let lo = span_with_quotes.lo() + BytePos(start + 1); + let hi = lo + BytePos(end - start); + span_with_quotes + .with_lo(lo) + .with_hi(hi) + }; + let last_char = || { + let c = lit[range.clone()].chars().rev().next().unwrap(); + let span = span.with_lo(span.hi() - BytePos(c.len_utf8() as u32)); + (c, span) + }; + match error { + EscapeError::LoneSurrogateUnicodeEscape => { + handler.struct_span_err(span, "invalid unicode character escape") + .help("unicode escape must not be a surrogate") + .emit(); + } + EscapeError::OutOfRangeUnicodeEscape => { + handler.struct_span_err(span, "invalid unicode character escape") + .help("unicode escape must be at most 10FFFF") + .emit(); + } + EscapeError::MoreThanOneChar => { + handler + .struct_span_err( + span_with_quotes, + "character literal may only contain one codepoint", + ) + .span_suggestion( + span_with_quotes, + "if you meant to write a `str` literal, use double quotes", + format!("\"{}\"", lit), + Applicability::MachineApplicable, + ).emit() + } + EscapeError::EscapeOnlyChar => { + let (c, _span) = last_char(); + + let mut msg = if mode.is_bytes() { + "byte constant must be escaped: " + } else { + "character constant must be escaped: " + }.to_string(); + push_escaped_char(&mut msg, c); + + handler.span_err(span, msg.as_str()) + } + EscapeError::BareCarriageReturn => { + let msg = if mode.in_double_quotes() { + "bare CR not allowed in string, use \\r instead" + } else { + "character constant must be escaped: \\r" + }; + handler.span_err(span, msg); + } + EscapeError::InvalidEscape => { + let (c, span) = last_char(); + + let label = if mode.is_bytes() { + "unknown byte escape" + } else { + "unknown character escape" + }; + let mut msg = label.to_string(); + msg.push_str(": "); + push_escaped_char(&mut msg, c); + + let mut diag = handler.struct_span_err(span, msg.as_str()); + diag.span_label(span, label); + if c == '{' || c == '}' && !mode.is_bytes() { + diag.help("if used in a formatting string, \ + curly braces are escaped with `{{` and `}}`"); + } else if c == '\r' { + diag.help("this is an isolated carriage return; \ + consider checking your editor and version control settings"); + } + diag.emit(); + } + EscapeError::TooShortHexEscape => { + handler.span_err(span, "numeric character escape is too short") + } + EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => { + let (c, span) = last_char(); + + let mut msg = if error == EscapeError::InvalidCharInHexEscape { + "invalid character in numeric character escape: " + } else { + "invalid character in unicode escape: " + }.to_string(); + push_escaped_char(&mut msg, c); + + handler.span_err(span, msg.as_str()) + } + EscapeError::NonAsciiCharInByte => { + assert!(mode.is_bytes()); + let (_c, span) = last_char(); + handler.span_err(span, "byte constant must be ASCII. \ + Use a \\xHH escape for a non-ASCII byte") + } + EscapeError::OutOfRangeHexEscape => { + handler.span_err(span, "this form of character escape may only be used \ + with characters in the range [\\x00-\\x7f]") + } + EscapeError::LeadingUnderscoreUnicodeEscape => { + let (_c, span) = last_char(); + handler.span_err(span, "invalid start of unicode escape") + } + EscapeError::OverlongUnicodeEscape => { + handler.span_err(span, "overlong unicode escape (must have at most 6 hex digits)") + } + EscapeError::UnclosedUnicodeEscape => { + handler.span_err(span, "unterminated unicode escape (needed a `}`)") + } + EscapeError::NoBraceInUnicodeEscape => { + let msg = "incorrect unicode escape sequence"; + let mut diag = handler.struct_span_err(span, msg); + + let mut suggestion = "\\u{".to_owned(); + let mut suggestion_len = 0; + let (c, char_span) = last_char(); + let chars = once(c).chain(lit[range.end..].chars()); + for c in chars.take(6).take_while(|c| c.is_digit(16)) { + suggestion.push(c); + suggestion_len += c.len_utf8(); + } + + if suggestion_len > 0 { + suggestion.push('}'); + let lo = char_span.lo(); + let hi = lo + BytePos(suggestion_len as u32); + diag.span_suggestion( + span.with_lo(lo).with_hi(hi), + "format of unicode escape sequences uses braces", + suggestion, + Applicability::MaybeIncorrect, + ); + } else { + diag.span_label(span, msg); + diag.help( + "format of unicode escape sequences is `\\u{...}`", + ); + } + + diag.emit(); + } + EscapeError::UnicodeEscapeInByte => { + handler.span_err(span, "unicode escape sequences cannot be used \ + as a byte or in a byte string") + } + EscapeError::EmptyUnicodeEscape => { + handler.span_err(span, "empty unicode escape (must have at least 1 hex digit)") + } + EscapeError::ZeroChars => { + handler.span_err(span, "empty character literal") + } + EscapeError::LoneSlash => { + panic!("lexer accepted unterminated literal with trailing slash") + } + } +} + +/// Pushes a character to a message string for error reporting +pub(crate) fn push_escaped_char(msg: &mut String, c: char) { + match c { + '\u{20}'..='\u{7e}' => { + // Don't escape \, ' or " for user-facing messages + msg.push(c); + } + _ => { + msg.extend(c.escape_default()); + } + } +} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6c0fdfaa776f9..86db7a673d471 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -20,10 +20,8 @@ use rustc_target::spec::abi::{self, Abi}; use syntax_pos::{self, BytePos}; use syntax_pos::{DUMMY_SP, FileName}; -use std::ascii; use std::borrow::Cow; use std::io::{self, Write, Read}; -use std::iter::Peekable; use std::vec; pub enum AnnNode<'a> { @@ -49,8 +47,7 @@ impl PpAnn for NoAnn {} pub struct State<'a> { pub s: pp::Printer<'a>, cm: Option<&'a SourceMap>, - comments: Option >, - literals: Peekable>, + comments: Option>, cur_cmnt: usize, boxes: Vec, ann: &'a (dyn PpAnn+'a), @@ -62,7 +59,6 @@ fn rust_printer<'a>(writer: Box, ann: &'a dyn PpAnn) -> State<'a> s: pp::mk_printer(writer, DEFAULT_COLUMNS), cm: None, comments: None, - literals: vec![].into_iter().peekable(), cur_cmnt: 0, boxes: Vec::new(), ann, @@ -75,8 +71,7 @@ pub const INDENT_UNIT: usize = 4; 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: &ast::Crate, @@ -118,36 +113,23 @@ impl<'a> State<'a> { out: Box, ann: &'a dyn PpAnn, is_expanded: bool) -> 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) }, - is_expanded - ) + let comments = comments::gather_comments(sess, filename, input); + State::new(cm, out, ann, Some(comments), is_expanded) } pub fn new(cm: &'a SourceMap, out: Box, ann: &'a dyn PpAnn, comments: Option>, - literals: Option>, is_expanded: bool) -> 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, - is_expanded: is_expanded + is_expanded, } } } @@ -180,6 +162,31 @@ fn binop_to_string(op: BinOpToken) -> &'static str { } } +pub fn literal_to_string(lit: token::Lit, suffix: Option) -> String { + let mut out = match lit { + token::Byte(b) => format!("b'{}'", b), + token::Char(c) => format!("'{}'", c), + token::Err(c) => format!("'{}'", c), + token::Bool(c) | + token::Float(c) | + token::Integer(c) => c.to_string(), + token::Str_(s) => format!("\"{}\"", s), + token::StrRaw(s, n) => format!("r{delim}\"{string}\"{delim}", + delim="#".repeat(n as usize), + string=s), + token::ByteStr(v) => format!("b\"{}\"", v), + token::ByteStrRaw(s, n) => format!("br{delim}\"{string}\"{delim}", + delim="#".repeat(n as usize), + string=s), + }; + + if let Some(suffix) = suffix { + out.push_str(&suffix.as_str()) + } + + out +} + pub fn token_to_string(tok: &Token) -> String { match *tok { token::Eq => "=".to_string(), @@ -223,29 +230,7 @@ pub fn token_to_string(tok: &Token) -> String { token::SingleQuote => "'".to_string(), /* Literals */ - token::Literal(lit, suf) => { - let mut out = match lit { - token::Byte(b) => format!("b'{}'", b), - token::Char(c) => format!("'{}'", c), - token::Err(c) => format!("'{}'", c), - token::Float(c) | - token::Integer(c) => c.to_string(), - token::Str_(s) => format!("\"{}\"", s), - token::StrRaw(s, n) => format!("r{delim}\"{string}\"{delim}", - delim="#".repeat(n as usize), - string=s), - token::ByteStr(v) => format!("b\"{}\"", v), - token::ByteStrRaw(s, n) => format!("br{delim}\"{string}\"{delim}", - delim="#".repeat(n as usize), - string=s), - }; - - if let Some(s) = suf { - out.push_str(&s.as_str()) - } - - out - } + token::Literal(lit, suf) => literal_to_string(lit, suf), /* Name components */ token::Ident(s, false) => s.to_string(), @@ -278,12 +263,8 @@ pub fn nonterminal_to_string(nt: &Nonterminal) -> String { token::NtLifetime(e) => ident_to_string(e), token::NtLiteral(ref e) => expr_to_string(e), token::NtTT(ref tree) => tt_to_string(tree.clone()), - token::NtArm(ref e) => arm_to_string(e), token::NtImplItem(ref e) => impl_item_to_string(e), token::NtTraitItem(ref e) => trait_item_to_string(e), - token::NtGenerics(ref e) => generic_params_to_string(&e.params), - token::NtWhereClause(ref e) => where_clause_to_string(e), - token::NtArg(ref e) => arg_to_string(e), token::NtVis(ref e) => vis_to_string(e), token::NtForeignItem(ref e) => foreign_item_to_string(e), } @@ -438,8 +419,6 @@ pub trait PrintState<'a> { fn boxes(&mut self) -> &mut Vec; fn comments(&mut self) -> &mut Option>; fn cur_cmnt(&mut self) -> &mut usize; - fn cur_lit(&mut self) -> Option<&comments::Literal>; - fn bump_lit(&mut self) -> Option; fn word_space>>(&mut self, w: S) -> io::Result<()> { self.writer().word(w)?; @@ -504,21 +483,6 @@ pub trait PrintState<'a> { self.end() } - fn next_lit(&mut self, pos: BytePos) -> Option { - while let Some(ltrl) = self.cur_lit().cloned() { - if ltrl.pos > pos { break; } - - // we don't need the value here since we're forced to clone cur_lit - // due to lack of NLL. - self.bump_lit(); - if ltrl.pos == pos { - return Some(ltrl); - } - } - - None - } - fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> { while let Some(ref cmnt) = self.next_comment() { if cmnt.pos < pos { @@ -606,60 +570,7 @@ pub trait PrintState<'a> { fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> { self.maybe_print_comment(lit.span.lo())?; - if let Some(ltrl) = self.next_lit(lit.span.lo()) { - return self.writer().word(ltrl.lit.clone()); - } - match lit.node { - ast::LitKind::Str(st, style) => self.print_string(&st.as_str(), style), - ast::LitKind::Err(st) => { - let st = st.as_str().escape_debug().to_string(); - let mut res = String::with_capacity(st.len() + 2); - res.push('\''); - res.push_str(&st); - res.push('\''); - self.writer().word(res) - } - ast::LitKind::Byte(byte) => { - let mut res = String::from("b'"); - res.extend(ascii::escape_default(byte).map(|c| c as char)); - res.push('\''); - self.writer().word(res) - } - ast::LitKind::Char(ch) => { - let mut res = String::from("'"); - res.extend(ch.escape_default()); - res.push('\''); - self.writer().word(res) - } - ast::LitKind::Int(i, t) => { - match t { - ast::LitIntType::Signed(st) => { - self.writer().word(st.val_to_string(i as i128)) - } - ast::LitIntType::Unsigned(ut) => { - self.writer().word(ut.val_to_string(i)) - } - ast::LitIntType::Unsuffixed => { - self.writer().word(i.to_string()) - } - } - } - ast::LitKind::Float(ref f, t) => { - self.writer().word(format!("{}{}", &f, t.ty_to_string())) - } - ast::LitKind::FloatUnsuffixed(ref f) => self.writer().word(f.as_str().to_string()), - ast::LitKind::Bool(val) => { - if val { self.writer().word("true") } else { self.writer().word("false") } - } - ast::LitKind::ByteStr(ref v) => { - let mut escaped: String = String::new(); - for &ch in v.iter() { - escaped.extend(ascii::escape_default(ch) - .map(|c| c as char)); - } - self.writer().word(format!("b\"{}\"", escaped)) - } - } + self.writer().word(literal_to_string(lit.token, lit.suffix)) } fn print_string(&mut self, st: &str, @@ -880,14 +791,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() - } } impl<'a> State<'a> { @@ -2250,6 +2153,18 @@ impl<'a> State<'a> { self.ibox(0)?; self.print_block_with_attrs(blk, attrs)?; } + ast::ExprKind::Await(origin, ref expr) => { + match origin { + ast::AwaitOrigin::MacroLike => { + self.s.word("await!")?; + self.print_expr_maybe_paren(expr, parser::PREC_FORCE_PAREN)?; + } + ast::AwaitOrigin::FieldLike => { + self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?; + self.s.word(".await")?; + } + } + } ast::ExprKind::Assign(ref lhs, ref rhs) => { let prec = AssocOp::Assign.precedence() as i8; self.print_expr_maybe_paren(lhs, prec + 1)?; diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index 08abbf5e8a4dc..215618bd09ca3 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -930,6 +930,27 @@ impl SourceMap { None } + + /// Reuses the span but adds information like the kind of the desugaring and features that are + /// allowed inside this span. + pub fn mark_span_with_reason( + &self, + reason: hygiene::CompilerDesugaringKind, + span: Span, + allow_internal_unstable: Option>, + ) -> Span { + let mark = Mark::fresh(Mark::root()); + mark.set_expn_info(ExpnInfo { + call_site: span, + def_site: Some(span), + format: CompilerDesugaring(reason), + allow_internal_unstable, + allow_internal_unsafe: false, + local_inner_macros: false, + edition: hygiene::default_edition(), + }); + span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) + } } impl SourceMapper for SourceMap { diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index b9758bd655c15..f08fdcc6fb53c 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -2,7 +2,7 @@ use crate::ast; use crate::attr; use crate::edition::Edition; use crate::ext::hygiene::{Mark, SyntaxContext}; -use crate::symbol::{Symbol, keywords}; +use crate::symbol::{Symbol, keywords, sym}; use crate::source_map::{ExpnInfo, MacroAttribute, dummy_spanned, hygiene, respan}; use crate::ptr::P; use crate::tokenstream::TokenStream; @@ -35,6 +35,9 @@ pub fn injected_crate_name() -> Option<&'static str> { } thread_local! { + // A `Symbol` might make more sense here, but it doesn't work, probably for + // reasons relating to the use of thread-local storage for the Symbol + // interner. static INJECTED_CRATE_NAME: Cell> = Cell::new(None); } @@ -46,10 +49,10 @@ pub fn maybe_inject_crates_ref( let rust_2018 = edition >= Edition::Edition2018; // the first name in this list is the crate name of the crate with the prelude - let names: &[&str] = if attr::contains_name(&krate.attrs, "no_core") { + let names: &[&str] = if attr::contains_name(&krate.attrs, sym::no_core) { return krate; - } else if attr::contains_name(&krate.attrs, "no_std") { - if attr::contains_name(&krate.attrs, "compiler_builtins") { + } else if attr::contains_name(&krate.attrs, sym::no_std) { + if attr::contains_name(&krate.attrs, sym::compiler_builtins) { &["core"] } else { &["core", "compiler_builtins"] diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 03d0eff266e75..21bc236d00e6b 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -29,7 +29,7 @@ use crate::parse::{token, ParseSess}; use crate::print::pprust; use crate::ast::{self, Ident}; use crate::ptr::P; -use crate::symbol::{self, Symbol, keywords}; +use crate::symbol::{self, Symbol, keywords, sym}; use crate::ThinVec; struct Test { @@ -65,8 +65,7 @@ pub fn modify_for_testing(sess: &ParseSess, // unconditional, so that the attribute is still marked as used in // non-test builds. let reexport_test_harness_main = - attr::first_attr_value_str_by_name(&krate.attrs, - "reexport_test_harness_main"); + attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main); // Do this here so that the test_runner crate attribute gets marked as used // even in non-test builds @@ -185,7 +184,7 @@ impl MutVisitor for EntryPointCleaner { ident, attrs: attrs.into_iter() .filter(|attr| { - !attr.check_name("main") && !attr.check_name("start") + !attr.check_name(sym::main) && !attr.check_name(sym::start) }) .chain(iter::once(allow_dead_code)) .collect(), @@ -273,7 +272,8 @@ fn generate_test_harness(sess: &ParseSess, test_cases: Vec::new(), reexport_test_harness_main, // N.B., doesn't consider the value of `--crate-name` passed on the command line. - is_libtest: attr::find_crate_name(&krate.attrs).map(|s| s == "test").unwrap_or(false), + is_libtest: attr::find_crate_name(&krate.attrs) + .map(|s| s == sym::test).unwrap_or(false), toplevel_reexport: None, ctxt: SyntaxContext::empty().apply_mark(mark), features, @@ -428,11 +428,11 @@ fn visible_path(cx: &TestCtxt<'_>, path: &[Ident]) -> Vec{ } fn is_test_case(i: &ast::Item) -> bool { - attr::contains_name(&i.attrs, "rustc_test_marker") + attr::contains_name(&i.attrs, sym::rustc_test_marker) } fn get_test_runner(sd: &errors::Handler, krate: &ast::Crate) -> Option { - let test_attr = attr::find_by_name(&krate.attrs, "test_runner")?; + let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?; test_attr.meta_item_list().map(|meta_list| { if meta_list.len() != 1 { sd.span_fatal(test_attr.span, diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 5f15ede7b0b6a..86e89945afe06 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -207,6 +207,31 @@ impl AssocOp { ObsoleteInPlace | Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None } } + + /// This operator could be used to follow a block unambiguously. + /// + /// This is used for error recovery at the moment, providing a suggestion to wrap blocks with + /// parentheses while having a high degree of confidence on the correctness of the suggestion. + pub fn can_continue_expr_unambiguously(&self) -> bool { + use AssocOp::*; + match self { + BitXor | // `{ 42 } ^ 3` + Assign | // `{ 42 } = { 42 }` + Divide | // `{ 42 } / 42` + Modulus | // `{ 42 } % 2` + ShiftRight | // `{ 42 } >> 2` + LessEqual | // `{ 42 } <= 3` + Greater | // `{ 42 } > 3` + GreaterEqual | // `{ 42 } >= 3` + AssignOp(_) | // `{ 42 } +=` + LAnd | // `{ 42 } &&foo` + As | // `{ 42 } as usize` + // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect + // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery. + Colon => true, // `{ 42 }: usize` + _ => false, + } + } } pub const PREC_RESET: i8 = -100; @@ -267,6 +292,7 @@ pub enum ExprPrecedence { TryBlock, Struct, Async, + Await, Err, } @@ -301,6 +327,7 @@ impl ExprPrecedence { ExprPrecedence::Unary => PREC_PREFIX, // Unary, postfix + ExprPrecedence::Await | ExprPrecedence::Call | ExprPrecedence::MethodCall | ExprPrecedence::Field | @@ -346,6 +373,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { // X { y: 1 } + X { y: 2 } contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs) } + ast::ExprKind::Await(_, ref x) | ast::ExprKind::Unary(_, ref x) | ast::ExprKind::Cast(ref x, _) | ast::ExprKind::Type(ref x, _) | diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index fc99d10b0b6c6..0503e5644dbc5 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -768,6 +768,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Async(_, _, ref body) => { visitor.visit_block(body); } + ExprKind::Await(_, ref expr) => visitor.visit_expr(expr), ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => { visitor.visit_expr(left_hand_expression); visitor.visit_expr(right_hand_expression); diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs index 8edd0e1ae3884..b8e89c3ecf876 100644 --- a/src/libsyntax_ext/asm.rs +++ b/src/libsyntax_ext/asm.rs @@ -11,7 +11,7 @@ use syntax::ext::base::{self, *}; use syntax::feature_gate; use syntax::parse::{self, token}; use syntax::ptr::P; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::ast::AsmDialect; use syntax_pos::Span; use syntax::tokenstream; @@ -39,7 +39,7 @@ impl State { } } -const OPTIONS: &[&str] = &["volatile", "alignstack", "intel"]; +const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel]; pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, @@ -47,7 +47,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, -> Box { if !cx.ecfg.enable_asm() { feature_gate::emit_feature_err(&cx.parse_sess, - "asm", + sym::asm, sp, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_ASM); @@ -233,13 +233,13 @@ fn parse_inline_asm<'a>( Options => { let (option, _) = p.parse_str()?; - if option == "volatile" { + if option == sym::volatile { // Indicates that the inline assembly has side effects // and must not be optimized out along with its outputs. volatile = true; - } else if option == "alignstack" { + } else if option == sym::alignstack { alignstack = true; - } else if option == "intel" { + } else if option == sym::intel { dialect = AsmDialect::Intel; } else { cx.span_warn(p.prev_span, "unrecognized option"); diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs index 8c9eb4bf2d8ff..77c53f402cc9f 100644 --- a/src/libsyntax_ext/concat_idents.rs +++ b/src/libsyntax_ext/concat_idents.rs @@ -6,7 +6,7 @@ use syntax::feature_gate; use syntax::parse::token; use syntax::ptr::P; use syntax_pos::Span; -use syntax_pos::symbol::Symbol; +use syntax_pos::symbol::{Symbol, sym}; use syntax::tokenstream::TokenTree; pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, @@ -15,7 +15,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>, -> Box { if !cx.ecfg.enable_concat_idents() { feature_gate::emit_feature_err(&cx.parse_sess, - "concat_idents", + sym::concat_idents, sp, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_CONCAT_IDENTS); diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index b347092e1bc4c..1b0d572324a79 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -7,7 +7,7 @@ use syntax::attr; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::ptr::P; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, keywords, sym}; use syntax_pos::Span; pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>, @@ -37,7 +37,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt<'_>, match annitem.node { ItemKind::Struct(_, Generics { ref params, .. }) | ItemKind::Enum(_, Generics { ref params, .. }) => { - if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") && + if attr::contains_name(&annitem.attrs, sym::rustc_copy_clone_marker) && !params.iter().any(|param| match param.kind { ast::GenericParamKind::Type { .. } => true, _ => false, diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index e5939e396e5c1..a13dc07085f80 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -191,7 +191,7 @@ use syntax::ext::build::AstBuilder; use syntax::source_map::{self, respan}; use syntax::util::map_in_place::MapInPlace; use syntax::ptr::P; -use syntax::symbol::{Symbol, keywords}; +use syntax::symbol::{Symbol, keywords, sym}; use syntax::parse::ParseSess; use syntax_pos::{DUMMY_SP, Span}; @@ -426,7 +426,7 @@ impl<'a> TraitDef<'a> { } }; let is_always_copy = - attr::contains_name(&item.attrs, "rustc_copy_clone_marker") && + attr::contains_name(&item.attrs, sym::rustc_copy_clone_marker) && has_no_type_params; let use_temporaries = is_packed && is_always_copy; @@ -464,8 +464,8 @@ impl<'a> TraitDef<'a> { attrs.extend(item.attrs .iter() .filter(|a| { - ["allow", "warn", "deny", "forbid", "stable", "unstable"] - .contains(&a.name_or_empty().get()) + [sym::allow, sym::warn, sym::deny, sym::forbid, sym::stable, sym::unstable] + .contains(&a.name_or_empty()) }) .cloned()); push(Annotatable::Item(P(ast::Item { attrs: attrs, ..(*newitem).clone() }))) diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index fff54814a38c4..c27de692d887c 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -6,7 +6,7 @@ use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension, Resolver}; use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::ptr::P; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; macro path_local($x:ident) { @@ -139,7 +139,7 @@ fn call_intrinsic(cx: &ExtCtxt<'_>, let intrinsic_allowed_via_allow_internal_unstable = cx .current_expansion.mark.expn_info().unwrap() .allow_internal_unstable.map_or(false, |features| features.iter().any(|&s| - s == "core_intrinsics" + s == sym::core_intrinsics )); if intrinsic_allowed_via_allow_internal_unstable { span = span.with_ctxt(cx.backtrace()); diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 24fbc9b6caf3f..9e54c0634b666 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -12,7 +12,7 @@ use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::parse::token; use syntax::ptr::P; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::tokenstream; use syntax_pos::{MultiSpan, Span, DUMMY_SP}; @@ -711,12 +711,12 @@ pub fn expand_format_args_nl<'cx>( //if !ecx.ecfg.enable_allow_internal_unstable() { // For some reason, the only one that actually works for `println` is the first check - if !sp.allows_unstable("format_args_nl") // the span is marked as `#[allow_insternal_unsable]` + if !sp.allows_unstable(sym::format_args_nl) // the span is marked `#[allow_insternal_unsable]` && !ecx.ecfg.enable_allow_internal_unstable() // NOTE: when is this enabled? && !ecx.ecfg.enable_format_args_nl() // enabled using `#[feature(format_args_nl]` { feature_gate::emit_feature_err(&ecx.parse_sess, - "format_args_nl", + sym::format_args_nl, sp, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_FORMAT_ARGS_NL); diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs index 2baf530aedae7..3f2853e4b0e20 100644 --- a/src/libsyntax_ext/global_asm.rs +++ b/src/libsyntax_ext/global_asm.rs @@ -16,12 +16,12 @@ use syntax::ext::base::{self, *}; use syntax::feature_gate; use syntax::parse::token; use syntax::ptr::P; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; use syntax::tokenstream; use smallvec::smallvec; -pub const MACRO: &str = "global_asm"; +pub const MACRO: Symbol = sym::global_asm; pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>, sp: Span, diff --git a/src/libsyntax_ext/log_syntax.rs b/src/libsyntax_ext/log_syntax.rs index 658ce98d26884..1be3990837cfe 100644 --- a/src/libsyntax_ext/log_syntax.rs +++ b/src/libsyntax_ext/log_syntax.rs @@ -2,6 +2,7 @@ use syntax::ext::base; use syntax::feature_gate; use syntax::print; use syntax::tokenstream; +use syntax::symbol::sym; use syntax_pos; pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt<'_>, @@ -10,7 +11,7 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt<'_>, -> Box { if !cx.ecfg.enable_log_syntax() { feature_gate::emit_feature_err(&cx.parse_sess, - "log_syntax", + sym::log_syntax, sp, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_LOG_SYNTAX); diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index f0390ba3d40cb..1eab739cf6470 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -13,12 +13,16 @@ use syntax::mut_visit::MutVisitor; use syntax::parse::ParseSess; use syntax::ptr::P; use syntax::symbol::Symbol; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax::visit::{self, Visitor}; use syntax_pos::{Span, DUMMY_SP}; -const PROC_MACRO_KINDS: [&str; 3] = ["proc_macro_derive", "proc_macro_attribute", "proc_macro"]; +const PROC_MACRO_KINDS: [Symbol; 3] = [ + sym::proc_macro_derive, + sym::proc_macro_attribute, + sym::proc_macro +]; struct ProcMacroDerive { trait_name: ast::Name, @@ -139,7 +143,7 @@ impl<'a> CollectProcMacros<'a> { let attributes_attr = list.get(1); let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr { - if !attr.check_name("attributes") { + if !attr.check_name(sym::attributes) { self.handler.span_err(attr.span(), "second argument must be `attributes`") } attr.meta_item_list().unwrap_or_else(|| { @@ -231,7 +235,7 @@ impl<'a> CollectProcMacros<'a> { impl<'a> Visitor<'a> for CollectProcMacros<'a> { fn visit_item(&mut self, item: &'a ast::Item) { if let ast::ItemKind::MacroDef(..) = item.node { - if self.is_proc_macro_crate && attr::contains_name(&item.attrs, "macro_export") { + if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) { let msg = "cannot export macro_rules! macros from a `proc-macro` crate type currently"; self.handler.span_err(item.span, msg); @@ -304,11 +308,11 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { return; } - if attr.check_name("proc_macro_derive") { + if attr.check_name(sym::proc_macro_derive) { self.collect_custom_derive(item, attr); - } else if attr.check_name("proc_macro_attribute") { + } else if attr.check_name(sym::proc_macro_attribute) { self.collect_attr_proc_macro(item); - } else if attr.check_name("proc_macro") { + } else if attr.check_name(sym::proc_macro) { self.collect_bang_proc_macro(item); }; @@ -324,6 +328,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> { // Creates a new module which looks like: // +// #[doc(hidden)] // mod $gensym { // extern crate proc_macro; // @@ -357,6 +362,10 @@ fn mk_decls( }); let span = DUMMY_SP.apply_mark(mark); + let hidden = cx.meta_list_item_word(span, Symbol::intern("hidden")); + let doc = cx.meta_list(span, Symbol::intern("doc"), vec![hidden]); + let doc_hidden = cx.attribute(span, doc); + let proc_macro = Ident::from_str("proc_macro"); let krate = cx.item(span, proc_macro, @@ -421,7 +430,7 @@ fn mk_decls( span, span, ast::Ident::with_empty_ctxt(Symbol::gensym("decls")), - vec![], + vec![doc_hidden], vec![krate, decls_static], ).map(|mut i| { i.vis = respan(span, ast::VisibilityKind::Public); diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 0fa5cd64360c0..86ae6ab5fece5 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -7,7 +7,7 @@ use syntax::ext::hygiene::{self, Mark, SyntaxContext}; use syntax::attr; use syntax::ast; use syntax::print::pprust; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::{DUMMY_SP, Span}; use syntax::source_map::{ExpnInfo, MacroAttribute}; use std::iter; @@ -206,15 +206,15 @@ enum ShouldPanic { } fn should_ignore(i: &ast::Item) -> bool { - attr::contains_name(&i.attrs, "ignore") + attr::contains_name(&i.attrs, sym::ignore) } fn should_fail(i: &ast::Item) -> bool { - attr::contains_name(&i.attrs, "allow_fail") + attr::contains_name(&i.attrs, sym::allow_fail) } fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { - match attr::find_by_name(&i.attrs, "should_panic") { + match attr::find_by_name(&i.attrs, sym::should_panic) { Some(attr) => { let ref sd = cx.parse_sess.span_diagnostic; @@ -222,7 +222,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { // Handle #[should_panic(expected = "foo")] Some(list) => { let msg = list.iter() - .find(|mi| mi.check_name("expected")) + .find(|mi| mi.check_name(sym::expected)) .and_then(|mi| mi.meta_item()) .and_then(|mi| mi.value_str()); if list.len() != 1 || msg.is_none() { @@ -247,7 +247,7 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic { } fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { - let has_should_panic_attr = attr::contains_name(&i.attrs, "should_panic"); + let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic); let ref sd = cx.parse_sess.span_diagnostic; if let ast::ItemKind::Fn(ref decl, ref header, ref generics, _) = i.node { if header.unsafety == ast::Unsafety::Unsafe { diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs index 1ed1ab0a07b96..802037f6d22bb 100644 --- a/src/libsyntax_ext/test_case.rs +++ b/src/libsyntax_ext/test_case.rs @@ -14,7 +14,7 @@ use syntax::ext::build::AstBuilder; use syntax::ext::hygiene::{self, Mark, SyntaxContext}; use syntax::ast; use syntax::source_map::respan; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax_pos::{DUMMY_SP, Span}; use syntax::source_map::{ExpnInfo, MacroAttribute}; use syntax::feature_gate; @@ -27,7 +27,7 @@ pub fn expand( ) -> Vec { if !ecx.ecfg.enable_custom_test_frameworks() { feature_gate::emit_feature_err(&ecx.parse_sess, - "custom_test_frameworks", + sym::custom_test_frameworks, attr_sp, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_CUSTOM_TEST_FRAMEWORKS); diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs index 4d35daf3de998..eca658cb5473e 100644 --- a/src/libsyntax_ext/trace_macros.rs +++ b/src/libsyntax_ext/trace_macros.rs @@ -1,6 +1,6 @@ use syntax::ext::base::{self, ExtCtxt}; use syntax::feature_gate; -use syntax::symbol::keywords; +use syntax::symbol::{keywords, sym}; use syntax_pos::Span; use syntax::tokenstream::TokenTree; @@ -10,7 +10,7 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt<'_>, -> Box { if !cx.ecfg.enable_trace_macros() { feature_gate::emit_feature_err(&cx.parse_sess, - "trace_macros", + sym::trace_macros, sp, feature_gate::GateIssue::Language, feature_gate::EXPLAIN_TRACE_MACROS); diff --git a/src/libsyntax_pos/edition.rs b/src/libsyntax_pos/edition.rs index a0b0052f26dab..00cd00f283784 100644 --- a/src/libsyntax_pos/edition.rs +++ b/src/libsyntax_pos/edition.rs @@ -1,3 +1,4 @@ +use crate::symbol::{Symbol, sym}; use std::fmt; use std::str::FromStr; @@ -44,10 +45,10 @@ impl Edition { } } - pub fn feature_name(&self) -> &'static str { + pub fn feature_name(&self) -> Symbol { match *self { - Edition::Edition2015 => "rust_2015_preview", - Edition::Edition2018 => "rust_2018_preview", + Edition::Edition2015 => sym::rust_2015_preview, + Edition::Edition2018 => sym::rust_2018_preview, } } diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index c806020039d26..1d9dc26bf6092 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -591,6 +591,10 @@ impl ExpnFormat { /// The kind of compiler desugaring. #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { + /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`. + /// However, we do not want to blame `c` for unreachability but rather say that `i` + /// is unreachable. This desugaring kind allows us to avoid blaming `c`. + IfTemporary, QuestionMark, TryBlock, /// Desugaring of an `impl Trait` in return type position @@ -598,13 +602,16 @@ pub enum CompilerDesugaringKind { /// `impl Trait` with `Foo`. ExistentialReturnType, Async, + Await, ForLoop, } impl CompilerDesugaringKind { pub fn name(self) -> Symbol { Symbol::intern(match self { + CompilerDesugaringKind::IfTemporary => "if", CompilerDesugaringKind::Async => "async", + CompilerDesugaringKind::Await => "await", CompilerDesugaringKind::QuestionMark => "?", CompilerDesugaringKind::TryBlock => "try block", CompilerDesugaringKind::ExistentialReturnType => "existential type", diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 3f09405a5c8c6..39859f25f97fb 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -33,7 +33,7 @@ mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; pub mod symbol; -pub use symbol::symbols; +pub use symbol::{Symbol, sym}; mod analyze_source_file; @@ -388,12 +388,12 @@ impl Span { /// Checks if a span is "internal" to a macro in which `#[unstable]` /// items can be used (that is, a macro marked with /// `#[allow_internal_unstable]`). - pub fn allows_unstable(&self, feature: &str) -> bool { + pub fn allows_unstable(&self, feature: Symbol) -> bool { match self.ctxt().outer().expn_info() { Some(info) => info .allow_internal_unstable .map_or(false, |features| features.iter().any(|&f| - f == feature || f == "allow_internal_unstable_backcompat_hack" + f == feature || f == sym::allow_internal_unstable_backcompat_hack )), None => false, } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index cdbfabae7ce1f..ec0ce4253fa2d 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -84,6 +84,7 @@ symbols! { // Edition-specific keywords that are used in unstable Rust or reserved for future use. Async: "async", // >= 2018 Edition only + Await: "await", // >= 2018 Edition only Try: "try", // >= 2018 Edition only // Special lifetime names @@ -98,88 +99,375 @@ symbols! { Union: "union", } - // Other symbols that can be referred to with syntax_pos::symbols::* - Other { + // Symbols that can be referred to with syntax_pos::sym::*. The symbol is + // the stringified identifier unless otherwise specified (e.g. + // `proc_dash_macro` represents "proc-macro"). + Symbols { + aarch64_target_feature, + abi, + abi_amdgpu_kernel, + abi_msp430_interrupt, + abi_ptx, + abi_sysv64, + abi_thiscall, + abi_unadjusted, + abi_vectorcall, + abi_x86_interrupt, + aborts, + advanced_slice_patterns, + adx_target_feature, alias, align, + alignstack, + all, + allocator, + allocator_internals, alloc_error_handler, allow, + allowed, allow_fail, allow_internal_unsafe, allow_internal_unstable, + allow_internal_unstable_backcompat_hack, + always, + any, + arbitrary_self_types, + arm_target_feature, + asm, + associated_consts, + associated_type_defaults, + associated_types, + async_await, + attr, + attributes, + attr_literals, + augmented_assignments, automatically_derived, + avx512_target_feature, + await_macro, + bin, + bind_by_move_pattern_guards, + block, + borrowck_graphviz_postflow, + borrowck_graphviz_preflow, + box_patterns, + box_syntax, + braced_empty_structs, + C, + cdylib, cfg, cfg_attr, + cfg_attr_multi, + cfg_target_feature, + cfg_target_has_atomic, + cfg_target_thread_local, + cfg_target_vendor, + clone, + clone_closures, + clone_from, + closure_to_fn_coercion, + cmpxchg16b_target_feature, cold, + compile_error, compiler_builtins, + concat_idents, + conservative_impl_trait, + console, + const_compare_raw_pointers, + const_fn, + const_fn_union, + const_generics, + const_indexing, + const_let, + const_panic, + const_raw_ptr_deref, + const_raw_ptr_to_usize_cast, + const_transmute, + contents, + convert, + copy_closures, + core, + core_intrinsics, crate_id, + crate_in_paths, crate_name, crate_type, + crate_visibility_modifier, + custom_attribute, + custom_derive, + custom_inner_attributes, + custom_test_frameworks, + c_variadic, + decl_macro, default_lib_allocator, + default_type_parameter_fallback, + default_type_params, deny, deprecated, derive, doc, + doc_alias, + doc_cfg, + doc_keyword, + doc_masked, + doc_spotlight, + document_private_items, + dotdoteq_in_patterns, + dotdot_in_tuple_patterns, + dropck_eyepatch, + dropck_parametricity, + drop_types_in_const, + dylib, + dyn_trait, + eh_personality, + eh_unwind_resume, + enable, + Err, + except, + exclusive_range_pattern, + exhaustive_integer_patterns, + exhaustive_patterns, + existential_type, + expected, export_name, + extern_absolute_paths, + external_doc, + extern_crate_item_prelude, + extern_crate_self, + extern_in_paths, + extern_prelude, + extern_types, + f16c_target_feature, feature, ffi_returns_twice, + field_init_shorthand, + file, + fn_must_use, forbid, + format_args_nl, + from, + From, + from_error, + from_generator, + from_ok, fundamental, + future, + Future, + generators, + generic_associated_types, + generic_param_attrs, global_allocator, + global_asm, + globs, + hexagon_target_feature, + hidden, + homogeneous_aggregate, + html_favicon_url, + html_logo_url, + html_no_source, + html_playground_url, + html_root_url, + i128, + i128_type, + i16, + i32, + i64, + i8, + ident, + if_let, + if_while_or_patterns, ignore, + impl_header_lifetime_elision, + impl_trait_in_bindings, + import_shadowing, + in_band_lifetimes, include, + inclusive_range_syntax, + infer_outlives_requirements, + infer_static_outlives_requirements, inline, + intel, + into_iter, + IntoIterator, + into_result, + intrinsics, + irrefutable_let_patterns, + isize, + issue, + issue_5723_bootstrap, + issue_tracker_base_url, + item_like_imports, + iter, + Iterator, keyword, + kind, + label, + label_break_value, lang, + lang_items, + lib, link, + linkage, link_args, + link_cfg, + link_llvm_intrinsics, link_name, link_section, - linkage, + lint_reasons, + local_inner_macros, + log_syntax, + loop_break_value, + macro_at_most_once_rep, macro_escape, macro_export, + macro_lifetime_matcher, + macro_literal_matcher, + macro_reexport, + macro_rules, + macros_in_extern, macro_use, + macro_vis_matcher, main, + managed_boxes, marker, + marker_trait_attr, masked, + match_beginning_vert, + match_default_bindings, may_dangle, + message, + min_const_fn, + min_const_unsafe_fn, + mips_target_feature, + mmx_target_feature, + module, + more_struct_aliases, + movbe_target_feature, must_use, naked, + naked_functions, + name, needs_allocator, needs_panic_runtime, + negate_unsigned, + never, + never_type, + next, + nll, no_builtins, no_core, + no_crate_inject, no_debug, + no_default_passes, no_implicit_prelude, + no_inline, no_link, no_main, no_mangle, + non_ascii_idents, + None, + non_exhaustive, + non_modrs_mods, + no_stack_check, no_start, no_std, - non_exhaustive, + not, + note, + Ok, omit_gdb_pretty_printer_section, + on, + on_unimplemented, + oom, + ops, optimize, + optimize_attribute, + optin_builtin_traits, + option, + Option, + opt_out_copy, + overlapping_marker_traits, + packed, panic_handler, + panic_impl, + panic_implementation, panic_runtime, + passes, path, + pattern_parentheses, + Pending, + pin, + Pin, + platform_intrinsics, plugin, plugin_registrar, + plugins, + Poll, + poll_with_tls_context, + powerpc_target_feature, + precise_pointer_size_matching, + prelude, prelude_import, + primitive, + proc_dash_macro: "proc-macro", proc_macro, proc_macro_attribute, proc_macro_derive, + proc_macro_expr, + proc_macro_gen, + proc_macro_hygiene, + proc_macro_mod, + proc_macro_non_items, + proc_macro_path_invoc, profiler_runtime, + pub_restricted, + pushpop_unsafe, + quad_precision_float, + question_mark, + quote, + Range, + RangeFrom, + RangeFull, + RangeInclusive, + RangeTo, + RangeToInclusive, + raw_identifiers, + Ready, + reason, recursion_limit, reexport_test_harness_main, + reflect, + relaxed_adts, repr, + repr128, + repr_align, + repr_align_enum, + repr_packed, + repr_simd, + repr_transparent, + re_rebalance_coherence, + result, + Result, + Return, + rlib, + rtm_target_feature, + rust, + rust_2015_preview, + rust_2018_preview, + rust_begin_unwind, + rustc_allocator_nounwind, + rustc_allow_const_fn_ptr, rustc_args_required_const, + rustc_attrs, rustc_clean, rustc_const_unstable, rustc_conversion_suggestion, rustc_copy_clone_marker, rustc_def_path, rustc_deprecated, + rustc_diagnostic_macros, rustc_dirty, + rustc_doc_only_macro, + rustc_dump_env_program_clauses, rustc_dump_program_clauses, rustc_dump_user_substs, rustc_error, @@ -190,13 +478,21 @@ symbols! { rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, rustc_mir, + rustc_object_lifetime_default, rustc_on_unimplemented, rustc_outlives, rustc_paren_sugar, rustc_partition_codegened, rustc_partition_reused, + rustc_peek, + rustc_peek_definite_init, + rustc_peek_maybe_init, + rustc_peek_maybe_uninit, + rustc_private, rustc_proc_macro_decls, + rustc_promotable, rustc_regions, + rustc_stable, rustc_std_internal_symbol, rustc_symbol_name, rustc_synthetic, @@ -204,23 +500,108 @@ symbols! { rustc_then_this_would_need, rustc_transparent_macro, rustc_variance, + rustdoc, + rust_eh_personality, + rust_eh_unwind_resume, + rust_oom, + __rust_unstable_column, + rvalue_static_promotion, sanitizer_runtime, + self_in_typedefs, + self_struct_ctor, + Send, should_panic, simd, + simd_ffi, + since, + size, + slice_patterns, + slicing_syntax, + Some, + specialization, + speed, spotlight, + sse4a_target_feature, stable, + staged_api, start, + static_in_const, + staticlib, + static_nobundle, + static_recursion, + std, + stmt_expr_attributes, + stop_after_dataflow, + struct_field_attributes, + struct_inherit, structural_match, + struct_variant, + suggestion, target_feature, + target_has_atomic, + target_thread_local, + task, + tbm_target_feature, + termination_trait, + termination_trait_test, + test, + test_2018_feature, + test_accepted_feature, + test_removed_feature, test_runner, thread_local, + tool_attributes, + tool_lints, + trace_macros, + trait_alias, + transmute, + transparent, + trivial_bounds, + Try, + try_blocks, + tuple_indexing, + ty, + type_alias_enum_variants, + type_ascription, type_length_limit, + type_macros, + u128, + u16, + u32, + u64, + u8, + unboxed_closures, + underscore_const_names, + underscore_imports, + underscore_lifetimes, + uniform_paths, + universal_impl_trait, + unmarked_api, + unrestricted_attribute_tokens, unsafe_destructor_blind_to_params, + unsafe_no_drop_flag, + unsized_locals, + unsized_tuple_coercion, unstable, + untagged_unions, unwind, + unwind_attributes, used, + use_extern_macros, + use_nested_groups, + usize, + v1, + vis, + visible_private_types, + volatile, warn, + warn_directory_ownership, + wasm_import_module, + wasm_target_feature, + while_let, + windows, windows_subsystem, + Yield, } } @@ -343,9 +724,22 @@ impl Decodable for Ident { } } -/// A symbol is an interned or gensymed string. The use of `newtype_index!` means -/// that `Option` only takes up 4 bytes, because `newtype_index!` reserves -/// the last 256 values for tagging purposes. +/// A symbol is an interned or gensymed string. A gensym is a symbol that is +/// never equal to any other symbol. E.g.: +/// ``` +/// assert_eq!(Symbol::intern("x"), Symbol::intern("x")) +/// assert_ne!(Symbol::gensym("x"), Symbol::intern("x")) +/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x")) +/// ``` +/// Conceptually, a gensym can be thought of as a normal symbol with an +/// invisible unique suffix. Gensyms are useful when creating new identifiers +/// that must not match any existing identifiers, e.g. during macro expansion +/// and syntax desugaring. +/// +/// Internally, a Symbol is implemented as an index, and all operations +/// (including hashing, equality, and ordering) operate on that index. The use +/// of `newtype_index!` means that `Option` only takes up 4 bytes, +/// because `newtype_index!` reserves the last 256 values for tagging purposes. /// /// Note that `Symbol` cannot directly be a `newtype_index!` because it implements /// `fmt::Debug`, `Encodable`, and `Decodable` in special ways. @@ -366,10 +760,6 @@ impl Symbol { with_interner(|interner| interner.intern(string)) } - pub fn interned(self) -> Self { - with_interner(|interner| interner.interned(self)) - } - /// Gensyms a new `usize`, using the current interner. pub fn gensym(string: &str) -> Self { with_interner(|interner| interner.gensym(string)) @@ -379,6 +769,7 @@ impl Symbol { with_interner(|interner| interner.gensymed(self)) } + // WARNING: this function is deprecated and will be removed in the future. pub fn is_gensymed(self) -> bool { with_interner(|interner| interner.is_gensymed(self)) } @@ -431,12 +822,6 @@ impl Decodable for Symbol { } } -impl> PartialEq for Symbol { - fn eq(&self, other: &T) -> bool { - self.as_str() == other.deref() - } -} - // The `&'static str`s in this type actually point into the arena. // // Note that normal symbols are indexed upward from 0, and gensyms are indexed @@ -452,15 +837,16 @@ pub struct Interner { impl Interner { fn prefill(init: &[&str]) -> Self { let mut this = Interner::default(); - for &string in init { - if string == "" { - // We can't allocate empty strings in the arena, so handle this here. - let name = Symbol::new(this.strings.len() as u32); - this.names.insert("", name); - this.strings.push(""); - } else { - this.intern(string); - } + this.names.reserve(init.len()); + this.strings.reserve(init.len()); + + // We can't allocate empty strings in the arena, so handle this here. + assert!(keywords::Invalid.name().as_u32() == 0 && init[0].is_empty()); + this.names.insert("", keywords::Invalid.name()); + this.strings.push(""); + + for string in &init[1..] { + this.intern(string); } this } @@ -487,11 +873,11 @@ impl Interner { name } - pub fn interned(&self, symbol: Symbol) -> Symbol { + fn interned(&self, symbol: Symbol) -> Symbol { if (symbol.0.as_usize()) < self.strings.len() { symbol } else { - self.interned(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]) + self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize] } } @@ -509,10 +895,15 @@ impl Interner { symbol.0.as_usize() >= self.strings.len() } + // Get the symbol as a string. `Symbol::as_str()` should be used in + // preference to this function. pub fn get(&self, symbol: Symbol) -> &str { match self.strings.get(symbol.0.as_usize()) { Some(string) => string, - None => self.get(self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]), + None => { + let symbol = self.gensyms[(SymbolIndex::MAX_AS_U32 - symbol.0.as_u32()) as usize]; + self.strings[symbol.0.as_usize()] + } } } } @@ -540,7 +931,8 @@ pub mod keywords { keywords!(); } -pub mod symbols { +// This module has a very short name because it's used a lot. +pub mod sym { use super::Symbol; symbols!(); } @@ -610,11 +1002,17 @@ fn with_interner T>(f: F) -> T { GLOBALS.with(|globals| f(&mut *globals.symbol_interner.lock())) } -/// Represents a string stored in the interner. Because the interner outlives any thread -/// which uses this type, we can safely treat `string` which points to interner data, -/// as an immortal string, as long as this type never crosses between threads. -// FIXME: ensure that the interner outlives any thread which uses `LocalInternedString`, -// by creating a new thread right after constructing the interner. +/// An alternative to `Symbol` and `InternedString`, useful when the chars +/// within the symbol need to be accessed. It is best used for temporary +/// values. +/// +/// Because the interner outlives any thread which uses this type, we can +/// safely treat `string` which points to interner data, as an immortal string, +/// as long as this type never crosses between threads. +// +// FIXME: ensure that the interner outlives any thread which uses +// `LocalInternedString`, by creating a new thread right after constructing the +// interner. #[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)] pub struct LocalInternedString { string: &'static str, @@ -707,7 +1105,19 @@ impl Encodable for LocalInternedString { } } -/// Represents a string stored in the string interner. +/// An alternative to `Symbol` that is focused on string contents. It has two +/// main differences to `Symbol`. +/// +/// First, its implementations of `Hash`, `PartialOrd` and `Ord` work with the +/// string chars rather than the symbol integer. This is useful when hash +/// stability is required across compile sessions, or a guaranteed sort +/// ordering is required. +/// +/// Second, gensym-ness is irrelevant. E.g.: +/// ``` +/// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x")) +/// assert_eq!(Symbol::gensym("x").as_interned_str(), Symbol::gensym("x").as_interned_str()) +/// ``` #[derive(Clone, Copy, Eq)] pub struct InternedString { symbol: Symbol, @@ -724,6 +1134,15 @@ impl InternedString { unsafe { f(&*str) } } + fn with2 R, R>(self, other: &InternedString, f: F) -> R { + let (self_str, other_str) = with_interner(|interner| { + (interner.get(self.symbol) as *const str, + interner.get(other.symbol) as *const str) + }); + // This is safe for the same reason that `with` is safe. + unsafe { f(&*self_str, &*other_str) } + } + pub fn as_symbol(self) -> Symbol { self.symbol } @@ -744,7 +1163,7 @@ impl PartialOrd for InternedString { if self.symbol == other.symbol { return Some(Ordering::Equal); } - self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str))) + self.with2(other, |self_str, other_str| self_str.partial_cmp(other_str)) } } @@ -753,7 +1172,7 @@ impl Ord for InternedString { if self.symbol == other.symbol { return Ordering::Equal; } - self.with(|self_str| other.with(|other_str| self_str.cmp(&other_str))) + self.with2(other, |self_str, other_str| self_str.cmp(other_str)) } } @@ -793,12 +1212,6 @@ impl<'a> PartialEq for &'a String { } } -impl std::convert::From for String { - fn from(val: InternedString) -> String { - val.as_symbol().to_string() - } -} - impl fmt::Debug for InternedString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.with(|str| fmt::Debug::fmt(&str, f)) diff --git a/src/libtest/Cargo.toml b/src/libtest/Cargo.toml index 2e836b6772fda..a72e4c7050289 100644 --- a/src/libtest/Cargo.toml +++ b/src/libtest/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" crate-type = ["dylib", "rlib"] [dependencies] -getopts = "0.2.18" +getopts = "0.2.19" term = { path = "../libterm" } # not actually used but needed to always have proc_macro in the sysroot diff --git a/src/test/codegen/i686-macosx-deployment-target.rs b/src/test/codegen/i686-macosx-deployment-target.rs new file mode 100644 index 0000000000000..dad376d6677f7 --- /dev/null +++ b/src/test/codegen/i686-macosx-deployment-target.rs @@ -0,0 +1,26 @@ +// +// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set. +// See issue #60235. + +// compile-flags: -O --target=i686-apple-darwin --crate-type=rlib +// rustc-env:MACOSX_DEPLOYMENT_TARGET=10.9 +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "i686-apple-macosx10.9.0" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/src/test/codegen/i686-no-macosx-deployment-target.rs b/src/test/codegen/i686-no-macosx-deployment-target.rs new file mode 100644 index 0000000000000..eb826590523b7 --- /dev/null +++ b/src/test/codegen/i686-no-macosx-deployment-target.rs @@ -0,0 +1,26 @@ +// +// Checks that we leave the target alone MACOSX_DEPLOYMENT_TARGET is unset. +// See issue #60235. + +// compile-flags: -O --target=i686-apple-darwin --crate-type=rlib +// unset-rustc-env:MACOSX_DEPLOYMENT_TARGET +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "i686-apple-darwin" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/src/test/codegen/x86_64-macosx-deployment-target.rs b/src/test/codegen/x86_64-macosx-deployment-target.rs new file mode 100644 index 0000000000000..8e291b7b298d5 --- /dev/null +++ b/src/test/codegen/x86_64-macosx-deployment-target.rs @@ -0,0 +1,26 @@ +// +// Checks that we correctly modify the target when MACOSX_DEPLOYMENT_TARGET is set. +// See issue #60235. + +// compile-flags: -O --target=x86_64-apple-darwin --crate-type=rlib +// rustc-env:MACOSX_DEPLOYMENT_TARGET=10.9 +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "x86_64-apple-macosx10.9.0" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/src/test/codegen/x86_64-no-macosx-deployment-target.rs b/src/test/codegen/x86_64-no-macosx-deployment-target.rs new file mode 100644 index 0000000000000..58a11d1095bbe --- /dev/null +++ b/src/test/codegen/x86_64-no-macosx-deployment-target.rs @@ -0,0 +1,26 @@ +// +// Checks that we leave the target alone when MACOSX_DEPLOYMENT_TARGET is unset. +// See issue #60235. + +// compile-flags: -O --target=x86_64-apple-darwin --crate-type=rlib +// unset-rustc-env:MACOSX_DEPLOYMENT_TARGET +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + +#[repr(C)] +pub struct Bool { + b: bool, +} + +// CHECK: target triple = "x86_64-apple-darwin" +#[no_mangle] +pub extern "C" fn structbool() -> Bool { + Bool { b: true } +} diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs index fba7869af42f2..6bc7d286e3adb 100644 --- a/src/test/incremental/hashes/if_expressions.rs +++ b/src/test/incremental/hashes/if_expressions.rs @@ -94,7 +94,7 @@ pub fn add_else_branch(x: bool) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="HirBody")] #[rustc_clean(cfg="cfail3")] pub fn add_else_branch(x: bool) -> u32 { let mut ret = 1; @@ -191,7 +191,7 @@ pub fn add_else_branch_if_let(x: Option) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(cfg="cfail2", except="HirBody,typeck_tables_of")] +#[rustc_clean(cfg="cfail2", except="HirBody")] #[rustc_clean(cfg="cfail3")] pub fn add_else_branch_if_let(x: Option) -> u32 { let mut ret = 1; diff --git a/src/test/incremental/issue-60629.rs b/src/test/incremental/issue-60629.rs new file mode 100644 index 0000000000000..4807af4b3cf70 --- /dev/null +++ b/src/test/incremental/issue-60629.rs @@ -0,0 +1,10 @@ +// revisions:rpass1 rpass2 + +struct A; + +#[cfg(rpass2)] +impl From for () { + fn from(_: A) {} +} + +fn main() {} diff --git a/src/test/mir-opt/graphviz.rs b/src/test/mir-opt/graphviz.rs index 660576996e5d4..67a6d1d263bf5 100644 --- a/src/test/mir-opt/graphviz.rs +++ b/src/test/mir-opt/graphviz.rs @@ -7,7 +7,7 @@ fn main() {} // END RUST SOURCE // START rustc.main.mir_map.0.dot -// digraph Mir_0_0_3 { // The name here MUST be an ASCII identifier. +// digraph Mir_0_12 { // The name here MUST be an ASCII identifier. // graph [fontname="monospace"]; // node [fontname="monospace"]; // edge [fontname="monospace"]; diff --git a/src/test/mir-opt/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline-closure-borrows-arg.rs index 84567e1b4b8f2..0e1db68f37255 100644 --- a/src/test/mir-opt/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline-closure-borrows-arg.rs @@ -20,7 +20,7 @@ fn foo(_t: T, q: &i32) -> i32 { // ... // bb0: { // ... -// _3 = [closure@HirId { owner: DefIndex(0:4), local_id: 31 }]; +// _3 = [closure@HirId { owner: DefIndex(13), local_id: 31 }]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/inline-closure.rs b/src/test/mir-opt/inline-closure.rs index 2be48927fd3b7..fa8557f3b38a7 100644 --- a/src/test/mir-opt/inline-closure.rs +++ b/src/test/mir-opt/inline-closure.rs @@ -16,7 +16,7 @@ fn foo(_t: T, q: i32) -> i32 { // ... // bb0: { // ... -// _3 = [closure@HirId { owner: DefIndex(0:4), local_id: 15 }]; +// _3 = [closure@HirId { owner: DefIndex(13), local_id: 15 }]; // ... // _4 = &_3; // ... diff --git a/src/test/mir-opt/issue-38669.rs b/src/test/mir-opt/issue-38669.rs index 047e623941b71..e8ab690bb4648 100644 --- a/src/test/mir-opt/issue-38669.rs +++ b/src/test/mir-opt/issue-38669.rs @@ -27,15 +27,17 @@ fn main() { // bb3: { // StorageLive(_4); // _4 = _1; -// switchInt(move _4) -> [false: bb5, otherwise: bb4]; +// FakeRead(ForMatchedPlace, _4); +// switchInt(_4) -> [false: bb5, otherwise: bb4]; // } -// bb4: { +// ... +// bb7: { // _0 = (); // StorageDead(_4); // StorageDead(_1); // return; // } -// bb5: { +// bb8: { // _3 = (); // StorageDead(_4); // _1 = const true; diff --git a/src/test/mir-opt/loop_test.rs b/src/test/mir-opt/loop_test.rs index 34891ee70b5c6..e75955b9b2440 100644 --- a/src/test/mir-opt/loop_test.rs +++ b/src/test/mir-opt/loop_test.rs @@ -22,19 +22,20 @@ fn main() { // resume; // } // ... -// bb3: { // Entry into the loop +// bb6: { // Entry into the loop // _1 = (); -// goto -> bb4; +// StorageDead(_2); +// goto -> bb7; // } -// bb4: { // The loop_block -// falseUnwind -> [real: bb5, cleanup: bb1]; +// bb7: { // The loop_block +// falseUnwind -> [real: bb8, cleanup: bb1]; // } -// bb5: { // The loop body (body_block) -// StorageLive(_5); -// _5 = const 1i32; -// FakeRead(ForLet, _5); -// StorageDead(_5); -// goto -> bb4; +// bb8: { // The loop body (body_block) +// StorageLive(_6); +// _6 = const 1i32; +// FakeRead(ForLet, _6); +// StorageDead(_6); +// goto -> bb7; // } // ... // END rustc.main.SimplifyCfg-qualify-consts.after.mir diff --git a/src/test/mir-opt/nll/region-subtyping-basic.rs b/src/test/mir-opt/nll/region-subtyping-basic.rs index bb27461bb1e0f..622cc99983002 100644 --- a/src/test/mir-opt/nll/region-subtyping-basic.rs +++ b/src/test/mir-opt/nll/region-subtyping-basic.rs @@ -22,9 +22,9 @@ fn main() { // END RUST SOURCE // START rustc.main.nll.0.mir -// | '_#2r | U0 | {bb2[0..=5], bb3[0..=1]} -// | '_#3r | U0 | {bb2[1..=5], bb3[0..=1]} -// | '_#4r | U0 | {bb2[4..=5], bb3[0..=1]} +// | '_#2r | U0 | {bb2[0..=8], bb3[0], bb6[0..=1]} +// | '_#3r | U0 | {bb2[1..=8], bb3[0], bb6[0..=1]} +// | '_#4r | U0 | {bb2[4..=8], bb3[0], bb6[0..=1]} // END rustc.main.nll.0.mir // START rustc.main.nll.0.mir // let _2: &'_#3r usize; diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 6b7c863fcd43f..33ee0fe61b288 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -98,7 +98,7 @@ fn main() { // } // END rustc.main.EraseRegions.after.mir // START rustc.main-{{closure}}.EraseRegions.after.mir -// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(0:7), local_id: 72 }], _2: &i32) -> &i32 { +// fn main::{{closure}}#0(_1: &[closure@HirId { owner: DefIndex(20), local_id: 72 }], _2: &i32) -> &i32 { // ... // bb0: { // Retag([fn entry] _1); diff --git a/src/test/mir-opt/simplify_if.rs b/src/test/mir-opt/simplify_if.rs index f6e6c6baf7a46..b2a99a6d446bb 100644 --- a/src/test/mir-opt/simplify_if.rs +++ b/src/test/mir-opt/simplify_if.rs @@ -5,13 +5,15 @@ fn main() { } // END RUST SOURCE -// START rustc.main.SimplifyBranches-initial.before.mir +// START rustc.main.SimplifyBranches-after-copy-prop.before.mir // bb0: { -// switchInt(const false) -> [false: bb3, otherwise: bb2]; +// ... +// switchInt(const false) -> [false: bb3, otherwise: bb1]; // } -// END rustc.main.SimplifyBranches-initial.before.mir -// START rustc.main.SimplifyBranches-initial.after.mir +// END rustc.main.SimplifyBranches-after-copy-prop.before.mir +// START rustc.main.SimplifyBranches-after-copy-prop.after.mir // bb0: { +// ... // goto -> bb3; // } -// END rustc.main.SimplifyBranches-initial.after.mir +// END rustc.main.SimplifyBranches-after-copy-prop.after.mir diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs new file mode 100644 index 0000000000000..754fad51b21e7 --- /dev/null +++ b/src/test/mir-opt/slice-drop-shim.rs @@ -0,0 +1,88 @@ +fn main() { + std::ptr::drop_in_place::<[String]> as unsafe fn(_); +} + +// END RUST SOURCE + +// START rustc.ptr-real_drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir +// let mut _2: usize; +// let mut _3: usize; +// let mut _4: usize; +// let mut _5: &mut std::string::String; +// let mut _6: bool; +// let mut _7: &mut std::string::String; +// let mut _8: bool; +// let mut _9: *mut std::string::String; +// let mut _10: *mut std::string::String; +// let mut _11: &mut std::string::String; +// let mut _12: bool; +// let mut _13: &mut std::string::String; +// let mut _14: bool; +// let mut _15: *mut [std::string::String]; +// bb0: { +// goto -> bb15; +// } +// bb1: { +// return; +// } +// bb2 (cleanup): { +// resume; +// } +// bb3 (cleanup): { +// _5 = &mut (*_1)[_4]; +// _4 = Add(move _4, const 1usize); +// drop((*_5)) -> bb4; +// } +// bb4 (cleanup): { +// _6 = Eq(_4, _3); +// switchInt(move _6) -> [false: bb3, otherwise: bb2]; +// } +// bb5: { +// _7 = &mut (*_1)[_4]; +// _4 = Add(move _4, const 1usize); +// drop((*_7)) -> [return: bb6, unwind: bb4]; +// } +// bb6: { +// _8 = Eq(_4, _3); +// switchInt(move _8) -> [false: bb5, otherwise: bb1]; +// } +// bb7: { +// _4 = const 0usize; +// goto -> bb6; +// } +// bb8: { +// goto -> bb7; +// } +// bb9 (cleanup): { +// _11 = &mut (*_9); +// _9 = Offset(move _9, const 1usize); +// drop((*_11)) -> bb10; +// } +// bb10 (cleanup): { +// _12 = Eq(_9, _10); +// switchInt(move _12) -> [false: bb9, otherwise: bb2]; +// } +// bb11: { +// _13 = &mut (*_9); +// _9 = Offset(move _9, const 1usize); +// drop((*_13)) -> [return: bb12, unwind: bb10]; +// } +// bb12: { +// _14 = Eq(_9, _10); +// switchInt(move _14) -> [false: bb11, otherwise: bb1]; +// } +// bb13: { +// _15 = &mut (*_1); +// _9 = move _15 as *mut std::string::String (Misc); +// _10 = Offset(_9, move _3); +// goto -> bb12; +// } +// bb14: { +// goto -> bb13; +// } +// bb15: { +// _2 = SizeOf(std::string::String); +// _3 = Len((*_1)); +// switchInt(move _2) -> [0usize: bb8, otherwise: bb14]; +// } +// END rustc.ptr-real_drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir diff --git a/src/test/run-make-fulldeps/link-cfg/Makefile b/src/test/run-make-fulldeps/link-cfg/Makefile index 188cba5fe4127..2701b4a593cc6 100644 --- a/src/test/run-make-fulldeps/link-cfg/Makefile +++ b/src/test/run-make-fulldeps/link-cfg/Makefile @@ -2,7 +2,7 @@ all: $(call DYLIB,return1) $(call DYLIB,return2) $(call NATIVE_STATICLIB,return3) ls $(TMPDIR) - $(RUSTC) --print cfg --target x86_64-unknown-linux-musl | $(CGREP) crt-static + $(BARE_RUSTC) --print cfg --target x86_64-unknown-linux-musl | $(CGREP) crt-static $(RUSTC) no-deps.rs --cfg foo $(call RUN,no-deps) diff --git a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile b/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile index 3fffd1e7aa2a2..b47ce17ec8baa 100644 --- a/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile +++ b/src/test/run-make-fulldeps/linker-output-non-utf8/Makefile @@ -20,4 +20,4 @@ all: $(RUSTC) library.rs mkdir $(bad_dir) mv $(TMPDIR)/liblibrary.a $(bad_dir) - LIBRARY_PATH=$(bad_dir) $(RUSTC) exec.rs 2>&1 | $(CGREP) this_symbol_not_defined + $(RUSTC) -L $(bad_dir) exec.rs 2>&1 | $(CGREP) this_symbol_not_defined diff --git a/src/test/run-make-fulldeps/override-aliased-flags/Makefile b/src/test/run-make-fulldeps/override-aliased-flags/Makefile new file mode 100644 index 0000000000000..bea610eeb9fd1 --- /dev/null +++ b/src/test/run-make-fulldeps/override-aliased-flags/Makefile @@ -0,0 +1,22 @@ +-include ../tools.mk + +# FIXME: it would be good to check that it's actually the rightmost flags +# that are used when multiple flags are specified, but I can't think of a +# reliable way to check this. + +all: + # Test that `-O` and `-C opt-level` can be specified multiple times. + # The rightmost flag will be used over any previous flags. + $(RUSTC) -O -O main.rs + $(RUSTC) -O -C opt-level=0 main.rs + $(RUSTC) -C opt-level=0 -O main.rs + $(RUSTC) -C opt-level=0 -C opt-level=2 main.rs + $(RUSTC) -C opt-level=2 -C opt-level=0 main.rs + + # Test that `-g` and `-C debuginfo` can be specified multiple times. + # The rightmost flag will be used over any previous flags. + $(RUSTC) -g -g main.rs + $(RUSTC) -g -C debuginfo=0 main.rs + $(RUSTC) -C debuginfo=0 -g main.rs + $(RUSTC) -C debuginfo=0 -C debuginfo=2 main.rs + $(RUSTC) -C debuginfo=2 -C debuginfo=0 main.rs diff --git a/src/test/run-make-fulldeps/override-aliased-flags/main.rs b/src/test/run-make-fulldeps/override-aliased-flags/main.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/src/test/run-make-fulldeps/override-aliased-flags/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/test/run-make-fulldeps/reproducible-build/Makefile b/src/test/run-make-fulldeps/reproducible-build/Makefile index ca76a5e5d77b6..a17ec212cfd58 100644 --- a/src/test/run-make-fulldeps/reproducible-build/Makefile +++ b/src/test/run-make-fulldeps/reproducible-build/Makefile @@ -1,4 +1,8 @@ -include ../tools.mk + +# ignore-musl +# Objects are reproducible but their path is not. + all: \ smoke \ debug \ diff --git a/src/test/run-make/rustc-macro-dep-files/Makefile b/src/test/run-make/rustc-macro-dep-files/Makefile index 0420a389168f1..a08a63fb44bf5 100644 --- a/src/test/run-make/rustc-macro-dep-files/Makefile +++ b/src/test/run-make/rustc-macro-dep-files/Makefile @@ -2,7 +2,10 @@ # FIXME(eddyb) provide `HOST_RUSTC` and `TARGET_RUSTC` # instead of hardcoding them everywhere they're needed. +ifeq ($(IS_MUSL_HOST),1) +ADDITIONAL_ARGS := $(RUSTFLAGS) +endif all: - $(BARE_RUSTC) foo.rs --out-dir $(TMPDIR) + $(BARE_RUSTC) $(ADDITIONAL_ARGS) foo.rs --out-dir $(TMPDIR) $(RUSTC) bar.rs --target $(TARGET) --emit dep-info $(CGREP) -v "proc-macro source" < $(TMPDIR)/bar.d diff --git a/src/test/run-make/wasm-export-all-symbols/Makefile b/src/test/run-make/wasm-export-all-symbols/Makefile index 039481215f0a6..15403d8d4109d 100644 --- a/src/test/run-make/wasm-export-all-symbols/Makefile +++ b/src/test/run-make/wasm-export-all-symbols/Makefile @@ -6,8 +6,14 @@ all: $(RUSTC) bar.rs --target wasm32-unknown-unknown $(RUSTC) foo.rs --target wasm32-unknown-unknown $(NODE) verify.js $(TMPDIR)/foo.wasm + $(RUSTC) main.rs --target wasm32-unknown-unknown + $(NODE) verify.js $(TMPDIR)/main.wasm $(RUSTC) bar.rs --target wasm32-unknown-unknown -O $(RUSTC) foo.rs --target wasm32-unknown-unknown -O $(NODE) verify.js $(TMPDIR)/foo.wasm + $(RUSTC) main.rs --target wasm32-unknown-unknown -O + $(NODE) verify.js $(TMPDIR)/main.wasm $(RUSTC) foo.rs --target wasm32-unknown-unknown -C lto $(NODE) verify.js $(TMPDIR)/foo.wasm + $(RUSTC) main.rs --target wasm32-unknown-unknown -C lto + $(NODE) verify.js $(TMPDIR)/main.wasm diff --git a/src/test/run-make/wasm-export-all-symbols/main.rs b/src/test/run-make/wasm-export-all-symbols/main.rs new file mode 100644 index 0000000000000..0edda7d7b8842 --- /dev/null +++ b/src/test/run-make/wasm-export-all-symbols/main.rs @@ -0,0 +1,3 @@ +extern crate bar; + +fn main() {} diff --git a/src/test/run-make/wasm-export-all-symbols/verify.js b/src/test/run-make/wasm-export-all-symbols/verify.js index 0f56fa45c223d..7b6fc7a45682b 100644 --- a/src/test/run-make/wasm-export-all-symbols/verify.js +++ b/src/test/run-make/wasm-export-all-symbols/verify.js @@ -16,7 +16,13 @@ for (const entry of list) { nexports += 1; } -if (nexports != 1) - throw new Error("should only have one function export"); if (my_exports.foo === undefined) throw new Error("`foo` wasn't defined"); + +if (my_exports.main === undefined) { + if (nexports != 1) + throw new Error("should only have one function export"); +} else { + if (nexports != 2) + throw new Error("should only have two function exports"); +} diff --git a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs index 699972c9a85bd..c6b33fbc75ee2 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom-derive-plugin-attr.rs @@ -14,7 +14,7 @@ use syntax::ast; use syntax::attr; use syntax::ext::base::{MultiDecorator, ExtCtxt, Annotatable}; use syntax::ext::build::AstBuilder; -use syntax::symbol::Symbol; +use syntax::symbol::{Symbol, sym}; use syntax::ptr::P; use syntax_ext::deriving::generic::{TraitDef, MethodDef, combine_substructure}; use syntax_ext::deriving::generic::{Substructure, Struct, EnumMatching}; @@ -71,7 +71,7 @@ fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span, }; fields.iter().fold(cx.expr_isize(trait_span, 0), |acc, ref item| { - if attr::contains_name(&item.attrs, "ignore") { + if attr::contains_name(&item.attrs, sym::ignore) { acc } else { cx.expr_binary(item.span, ast::BinOpKind::Add, acc, diff --git a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs index 76d0906f97c9a..40e0115c623ee 100644 --- a/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/issue-40001-plugin.rs @@ -23,7 +23,7 @@ use syntax::{ast, source_map}; #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { reg.register_late_lint_pass(box MissingWhitelistedAttrPass); - reg.register_attribute("whitelisted_attr".to_string(), Whitelisted); + reg.register_attribute(Symbol::intern("whitelisted_attr"), Whitelisted); } declare_lint! { @@ -48,7 +48,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingWhitelistedAttrPass { _ => cx.tcx.hir().expect_item_by_hir_id(cx.tcx.hir().get_parent_item(id)), }; - if !attr::contains_name(&item.attrs, "whitelisted_attr") { + if !attr::contains_name(&item.attrs, Symbol::intern("whitelisted_attr")) { cx.span_lint(MISSING_WHITELISTED_ATTR, span, "Missing 'whitelisted_attr' attribute"); } diff --git a/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs b/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs index f34e10218d455..8c7bd7222e73c 100644 --- a/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/run-pass-fulldeps/auxiliary/lint-for-crate.rs @@ -11,6 +11,7 @@ use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPass use rustc_plugin::Registry; use rustc::hir; use syntax::attr; +use syntax::symbol::Symbol; macro_rules! fake_lint_pass { ($struct:ident, $lints:expr, $($attr:expr),*) => { @@ -49,19 +50,19 @@ declare_lint!(CRATE_NOT_GREEN, Warn, "crate not marked with #![crate_green]"); fake_lint_pass! { PassOkay, lint_array!(CRATE_NOT_OKAY), // Single lint - "rustc_crate_okay" + Symbol::intern("rustc_crate_okay") } fake_lint_pass! { PassRedBlue, lint_array!(CRATE_NOT_RED, CRATE_NOT_BLUE), // Multiple lints - "rustc_crate_red", "rustc_crate_blue" + Symbol::intern("rustc_crate_red"), Symbol::intern("rustc_crate_blue") } fake_lint_pass! { PassGreyGreen, lint_array!(CRATE_NOT_GREY, CRATE_NOT_GREEN, ), // Trailing comma - "rustc_crate_grey", "rustc_crate_green" + Symbol::intern("rustc_crate_grey"), Symbol::intern("rustc_crate_green") } #[plugin_registrar] diff --git a/src/test/run-pass/async-await.rs b/src/test/run-pass/async-await.rs index e1b4328debd9a..49fd8b8b1ce27 100644 --- a/src/test/run-pass/async-await.rs +++ b/src/test/run-pass/async-await.rs @@ -1,7 +1,7 @@ // edition:2018 // aux-build:arc_wake.rs -#![feature(async_await, await_macro)] +#![feature(async_await)] extern crate arc_wake; @@ -46,14 +46,14 @@ impl Future for WakeOnceThenComplete { fn async_block(x: u8) -> impl Future { async move { - await!(wake_and_yield_once()); + wake_and_yield_once().await; x } } fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { async move { - await!(wake_and_yield_once()); + wake_and_yield_once().await; *x } } @@ -61,43 +61,43 @@ fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future impl Future { async move { let future = async { - await!(wake_and_yield_once()); + wake_and_yield_once().await; x }; - await!(future) + future.await } } fn async_closure(x: u8) -> impl Future { (async move |x: u8| -> u8 { - await!(wake_and_yield_once()); + wake_and_yield_once().await; x })(x) } async fn async_fn(x: u8) -> u8 { - await!(wake_and_yield_once()); + wake_and_yield_once().await; x } async fn generic_async_fn(x: T) -> T { - await!(wake_and_yield_once()); + wake_and_yield_once().await; x } async fn async_fn_with_borrow(x: &u8) -> u8 { - await!(wake_and_yield_once()); + wake_and_yield_once().await; *x } async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 { - await!(wake_and_yield_once()); + wake_and_yield_once().await; *x } fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { async move { - await!(wake_and_yield_once()); + wake_and_yield_once().await; *x } } @@ -110,18 +110,18 @@ async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 { */ async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 { - await!(wake_and_yield_once()); + wake_and_yield_once().await; *x } fn async_fn_with_internal_borrow(y: u8) -> impl Future { async move { - await!(async_fn_with_borrow_named_lifetime(&y)) + async_fn_with_borrow_named_lifetime(&y).await } } unsafe async fn unsafe_async_fn(x: u8) -> u8 { - await!(wake_and_yield_once()); + wake_and_yield_once().await; x } @@ -134,7 +134,7 @@ trait Bar { impl Foo { async fn async_method(x: u8) -> u8 { unsafe { - await!(unsafe_async_fn(x)) + unsafe_async_fn(x).await } } } @@ -165,7 +165,7 @@ fn main() { ($($fn_name:expr,)*) => { $( test_future_yields_once_then_returns(|x| { async move { - await!($fn_name(&x)) + $fn_name(&x).await } }); )* } @@ -181,7 +181,7 @@ fn main() { Foo::async_method, |x| { async move { - unsafe { await!(unsafe_async_fn(x)) } + unsafe { unsafe_async_fn(x).await } } }, } @@ -192,7 +192,7 @@ fn main() { async_fn_with_impl_future_named_lifetime, |x| { async move { - await!(async_fn_multiple_args_named_lifetime(x, x)) + async_fn_multiple_args_named_lifetime(x, x).await } }, } diff --git a/src/test/run-pass/await-macro.rs b/src/test/run-pass/await-macro.rs new file mode 100644 index 0000000000000..e1b4328debd9a --- /dev/null +++ b/src/test/run-pass/await-macro.rs @@ -0,0 +1,199 @@ +// edition:2018 +// aux-build:arc_wake.rs + +#![feature(async_await, await_macro)] + +extern crate arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool); + +fn wake_and_yield_once() -> WakeOnceThenComplete { WakeOnceThenComplete(false) } + +impl Future for WakeOnceThenComplete { + type Output = (); + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.0 { + Poll::Ready(()) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn async_block(x: u8) -> impl Future { + async move { + await!(wake_and_yield_once()); + x + } +} + +fn async_block_with_borrow_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + await!(wake_and_yield_once()); + *x + } +} + +fn async_nonmove_block(x: u8) -> impl Future { + async move { + let future = async { + await!(wake_and_yield_once()); + x + }; + await!(future) + } +} + +fn async_closure(x: u8) -> impl Future { + (async move |x: u8| -> u8 { + await!(wake_and_yield_once()); + x + })(x) +} + +async fn async_fn(x: u8) -> u8 { + await!(wake_and_yield_once()); + x +} + +async fn generic_async_fn(x: T) -> T { + await!(wake_and_yield_once()); + x +} + +async fn async_fn_with_borrow(x: &u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + +async fn async_fn_with_borrow_named_lifetime<'a>(x: &'a u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + +fn async_fn_with_impl_future_named_lifetime<'a>(x: &'a u8) -> impl Future + 'a { + async move { + await!(wake_and_yield_once()); + *x + } +} + +/* FIXME(cramertj) support when `existential type T<'a, 'b>:;` works +async fn async_fn_multiple_args(x: &u8, _y: &u8) -> u8 { + await!(wake_and_yield_once()); + *x +} +*/ + +async fn async_fn_multiple_args_named_lifetime<'a>(x: &'a u8, _y: &'a u8) -> u8 { + await!(wake_and_yield_once()); + *x +} + +fn async_fn_with_internal_borrow(y: u8) -> impl Future { + async move { + await!(async_fn_with_borrow_named_lifetime(&y)) + } +} + +unsafe async fn unsafe_async_fn(x: u8) -> u8 { + await!(wake_and_yield_once()); + x +} + +struct Foo; + +trait Bar { + fn foo() {} +} + +impl Foo { + async fn async_method(x: u8) -> u8 { + unsafe { + await!(unsafe_async_fn(x)) + } + } +} + +fn test_future_yields_once_then_returns(f: F) +where + F: FnOnce(u8) -> Fut, + Fut: Future, +{ + let mut fut = Box::pin(f(9)); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + assert_eq!(0, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Pending, fut.as_mut().poll(&mut cx)); + assert_eq!(1, counter.wakes.load(atomic::Ordering::SeqCst)); + assert_eq!(Poll::Ready(9), fut.as_mut().poll(&mut cx)); +} + +fn main() { + macro_rules! test { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns($fn_name); + )* } + } + + macro_rules! test_with_borrow { + ($($fn_name:expr,)*) => { $( + test_future_yields_once_then_returns(|x| { + async move { + await!($fn_name(&x)) + } + }); + )* } + } + + test! { + async_block, + async_nonmove_block, + async_closure, + async_fn, + generic_async_fn, + async_fn_with_internal_borrow, + Foo::async_method, + |x| { + async move { + unsafe { await!(unsafe_async_fn(x)) } + } + }, + } + test_with_borrow! { + async_block_with_borrow_named_lifetime, + async_fn_with_borrow, + async_fn_with_borrow_named_lifetime, + async_fn_with_impl_future_named_lifetime, + |x| { + async move { + await!(async_fn_multiple_args_named_lifetime(x, x)) + } + }, + } +} diff --git a/src/test/run-pass/consts/const-ptr-nonnull.rs b/src/test/run-pass/consts/const-ptr-nonnull.rs index 91624e92fbe75..c5b9d837b47a8 100644 --- a/src/test/run-pass/consts/const-ptr-nonnull.rs +++ b/src/test/run-pass/consts/const-ptr-nonnull.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(const_ptr_nonnull)] - use std::ptr::NonNull; const DANGLING: NonNull = NonNull::dangling(); diff --git a/src/test/run-pass/generator/issue-59972.rs b/src/test/run-pass/generator/issue-59972.rs new file mode 100644 index 0000000000000..995da4fb3ff3c --- /dev/null +++ b/src/test/run-pass/generator/issue-59972.rs @@ -0,0 +1,23 @@ +// compile-flags: --edition=2018 + +#![feature(async_await, await_macro)] + +pub enum Uninhabited { } + +fn uninhabited_async() -> Uninhabited { + unreachable!() +} + +async fn noop() { } + +#[allow(unused)] +async fn contains_never() { + let error = uninhabited_async(); + await!(noop()); + let error2 = error; +} + +#[allow(unused_must_use)] +fn main() { + contains_never(); +} diff --git a/src/test/run-pass/if-ret.stderr b/src/test/run-pass/if-ret.stderr new file mode 100644 index 0000000000000..a64281833e5cb --- /dev/null +++ b/src/test/run-pass/if-ret.stderr @@ -0,0 +1,8 @@ +warning: unreachable block in `if` expression + --> $DIR/if-ret.rs:4:24 + | +LL | fn foo() { if (return) { } } + | ^^^ + | + = note: #[warn(unreachable_code)] on by default + diff --git a/src/test/run-pass/impl-trait-in-bindings.rs b/src/test/run-pass/impl-trait-in-bindings.rs index 9a1f53b48933a..1e3a641b7cf94 100644 --- a/src/test/run-pass/impl-trait-in-bindings.rs +++ b/src/test/run-pass/impl-trait-in-bindings.rs @@ -1,4 +1,5 @@ #![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash use std::fmt::Debug; diff --git a/src/test/run-pass/impl-trait-in-bindings.stderr b/src/test/run-pass/impl-trait-in-bindings.stderr new file mode 100644 index 0000000000000..4896deb9d5c91 --- /dev/null +++ b/src/test/run-pass/impl-trait-in-bindings.stderr @@ -0,0 +1,6 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/impl-trait-in-bindings.rs:1:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + diff --git a/src/test/run-pass/impl-trait/lifetimes.rs b/src/test/run-pass/impl-trait/lifetimes.rs index 5a21e1dd81759..9a9843375e4c5 100644 --- a/src/test/run-pass/impl-trait/lifetimes.rs +++ b/src/test/run-pass/impl-trait/lifetimes.rs @@ -1,6 +1,7 @@ // run-pass #![allow(warnings)] +#![feature(generators)] use std::fmt::Debug; @@ -112,6 +113,11 @@ impl<'unnecessary_lifetime> MyVec { fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator { self.0.iter().flat_map(|inner_vec| inner_vec.iter()) } + + fn generator_doesnt_capture_unnecessary_lifetime<'s: 's>() -> impl Sized { + || yield + } } + fn main() {} diff --git a/src/test/run-pass/issue-55809.rs b/src/test/run-pass/issue-55809.rs index 12be6582a21e8..b7e60b773b416 100644 --- a/src/test/run-pass/issue-55809.rs +++ b/src/test/run-pass/issue-55809.rs @@ -1,7 +1,7 @@ // edition:2018 // run-pass -#![feature(async_await, await_macro)] +#![feature(async_await)] trait Foo { } @@ -14,15 +14,15 @@ async fn foo_async(_v: T) -> u8 where T: Foo { } async fn bad(v: T) -> u8 where T: Foo { - await!(foo_async(v)) + foo_async(v).await } async fn async_main() { let mut v = (); - let _ = await!(bad(&mut v)); - let _ = await!(foo_async(&mut v)); - let _ = await!(bad(v)); + let _ = bad(&mut v).await; + let _ = foo_async(&mut v).await; + let _ = bad(v).await; } fn main() { diff --git a/src/test/rustdoc/assoc-consts-version.rs b/src/test/rustdoc/assoc-consts-version.rs index c561269cf9a85..6060bc0a6fd5c 100644 --- a/src/test/rustdoc/assoc-consts-version.rs +++ b/src/test/rustdoc/assoc-consts-version.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - #![crate_name = "foo"] #![feature(staged_api)] @@ -10,7 +8,8 @@ pub struct SomeStruct; impl SomeStruct { - // @has 'foo/struct.SomeStruct.html' '//*[@id="associatedconstant.SOME_CONST"]//div[@class="since"]' '1.1.2' + // @has 'foo/struct.SomeStruct.html' \ + // '//*[@id="associatedconstant.SOME_CONST"]//span[@class="since"]' '1.1.2' #[stable(since="1.1.2", feature="rust2")] pub const SOME_CONST: usize = 0; } diff --git a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs index c83e7bdb9983e..039124f31ff42 100644 --- a/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/attr-plugin-test.rs @@ -8,14 +8,14 @@ extern crate syntax; extern crate rustc; extern crate rustc_plugin; +use syntax::symbol::Symbol; use syntax::feature_gate::AttributeType; use rustc_plugin::Registry; - #[plugin_registrar] pub fn plugin_registrar(reg: &mut Registry) { - reg.register_attribute("foo".to_owned(), AttributeType::Normal); - reg.register_attribute("bar".to_owned(), AttributeType::CrateLevel); - reg.register_attribute("baz".to_owned(), AttributeType::Whitelisted); + reg.register_attribute(Symbol::intern("foo"), AttributeType::Normal); + reg.register_attribute(Symbol::intern("bar"), AttributeType::CrateLevel); + reg.register_attribute(Symbol::intern("baz"), AttributeType::Whitelisted); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index e8f1d2eedf559..7656b15721ada 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -11,6 +11,7 @@ use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPass use rustc_plugin::Registry; use rustc::hir; use syntax::attr; +use syntax::symbol::Symbol; declare_lint! { CRATE_NOT_OKAY, @@ -22,7 +23,7 @@ declare_lint_pass!(Pass => [CRATE_NOT_OKAY]); impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass { fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) { - if !attr::contains_name(&krate.attrs, "crate_okay") { + if !attr::contains_name(&krate.attrs, Symbol::intern("crate_okay")) { cx.span_lint(CRATE_NOT_OKAY, krate.span, "crate is not marked with #![crate_okay]"); } diff --git a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs index 1d204e7bfcffa..0deb1bf091508 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs @@ -20,7 +20,7 @@ declare_lint_pass!(Pass => [TEST_LINT]); impl EarlyLintPass for Pass { fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name == "lintme" { + if it.ident.name.as_str() == "lintme" { cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); } } diff --git a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs index 182d2899da185..64664377cd943 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-tool-test.rs @@ -23,10 +23,10 @@ declare_lint_pass!(Pass => [TEST_LINT, TEST_GROUP]); impl EarlyLintPass for Pass { fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name == "lintme" { + if it.ident.name.as_str() == "lintme" { cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); } - if it.ident.name == "lintmetoo" { + if it.ident.name.as_str() == "lintmetoo" { cx.span_lint(TEST_GROUP, it.span, "item is named 'lintmetoo'"); } } diff --git a/src/test/ui/async-await/argument-patterns.rs b/src/test/ui/async-await/argument-patterns.rs new file mode 100644 index 0000000000000..3750c2bcb701a --- /dev/null +++ b/src/test/ui/async-await/argument-patterns.rs @@ -0,0 +1,30 @@ +// edition:2018 +// run-pass + +#![allow(unused_variables)] +#![deny(unused_mut)] +#![feature(async_await)] + +type A = Vec; + +async fn a(n: u32, mut vec: A) { + vec.push(n); +} + +async fn b(n: u32, ref mut vec: A) { + vec.push(n); +} + +async fn c(ref vec: A) { + vec.contains(&0); +} + +async fn d((a, mut b): (A, A)) { + b.push(1); +} + +async fn f((ref mut a, ref b): (A, A)) {} + +async fn g(((ref a, ref mut b), (ref mut c, ref d)): ((A, A), (A, A))) {} + +fn main() {} diff --git a/src/test/ui/async-await/auxiliary/issue-60674.rs b/src/test/ui/async-await/auxiliary/issue-60674.rs new file mode 100644 index 0000000000000..680c6e55e5668 --- /dev/null +++ b/src/test/ui/async-await/auxiliary/issue-60674.rs @@ -0,0 +1,12 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn attr(_args: TokenStream, input: TokenStream) -> TokenStream { + println!("{}", input); + TokenStream::new() +} diff --git a/src/test/ui/async-await/drop-order-for-async-fn-parameters-by-ref-binding.rs b/src/test/ui/async-await/drop-order-for-async-fn-parameters-by-ref-binding.rs new file mode 100644 index 0000000000000..c2b59eecb9993 --- /dev/null +++ b/src/test/ui/async-await/drop-order-for-async-fn-parameters-by-ref-binding.rs @@ -0,0 +1,271 @@ +// aux-build:arc_wake.rs +// edition:2018 +// run-pass + +#![allow(unused_variables)] +#![feature(async_await, await_macro)] + +// Test that the drop order for parameters in a fn and async fn matches up. Also test that +// parameters (used or unused) are not dropped until the async fn completes execution. +// See also #54716. + +extern crate arc_wake; + +use arc_wake::ArcWake; +use std::cell::RefCell; +use std::future::Future; +use std::marker::PhantomData; +use std::sync::Arc; +use std::rc::Rc; +use std::task::Context; + +struct EmptyWaker; + +impl ArcWake for EmptyWaker { + fn wake(self: Arc) {} +} + +#[derive(Debug, Eq, PartialEq)] +enum DropOrder { + Function, + Val(&'static str), +} + +type DropOrderListPtr = Rc>>; + +struct D(&'static str, DropOrderListPtr); + +impl Drop for D { + fn drop(&mut self) { + self.1.borrow_mut().push(DropOrder::Val(self.0)); + } +} + +/// Check that unused bindings are dropped after the function is polled. +async fn foo_async(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foo_sync(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns are dropped after the function is polled. +async fn bar_async(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn bar_sync(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore patterns within more complex patterns are dropped after the function +/// is polled. +async fn baz_async((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn baz_sync((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); +} + +/// Check that underscore and unused bindings within and outwith more complex patterns are dropped +/// after the function is polled. +async fn foobar_async(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +fn foobar_sync(ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); +} + +struct Foo; + +impl Foo { + /// Check that unused bindings are dropped after the method is polled. + async fn foo_async(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method is polled. + async fn bar_async(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// is polled. + async fn baz_async((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync((ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method is polled. + async fn foobar_async( + ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync( + ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +struct Bar<'a>(PhantomData<&'a ()>); + +impl<'a> Bar<'a> { + /// Check that unused bindings are dropped after the method with self is polled. + async fn foo_async(&'a self, ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foo_sync(&'a self, ref mut x: D, ref mut _y: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns are dropped after the method with self is polled. + async fn bar_async(&'a self, ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn bar_sync(&'a self, ref mut x: D, _: D) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore patterns within more complex patterns are dropped after the method + /// with self is polled. + async fn baz_async(&'a self, (ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn baz_sync(&'a self, (ref mut x, _): (D, D)) { + x.1.borrow_mut().push(DropOrder::Function); + } + + /// Check that underscore and unused bindings within and outwith more complex patterns are + /// dropped after the method with self is polled. + async fn foobar_async( + &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } + + fn foobar_sync( + &'a self, ref mut x: D, (ref mut a, _, ref mut _c): (D, D, D), _: D, ref mut _y: D, + ) { + x.1.borrow_mut().push(DropOrder::Function); + } +} + +fn assert_drop_order_after_poll>( + f: impl FnOnce(DropOrderListPtr) -> Fut, + g: impl FnOnce(DropOrderListPtr), +) { + let empty = Arc::new(EmptyWaker); + let waker = ArcWake::into_waker(empty); + let mut cx = Context::from_waker(&waker); + + let actual_order = Rc::new(RefCell::new(Vec::new())); + let mut fut = Box::pin(f(actual_order.clone())); + let _ = fut.as_mut().poll(&mut cx); + + let expected_order = Rc::new(RefCell::new(Vec::new())); + g(expected_order.clone()); + + assert_eq!(*actual_order.borrow(), *expected_order.borrow()); +} + +fn main() { + // Free functions (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| bar_async(D("x", l.clone()), D("_", l.clone())), + |l| bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods w/out self (see doc comment on function for what it tests). + assert_drop_order_after_poll(|l| Foo::foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| Foo::foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| Foo::bar_async(D("x", l.clone()), D("_", l.clone())), + |l| Foo::bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| Foo::baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| Foo::baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + Foo::foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + Foo::foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); + + // Methods (see doc comment on function for what it tests). + let b = Bar(Default::default()); + assert_drop_order_after_poll(|l| b.foo_async(D("x", l.clone()), D("_y", l.clone())), + |l| b.foo_sync(D("x", l.clone()), D("_y", l.clone()))); + assert_drop_order_after_poll(|l| b.bar_async(D("x", l.clone()), D("_", l.clone())), + |l| b.bar_sync(D("x", l.clone()), D("_", l.clone()))); + assert_drop_order_after_poll(|l| b.baz_async((D("x", l.clone()), D("_", l.clone()))), + |l| b.baz_sync((D("x", l.clone()), D("_", l.clone())))); + assert_drop_order_after_poll( + |l| { + b.foobar_async( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + |l| { + b.foobar_sync( + D("x", l.clone()), + (D("a", l.clone()), D("_", l.clone()), D("_c", l.clone())), + D("_", l.clone()), + D("_y", l.clone()), + ) + }, + ); +} diff --git a/src/test/ui/async-await/drop-order-locals-are-hidden.rs b/src/test/ui/async-await/drop-order-locals-are-hidden.rs index 10dc5e27f6f9f..bcdb8878eb5d2 100644 --- a/src/test/ui/async-await/drop-order-locals-are-hidden.rs +++ b/src/test/ui/async-await/drop-order-locals-are-hidden.rs @@ -8,4 +8,9 @@ async fn foobar_async(x: u32, (a, _, _c): (u32, u32, u32), _: u32, _y: u32) { assert_eq!(__arg2, 4); //~ ERROR cannot find value `__arg2` in this scope [E0425] } +async fn baz_async(ref mut x: u32, ref y: u32) { + assert_eq!(__arg0, 1); //~ ERROR cannot find value `__arg0` in this scope [E0425] + assert_eq!(__arg1, 2); //~ ERROR cannot find value `__arg1` in this scope [E0425] +} + fn main() {} diff --git a/src/test/ui/async-await/drop-order-locals-are-hidden.stderr b/src/test/ui/async-await/drop-order-locals-are-hidden.stderr index ca0da6b7c962a..484e1f4f4269e 100644 --- a/src/test/ui/async-await/drop-order-locals-are-hidden.stderr +++ b/src/test/ui/async-await/drop-order-locals-are-hidden.stderr @@ -10,6 +10,18 @@ error[E0425]: cannot find value `__arg2` in this scope LL | assert_eq!(__arg2, 4); | ^^^^^^ not found in this scope -error: aborting due to 2 previous errors +error[E0425]: cannot find value `__arg0` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:12:16 + | +LL | assert_eq!(__arg0, 1); + | ^^^^^^ not found in this scope + +error[E0425]: cannot find value `__arg1` in this scope + --> $DIR/drop-order-locals-are-hidden.rs:13:16 + | +LL | assert_eq!(__arg1, 2); + | ^^^^^^ not found in this scope + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/async-await/issue-60674.rs b/src/test/ui/async-await/issue-60674.rs new file mode 100644 index 0000000000000..ecb80803383b4 --- /dev/null +++ b/src/test/ui/async-await/issue-60674.rs @@ -0,0 +1,20 @@ +// aux-build:issue-60674.rs +// compile-pass +// edition:2018 +#![feature(async_await)] + +// This is a regression test that ensures that `mut` patterns are not lost when provided as input +// to a proc macro. + +extern crate issue_60674; + +#[issue_60674::attr] +async fn f(mut x: u8) {} + +#[issue_60674::attr] +async fn g((mut x, y, mut z): (u8, u8, u8)) {} + +#[issue_60674::attr] +async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) {} + +fn main() {} diff --git a/src/test/ui/async-await/issue-60674.stdout b/src/test/ui/async-await/issue-60674.stdout new file mode 100644 index 0000000000000..86c3591b3afc0 --- /dev/null +++ b/src/test/ui/async-await/issue-60674.stdout @@ -0,0 +1,3 @@ +async fn f(mut x: u8) { } +async fn g((mut x, y, mut z): (u8, u8, u8)) { } +async fn g(mut x: u8, (a, mut b, c): (u8, u8, u8), y: u8) { } diff --git a/src/test/ui/async-await/mutable-arguments.rs b/src/test/ui/async-await/mutable-arguments.rs deleted file mode 100644 index 4d6dba74097ca..0000000000000 --- a/src/test/ui/async-await/mutable-arguments.rs +++ /dev/null @@ -1,10 +0,0 @@ -// edition:2018 -// run-pass - -#![feature(async_await)] - -async fn foo(n: u32, mut vec: Vec) { - vec.push(n); -} - -fn main() {} diff --git a/src/test/ui/attr-eq-token-tree.stderr b/src/test/ui/attr-eq-token-tree.stderr index aae25b2721e4d..571779dfa1ae7 100644 --- a/src/test/ui/attr-eq-token-tree.stderr +++ b/src/test/ui/attr-eq-token-tree.stderr @@ -1,8 +1,8 @@ error: unexpected token: `!` - --> $DIR/attr-eq-token-tree.rs:3:11 + --> $DIR/attr-eq-token-tree.rs:3:13 | LL | #[my_attr = !] - | ^ + | ^ error: aborting due to previous error diff --git a/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.rs new file mode 100644 index 0000000000000..c4f3f3edc486e --- /dev/null +++ b/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.rs @@ -0,0 +1,36 @@ +#![feature(async_await, await_macro)] +#![allow(non_camel_case_types)] +#![deny(keyword_idents)] + +mod outer_mod { + pub mod await { //~ ERROR `await` is a keyword in the 2018 edition + //~^ WARN this was previously accepted by the compiler + pub struct await; //~ ERROR `await` is a keyword in the 2018 edition + //~^ WARN this was previously accepted by the compiler + } +} +use outer_mod::await::await; //~ ERROR `await` is a keyword in the 2018 edition +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler +//~^^^ WARN this was previously accepted by the compiler + +struct Foo { await: () } +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler + +impl Foo { fn await() {} } +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler + +macro_rules! await { +//~^ ERROR `await` is a keyword in the 2018 edition +//~^^ WARN this was previously accepted by the compiler + () => {} +} + +fn main() { + match await { await => {} } //~ ERROR `await` is a keyword in the 2018 edition + //~^ ERROR `await` is a keyword in the 2018 edition + //~^^ WARN this was previously accepted by the compiler + //~^^^ WARN this was previously accepted by the compiler +} diff --git a/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.stderr new file mode 100644 index 0000000000000..067ecd6a5138d --- /dev/null +++ b/src/test/ui/await-keyword/2015-edition-error-in-non-macro-position.stderr @@ -0,0 +1,88 @@ +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:6:13 + | +LL | pub mod await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | +note: lint level defined here + --> $DIR/2015-edition-error-in-non-macro-position.rs:3:9 + | +LL | #![deny(keyword_idents)] + | ^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:8:20 + | +LL | pub struct await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:12:16 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:12:23 + | +LL | use outer_mod::await::await; + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:17:14 + | +LL | struct Foo { await: () } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:21:15 + | +LL | impl Foo { fn await() {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:25:14 + | +LL | macro_rules! await { + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:32:11 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: `await` is a keyword in the 2018 edition + --> $DIR/2015-edition-error-in-non-macro-position.rs:32:19 + | +LL | match await { await => {} } + | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! + = note: for more information, see issue #49716 + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs b/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs deleted file mode 100644 index 92c60e7d6eed0..0000000000000 --- a/src/test/ui/await-keyword/2015-edition-no-warnings-with-feature-gate.rs +++ /dev/null @@ -1,16 +0,0 @@ -// compile-pass - -#![feature(async_await)] -#![allow(non_camel_case_types)] -#![deny(keyword_idents)] - -mod outer_mod { - pub mod await { - pub struct await; - } -} -use outer_mod::await::await; - -fn main() { - match await { await => {} } -} diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs new file mode 100644 index 0000000000000..b2e8e4be17244 --- /dev/null +++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.rs @@ -0,0 +1,27 @@ +// edition:2018 + +#![allow(non_camel_case_types)] +#![feature(async_await, await_macro)] + +mod outer_mod { + pub mod await { //~ ERROR expected identifier, found reserved keyword `await` + pub struct await; //~ ERROR expected identifier, found reserved keyword `await` + } +} +use self::outer_mod::await::await; //~ ERROR expected identifier, found reserved keyword `await` +//~^ ERROR expected identifier, found reserved keyword `await` + +struct Foo { await: () } +//~^ ERROR expected identifier, found reserved keyword `await` + +impl Foo { fn await() {} } +//~^ ERROR expected identifier, found reserved keyword `await` + +macro_rules! await { +//~^ ERROR expected identifier, found reserved keyword `await` + () => {} +} + +fn main() { + match await { await => () } //~ ERROR expected `!`, found `{` +} diff --git a/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr new file mode 100644 index 0000000000000..076a31bd9ced6 --- /dev/null +++ b/src/test/ui/await-keyword/2018-edition-error-in-non-macro-position.stderr @@ -0,0 +1,80 @@ +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:7:13 + | +LL | pub mod await { + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub mod r#await { + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:8:20 + | +LL | pub struct await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub struct r#await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:11:22 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | use self::outer_mod::r#await::await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:11:29 + | +LL | use self::outer_mod::await::await; + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | use self::outer_mod::await::r#await; + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:14:14 + | +LL | struct Foo { await: () } + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | struct Foo { r#await: () } + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:17:15 + | +LL | impl Foo { fn await() {} } + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | impl Foo { fn r#await() {} } + | ^^^^^^^ + +error: expected identifier, found reserved keyword `await` + --> $DIR/2018-edition-error-in-non-macro-position.rs:20:14 + | +LL | macro_rules! await { + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | macro_rules! r#await { + | ^^^^^^^ + +error: expected `!`, found `{` + --> $DIR/2018-edition-error-in-non-macro-position.rs:26:17 + | +LL | match await { await => () } + | ----- ^ expected `!` + | | + | while parsing this match expression + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/await-keyword/2018-edition-error.rs b/src/test/ui/await-keyword/2018-edition-error.rs index 7ba3382ddf129..e0b2962ce9791 100644 --- a/src/test/ui/await-keyword/2018-edition-error.rs +++ b/src/test/ui/await-keyword/2018-edition-error.rs @@ -2,14 +2,13 @@ #![allow(non_camel_case_types)] mod outer_mod { - pub mod await { //~ ERROR `await` is a keyword - pub struct await; //~ ERROR `await` is a keyword + pub mod await { //~ ERROR expected identifier + pub struct await; //~ ERROR expected identifier } } -use self::outer_mod::await::await; //~ ERROR `await` is a keyword - //~^ ERROR `await` is a keyword +use self::outer_mod::await::await; //~ ERROR expected identifier + //~^ ERROR expected identifier, found reserved keyword `await` fn main() { - match await { await => () } //~ ERROR `await` is a keyword - //~^ ERROR `await` is a keyword + match await { await => () } //~ ERROR expected `!`, found `{` } diff --git a/src/test/ui/await-keyword/2018-edition-error.stderr b/src/test/ui/await-keyword/2018-edition-error.stderr index 67ff6c5675abf..c8bf9b42ca545 100644 --- a/src/test/ui/await-keyword/2018-edition-error.stderr +++ b/src/test/ui/await-keyword/2018-edition-error.stderr @@ -1,38 +1,50 @@ -error[E0721]: `await` is a keyword in the 2018 edition +error: expected identifier, found reserved keyword `await` --> $DIR/2018-edition-error.rs:5:13 | LL | pub mod await { - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub mod r#await { + | ^^^^^^^ -error[E0721]: `await` is a keyword in the 2018 edition +error: expected identifier, found reserved keyword `await` --> $DIR/2018-edition-error.rs:6:20 | LL | pub struct await; - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | pub struct r#await; + | ^^^^^^^ -error[E0721]: `await` is a keyword in the 2018 edition +error: expected identifier, found reserved keyword `await` --> $DIR/2018-edition-error.rs:9:22 | LL | use self::outer_mod::await::await; - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers + | +LL | use self::outer_mod::r#await::await; + | ^^^^^^^ -error[E0721]: `await` is a keyword in the 2018 edition +error: expected identifier, found reserved keyword `await` --> $DIR/2018-edition-error.rs:9:29 | LL | use self::outer_mod::await::await; - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` - -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:13:11 + | ^^^^^ expected identifier, found reserved keyword +help: you can escape reserved keywords to use them as identifiers | -LL | match await { await => () } - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` +LL | use self::outer_mod::await::r#await; + | ^^^^^^^ -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/2018-edition-error.rs:13:19 +error: expected `!`, found `{` + --> $DIR/2018-edition-error.rs:13:17 | LL | match await { await => () } - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | ----- ^ expected `!` + | | + | while parsing this match expression -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs b/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs deleted file mode 100644 index 52d32c8351080..0000000000000 --- a/src/test/ui/await-keyword/2018-edition-no-error-with-feature-gate.rs +++ /dev/null @@ -1,16 +0,0 @@ -// compile-pass -// edition:2018 - -#![allow(non_camel_case_types)] -#![feature(async_await)] - -mod outer_mod { - pub mod await { - pub struct await; - } -} -use self::outer_mod::await::await; - -fn main() { - match await { await => () } -} diff --git a/src/test/ui/await-keyword/post_expansion_error.rs b/src/test/ui/await-keyword/post_expansion_error.rs index 96dd48052def8..b4c899b0d0295 100644 --- a/src/test/ui/await-keyword/post_expansion_error.rs +++ b/src/test/ui/await-keyword/post_expansion_error.rs @@ -6,5 +6,5 @@ macro_rules! r#await { fn main() { await!() - //~^ ERROR `await` is a keyword + //~^ ERROR expected expression, found `)` } diff --git a/src/test/ui/await-keyword/post_expansion_error.stderr b/src/test/ui/await-keyword/post_expansion_error.stderr index 9483f77422759..0996c38b3b6c6 100644 --- a/src/test/ui/await-keyword/post_expansion_error.stderr +++ b/src/test/ui/await-keyword/post_expansion_error.stderr @@ -1,8 +1,8 @@ -error[E0721]: `await` is a keyword in the 2018 edition - --> $DIR/post_expansion_error.rs:8:5 +error: expected expression, found `)` + --> $DIR/post_expansion_error.rs:8:12 | LL | await!() - | ^^^^^ help: you can use a raw identifier to stay compatible: `r#await` + | ^ expected expression error: aborting due to previous error diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs new file mode 100644 index 0000000000000..c3f5e360fe280 --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs @@ -0,0 +1,11 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +// We should probably be able to infer the types here. However, this test is checking that we don't +// get an ICE in this case. It may be modified later to not be an error. + +struct Foo(pub [u8; NUM_BYTES]); + +fn main() { + let _ = Foo::<3>([1, 2, 3]); //~ ERROR type annotations needed +} diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr new file mode 100644 index 0000000000000..a0641bd2fdc96 --- /dev/null +++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr @@ -0,0 +1,15 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/cannot-infer-type-for-const-param.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + +error[E0282]: type annotations needed + --> $DIR/cannot-infer-type-for-const-param.rs:10:19 + | +LL | let _ = Foo::<3>([1, 2, 3]); + | ^ cannot infer type for `{integer}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/concrete-const-as-fn-arg.rs b/src/test/ui/const-generics/concrete-const-as-fn-arg.rs new file mode 100644 index 0000000000000..54981b77a2b84 --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-as-fn-arg.rs @@ -0,0 +1,14 @@ +// Test that a concrete const type i.e. A<2>, can be used as an argument type in a function +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct A; // ok + +fn with_concrete_const_arg(_: A<2>) -> u32 { 17 } + +fn main() { + let val: A<2> = A; + assert_eq!(with_concrete_const_arg(val), 17); +} diff --git a/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr b/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr new file mode 100644 index 0000000000000..955b319d70044 --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-as-fn-arg.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/concrete-const-as-fn-arg.rs:4:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/concrete-const-impl-method.rs b/src/test/ui/const-generics/concrete-const-impl-method.rs new file mode 100644 index 0000000000000..226ea4151806e --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-impl-method.rs @@ -0,0 +1,24 @@ +// Test that a method/associated non-method within an impl block of a concrete const type i.e. A<2>, +// is callable. +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +pub struct A; + +impl A<2> { + fn impl_method(&self) -> u32 { + 17 + } + + fn associated_non_method() -> u32 { + 17 + } +} + +fn main() { + let val: A<2> = A; + assert_eq!(val.impl_method(), 17); + assert_eq!(A::<2>::associated_non_method(), 17); +} diff --git a/src/test/ui/const-generics/concrete-const-impl-method.stderr b/src/test/ui/const-generics/concrete-const-impl-method.stderr new file mode 100644 index 0000000000000..3ce488c62755a --- /dev/null +++ b/src/test/ui/const-generics/concrete-const-impl-method.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/concrete-const-impl-method.rs:5:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/const-expression-parameter.rs b/src/test/ui/const-generics/const-expression-parameter.rs index 662c7b767bae0..22c6c35162281 100644 --- a/src/test/ui/const-generics/const-expression-parameter.rs +++ b/src/test/ui/const-generics/const-expression-parameter.rs @@ -6,7 +6,7 @@ fn i32_identity() -> i32 { } fn foo_a() { - i32_identity::<-1>(); //~ ERROR expected identifier, found `<-` + i32_identity::<-1>(); // ok } fn foo_b() { diff --git a/src/test/ui/const-generics/const-expression-parameter.stderr b/src/test/ui/const-generics/const-expression-parameter.stderr index 2f7a80f0c8fde..c255127c28079 100644 --- a/src/test/ui/const-generics/const-expression-parameter.stderr +++ b/src/test/ui/const-generics/const-expression-parameter.stderr @@ -1,9 +1,3 @@ -error: expected identifier, found `<-` - --> $DIR/const-expression-parameter.rs:9:19 - | -LL | i32_identity::<-1>(); - | ^^ expected identifier - error: expected one of `,` or `>`, found `+` --> $DIR/const-expression-parameter.rs:13:22 | @@ -16,5 +10,5 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 188b5dce31ea8..2c81681b85e7d 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,12 +1,12 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -fn foo(_: &T) { - //~^ ERROR type parameters must be declared prior to const parameters -} - fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters } +fn foo(_: &T) { + //~^ ERROR type parameters must be declared prior to const parameters +} + fn main() {} diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index 78f129e79ea24..33f981d1eba9b 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -4,17 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error: type parameters must be declared prior to const parameters +error: lifetime parameters must be declared prior to const parameters --> $DIR/const-param-before-other-params.rs:4:21 | -LL | fn foo(_: &T) { - | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` +LL | fn bar(_: &'a ()) { + | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` -error: lifetime parameters must be declared prior to const parameters +error: type parameters must be declared prior to const parameters --> $DIR/const-param-before-other-params.rs:8:21 | -LL | fn bar(_: &'a ()) { - | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` +LL | fn foo(_: &T) { + | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.rs b/src/test/ui/const-generics/const-param-in-trait-ungated.rs new file mode 100644 index 0000000000000..8a81bcc1a80c8 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.rs @@ -0,0 +1,3 @@ +trait Trait {} //~ ERROR const generics are unstable + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr new file mode 100644 index 0000000000000..53bc973841416 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr @@ -0,0 +1,12 @@ +error[E0658]: const generics are unstable + --> $DIR/const-param-in-trait-ungated.rs:1:19 + | +LL | trait Trait {} + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-in-trait.rs b/src/test/ui/const-generics/const-param-in-trait.rs new file mode 100644 index 0000000000000..6e4f65fe6cac0 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait.rs @@ -0,0 +1,8 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait Trait {} + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-in-trait.stderr b/src/test/ui/const-generics/const-param-in-trait.stderr new file mode 100644 index 0000000000000..a48eefddaa844 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-in-trait.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/impl-const-generic-struct.rs b/src/test/ui/const-generics/impl-const-generic-struct.rs new file mode 100644 index 0000000000000..7a0c0f2be5d7a --- /dev/null +++ b/src/test/ui/const-generics/impl-const-generic-struct.rs @@ -0,0 +1,16 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct S; + +impl S<{X}> { + fn x() -> u32 { + X + } +} + +fn main() { + assert_eq!(S::<19>::x(), 19); +} diff --git a/src/test/ui/const-generics/impl-const-generic-struct.stderr b/src/test/ui/const-generics/impl-const-generic-struct.stderr new file mode 100644 index 0000000000000..d443e060a9747 --- /dev/null +++ b/src/test/ui/const-generics/impl-const-generic-struct.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/impl-const-generic-struct.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs b/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs new file mode 100644 index 0000000000000..b069cd89680c1 --- /dev/null +++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.rs @@ -0,0 +1,9 @@ +use std::convert::TryInto; + +struct S; + +fn main() { + let _: u32 = 5i32.try_into::<32>().unwrap(); //~ ERROR wrong number of const arguments + S.f::<0>(); //~ ERROR no method named `f` + S::<0>; //~ ERROR wrong number of const arguments +} diff --git a/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr new file mode 100644 index 0000000000000..8f3f91651edfb --- /dev/null +++ b/src/test/ui/const-generics/invalid-const-arg-for-type-param.stderr @@ -0,0 +1,25 @@ +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/invalid-const-arg-for-type-param.rs:6:34 + | +LL | let _: u32 = 5i32.try_into::<32>().unwrap(); + | ^^ unexpected const argument + +error[E0599]: no method named `f` found for type `S` in the current scope + --> $DIR/invalid-const-arg-for-type-param.rs:7:7 + | +LL | struct S; + | --------- method `f` not found for this +... +LL | S.f::<0>(); + | ^ + +error[E0107]: wrong number of const arguments: expected 0, found 1 + --> $DIR/invalid-const-arg-for-type-param.rs:8:9 + | +LL | S::<0>; + | ^ unexpected const argument + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0599. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issue-60263.rs b/src/test/ui/const-generics/issue-60263.rs new file mode 100644 index 0000000000000..70cbc242c41a5 --- /dev/null +++ b/src/test/ui/const-generics/issue-60263.rs @@ -0,0 +1,9 @@ +struct B; //~ ERROR const generics are unstable + +impl B<0> { + fn bug() -> Self { + panic!() + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issue-60263.stderr b/src/test/ui/const-generics/issue-60263.stderr new file mode 100644 index 0000000000000..ab1b9e4a7cd86 --- /dev/null +++ b/src/test/ui/const-generics/issue-60263.stderr @@ -0,0 +1,12 @@ +error[E0658]: const generics are unstable + --> $DIR/issue-60263.rs:1:16 + | +LL | struct B; + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr index 603efe449f143..e45ce65d8bb35 100644 --- a/src/test/ui/consts/const-eval/unused-broken-const.stderr +++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr @@ -1,5 +1,3 @@ -warning: due to multiple output types requested, the explicitly specified output file name will be adapted for each output type - error: any use of this value will cause an error --> $DIR/unused-broken-const.rs:5:18 | diff --git a/src/test/ui/emit-artifact-notifications.nll.stderr b/src/test/ui/emit-artifact-notifications.nll.stderr new file mode 100644 index 0000000000000..347d9aeac2307 --- /dev/null +++ b/src/test/ui/emit-artifact-notifications.nll.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications.nll/libemit_artifact_notifications.rmeta"} diff --git a/src/test/ui/emit-artifact-notifications.rs b/src/test/ui/emit-artifact-notifications.rs new file mode 100644 index 0000000000000..c2c930c8b1bae --- /dev/null +++ b/src/test/ui/emit-artifact-notifications.rs @@ -0,0 +1,6 @@ +// compile-flags:--emit=metadata --error-format=json -Z emit-artifact-notifications +// compile-pass + +// A very basic test for the emission of artifact notifications in JSON output. + +fn main() {} diff --git a/src/test/ui/emit-artifact-notifications.stderr b/src/test/ui/emit-artifact-notifications.stderr new file mode 100644 index 0000000000000..56c977181ff51 --- /dev/null +++ b/src/test/ui/emit-artifact-notifications.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/emit-artifact-notifications/libemit_artifact_notifications.rmeta"} diff --git a/src/test/ui/emit-directives.rs b/src/test/ui/emit-directives.rs deleted file mode 100644 index 088280e358ae7..0000000000000 --- a/src/test/ui/emit-directives.rs +++ /dev/null @@ -1,12 +0,0 @@ -// ignore-tidy-linelength -// compile-flags:--emit=metadata --error-format=json -Z emit-directives -// compile-pass -// -// Normalization is required to eliminated minor path and filename differences -// across platforms. -// normalize-stderr-test: "metadata file written: .*/emit-directives" -> "metadata file written: .../emit-directives" -// normalize-stderr-test: "emit-directives(\.\w*)?/a(\.\w*)?" -> "emit-directives/a" - -// A very basic test for the emission of build directives in JSON output. - -fn main() {} diff --git a/src/test/ui/emit-directives.stderr b/src/test/ui/emit-directives.stderr deleted file mode 100644 index b8a4b96f4bf25..0000000000000 --- a/src/test/ui/emit-directives.stderr +++ /dev/null @@ -1 +0,0 @@ -{"directive":"metadata file written: .../emit-directives/a"} diff --git a/src/test/ui/error-codes/E0423.stderr b/src/test/ui/error-codes/E0423.stderr index 5cb7121a0d1c3..ec240003f9182 100644 --- a/src/test/ui/error-codes/E0423.stderr +++ b/src/test/ui/error-codes/E0423.stderr @@ -3,7 +3,7 @@ error: struct literals are not allowed here | LL | if let S { x: _x, y: 2 } = S { x: 1, y: 2 } { println!("Ok"); } | ^^^^^^^^^^^^^^^^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | if let S { x: _x, y: 2 } = (S { x: 1, y: 2 }) { println!("Ok"); } | ^ ^ @@ -19,7 +19,7 @@ error: struct literals are not allowed here | LL | for _ in std::ops::Range { start: 0, end: 10 } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | for _ in (std::ops::Range { start: 0, end: 10 }) {} | ^ ^ diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr index 03867a8e43b10..359725a41c105 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision.stderr @@ -1,8 +1,8 @@ error: unexpected token: `,` - --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:15 + --> $DIR/exclusive_range_pattern_syntax_collision.rs:5:17 | LL | [_, 99.., _] => {}, - | ^^ + | ^ error: aborting due to previous error diff --git a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr index 5ac435bf011e4..8f849d7b3f87c 100644 --- a/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr +++ b/src/test/ui/exclusive-range/exclusive_range_pattern_syntax_collision2.stderr @@ -1,8 +1,8 @@ error: unexpected token: `]` - --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:15 + --> $DIR/exclusive_range_pattern_syntax_collision2.rs:5:17 | LL | [_, 99..] => {}, - | ^^ + | ^ error: aborting due to previous error diff --git a/src/test/ui/existential-type/issue-60371.rs b/src/test/ui/existential-type/issue-60371.rs new file mode 100644 index 0000000000000..f9def11d1932d --- /dev/null +++ b/src/test/ui/existential-type/issue-60371.rs @@ -0,0 +1,15 @@ +trait Bug { + type Item: Bug; + + const FUN: fn() -> Self::Item; +} + +impl Bug for &() { + existential type Item: Bug; //~ ERROR existential types are unstable + //~^ ERROR the trait bound `(): Bug` is not satisfied + //~^^ ERROR could not find defining uses + + const FUN: fn() -> Self::Item = || (); +} + +fn main() {} diff --git a/src/test/ui/existential-type/issue-60371.stderr b/src/test/ui/existential-type/issue-60371.stderr new file mode 100644 index 0000000000000..2560e01047aad --- /dev/null +++ b/src/test/ui/existential-type/issue-60371.stderr @@ -0,0 +1,29 @@ +error[E0658]: existential types are unstable + --> $DIR/issue-60371.rs:8:5 + | +LL | existential type Item: Bug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/34511 + = help: add #![feature(existential_type)] to the crate attributes to enable + +error[E0277]: the trait bound `(): Bug` is not satisfied + --> $DIR/issue-60371.rs:8:5 + | +LL | existential type Item: Bug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bug` is not implemented for `()` + | + = help: the following implementations were found: + <&() as Bug> + = note: the return type of a function must have a statically known size + +error: could not find defining uses + --> $DIR/issue-60371.rs:8:5 + | +LL | existential type Item: Bug; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/feature-gate/await-macro.rs b/src/test/ui/feature-gate/await-macro.rs new file mode 100644 index 0000000000000..291db9ba41370 --- /dev/null +++ b/src/test/ui/feature-gate/await-macro.rs @@ -0,0 +1,12 @@ +// gate-test-await_macro +// edition:2018 + +#![feature(async_await)] + +async fn bar() {} + +async fn foo() { + await!(bar()); //~ ERROR `await!()` macro syntax is unstable, and will soon be removed +} + +fn main() {} diff --git a/src/test/ui/feature-gate/await-macro.stderr b/src/test/ui/feature-gate/await-macro.stderr new file mode 100644 index 0000000000000..b6833655f6d8a --- /dev/null +++ b/src/test/ui/feature-gate/await-macro.stderr @@ -0,0 +1,12 @@ +error[E0658]: `await!()` macro syntax is unstable, and will soon be removed in favor of `.await` syntax. + --> $DIR/await-macro.rs:9:5 + | +LL | await!(bar()); + | ^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/50547 + = help: add #![feature(await_macro)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/fmt/format-string-error-2.rs b/src/test/ui/fmt/format-string-error-2.rs index 5c25ae502ff6d..8ca98fc266a01 100644 --- a/src/test/ui/fmt/format-string-error-2.rs +++ b/src/test/ui/fmt/format-string-error-2.rs @@ -1,3 +1,4 @@ +// compile-flags: -Z continue-parse-after-error // ignore-tidy-tab fn main() { @@ -76,7 +77,6 @@ raw { \n println!("\x7B}\u8 {", 1); //~^ ERROR incorrect unicode escape sequence - //~| ERROR argument never used // note: raw strings don't escape `\xFF` and `\u{FF}` sequences println!(r#"\x7B}\u{8} {"#, 1); diff --git a/src/test/ui/fmt/format-string-error-2.stderr b/src/test/ui/fmt/format-string-error-2.stderr index 66d35a1b854d3..227ec27efc87f 100644 --- a/src/test/ui/fmt/format-string-error-2.stderr +++ b/src/test/ui/fmt/format-string-error-2.stderr @@ -1,13 +1,13 @@ error: incorrect unicode escape sequence - --> $DIR/format-string-error-2.rs:77:20 + --> $DIR/format-string-error-2.rs:78:20 | LL | println!("\x7B}\u8 {", 1); | ^^- - | | - | help: format of unicode escape sequences uses braces: `\u{8}` + | | + | help: format of unicode escape sequences uses braces: `\u{8}` error: invalid format string: expected `'}'`, found `'a'` - --> $DIR/format-string-error-2.rs:5:5 + --> $DIR/format-string-error-2.rs:6:5 | LL | format!("{ | - because of this opening brace @@ -17,7 +17,7 @@ LL | a"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'b'` - --> $DIR/format-string-error-2.rs:9:5 + --> $DIR/format-string-error-2.rs:10:5 | LL | format!("{ \ | - because of this opening brace @@ -28,7 +28,7 @@ LL | b"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'\'` - --> $DIR/format-string-error-2.rs:11:18 + --> $DIR/format-string-error-2.rs:12:18 | LL | format!(r#"{ \ | - ^ expected `}` in format string @@ -38,7 +38,7 @@ LL | format!(r#"{ \ = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'\'` - --> $DIR/format-string-error-2.rs:15:18 + --> $DIR/format-string-error-2.rs:16:18 | LL | format!(r#"{ \n | - ^ expected `}` in format string @@ -48,7 +48,7 @@ LL | format!(r#"{ \n = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'e'` - --> $DIR/format-string-error-2.rs:21:5 + --> $DIR/format-string-error-2.rs:22:5 | LL | format!("{ \n | - because of this opening brace @@ -59,7 +59,7 @@ LL | e"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'a'` - --> $DIR/format-string-error-2.rs:25:5 + --> $DIR/format-string-error-2.rs:26:5 | LL | { | - because of this opening brace @@ -69,7 +69,7 @@ LL | a"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'a'` - --> $DIR/format-string-error-2.rs:29:5 + --> $DIR/format-string-error-2.rs:30:5 | LL | { | - because of this opening brace @@ -79,7 +79,7 @@ LL | a = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'b'` - --> $DIR/format-string-error-2.rs:35:5 + --> $DIR/format-string-error-2.rs:36:5 | LL | { \ | - because of this opening brace @@ -90,7 +90,7 @@ LL | b"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'b'` - --> $DIR/format-string-error-2.rs:40:5 + --> $DIR/format-string-error-2.rs:41:5 | LL | { \ | - because of this opening brace @@ -101,7 +101,7 @@ LL | b \ = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'\'` - --> $DIR/format-string-error-2.rs:45:8 + --> $DIR/format-string-error-2.rs:46:8 | LL | raw { \ | - ^ expected `}` in format string @@ -111,7 +111,7 @@ LL | raw { \ = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'\'` - --> $DIR/format-string-error-2.rs:50:8 + --> $DIR/format-string-error-2.rs:51:8 | LL | raw { \n | - ^ expected `}` in format string @@ -121,7 +121,7 @@ LL | raw { \n = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'e'` - --> $DIR/format-string-error-2.rs:57:5 + --> $DIR/format-string-error-2.rs:58:5 | LL | { \n | - because of this opening brace @@ -132,7 +132,7 @@ LL | e"); = note: if you intended to print `{`, you can escape it using `{{` error: invalid format string: expected `'}'`, found `'a'` - --> $DIR/format-string-error-2.rs:67:5 + --> $DIR/format-string-error-2.rs:68:5 | LL | { | - because of this opening brace @@ -142,13 +142,13 @@ LL | asdf} = note: if you intended to print `{`, you can escape it using `{{` error: 1 positional argument in format string, but no arguments were given - --> $DIR/format-string-error-2.rs:70:17 + --> $DIR/format-string-error-2.rs:71:17 | LL | println!("\t{}"); | ^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/format-string-error-2.rs:74:27 + --> $DIR/format-string-error-2.rs:75:27 | LL | println!("\x7B}\u{8} {", 1); | -^ expected `'}'` in format string @@ -157,14 +157,6 @@ LL | println!("\x7B}\u{8} {", 1); | = note: if you intended to print `{`, you can escape it using `{{` -error: argument never used - --> $DIR/format-string-error-2.rs:77:28 - | -LL | println!("\x7B}\u8 {", 1); - | ------------ ^ argument never used - | | - | formatting specifier missing - error: invalid format string: unmatched `}` found --> $DIR/format-string-error-2.rs:82:21 | @@ -181,5 +173,5 @@ LL | println!(r#"\x7B}\u8 {"#, 1); | = note: if you intended to print `}`, you can escape it using `}}` -error: aborting due to 19 previous errors +error: aborting due to 18 previous errors diff --git a/src/test/ui/fn-in-pat.rs b/src/test/ui/fn-in-pat.rs new file mode 100644 index 0000000000000..ed76b2c5db025 --- /dev/null +++ b/src/test/ui/fn-in-pat.rs @@ -0,0 +1,16 @@ +struct A {} + +impl A { + fn new() {} +} + +fn hof(_: F) where F: FnMut(()) {} + +fn ice() { + hof(|c| match c { + A::new() => (), //~ ERROR expected tuple struct/variant, found method + _ => () + }) +} + +fn main() {} diff --git a/src/test/ui/fn-in-pat.stderr b/src/test/ui/fn-in-pat.stderr new file mode 100644 index 0000000000000..eee97fe9587c2 --- /dev/null +++ b/src/test/ui/fn-in-pat.stderr @@ -0,0 +1,9 @@ +error[E0164]: expected tuple struct/variant, found method `::new` + --> $DIR/fn-in-pat.rs:11:9 + | +LL | A::new() => (), + | ^^^^^^^^ not a tuple variant or struct + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0164`. diff --git a/src/test/ui/generator-yielding-or-returning-itself.rs b/src/test/ui/generator-yielding-or-returning-itself.rs index 30788e3c1864b..fd52667981873 100644 --- a/src/test/ui/generator-yielding-or-returning-itself.rs +++ b/src/test/ui/generator-yielding-or-returning-itself.rs @@ -13,7 +13,7 @@ pub fn want_cyclic_generator_return(_: T) fn supply_cyclic_generator_return() { want_cyclic_generator_return(|| { - //~^ ERROR type mismatch + //~^ ERROR closure/generator type that references itself if false { yield None.unwrap(); } None.unwrap() }) diff --git a/src/test/ui/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator-yielding-or-returning-itself.stderr index 5834aed2450b1..42591683fe4e3 100644 --- a/src/test/ui/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator-yielding-or-returning-itself.stderr @@ -1,20 +1,17 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as std::ops::Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` - --> $DIR/generator-yielding-or-returning-itself.rs:15:5 +error[E0644]: closure/generator type that references itself + --> $DIR/generator-yielding-or-returning-itself.rs:15:34 | -LL | want_cyclic_generator_return(|| { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic type of infinite size +LL | want_cyclic_generator_return(|| { + | __________________________________^ +LL | | +LL | | if false { yield None.unwrap(); } +LL | | None.unwrap() +LL | | }) + | |_____^ cyclic type of infinite size | = note: closures cannot capture themselves or take themselves as argument; this error may be the result of a recent compiler bug-fix, see https://github.com/rust-lang/rust/issues/46062 for more details -note: required by `want_cyclic_generator_return` - --> $DIR/generator-yielding-or-returning-itself.rs:9:1 - | -LL | / pub fn want_cyclic_generator_return(_: T) -LL | | where T: Generator -LL | | { -LL | | } - | |_^ error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as std::ops::Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 @@ -36,4 +33,5 @@ LL | | } error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0271`. +Some errors have detailed explanations: E0271, E0644. +For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.rs b/src/test/ui/generator/type-mismatch-signature-deduction.rs new file mode 100644 index 0000000000000..b9c6bc5d0796e --- /dev/null +++ b/src/test/ui/generator/type-mismatch-signature-deduction.rs @@ -0,0 +1,17 @@ +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn foo() -> impl Generator { + || { + if false { + return Ok(6); //~ ERROR mismatched types [E0308] + } + + yield (); + + 5 + } +} + +fn main() {} diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr new file mode 100644 index 0000000000000..35d3f95c3e9e4 --- /dev/null +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch-signature-deduction.rs:8:20 + | +LL | return Ok(6); + | ^^^^^ expected i32, found enum `std::result::Result` + | + = note: expected type `i32` + found type `std::result::Result<{integer}, _>` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generator/unresolved_type_param.rs b/src/test/ui/generator/unresolved_type_param.rs index f49369b125f6f..77174b0321782 100644 --- a/src/test/ui/generator/unresolved_type_param.rs +++ b/src/test/ui/generator/unresolved_type_param.rs @@ -2,13 +2,14 @@ // Error message should pinpoint the type parameter T as needing to be bound // (rather than give a general error message) // edition:2018 -#![feature(futures_api, async_await, await_macro)] +#![feature(async_await)] async fn bar() -> () {} async fn foo() { - await!(bar()); - //~^ ERROR type inside generator must be known in this context - //~| NOTE cannot infer type for `T` - //~| NOTE the type is part of the generator because of this `yield` + bar().await; + //~^ ERROR type inside generator must be known in this context + //~| NOTE cannot infer type for `T` + //~| NOTE the type is part of the generator because of this `yield` + //~| NOTE in this expansion of desugaring of `await` } fn main() {} diff --git a/src/test/ui/generator/unresolved_type_param.stderr b/src/test/ui/generator/unresolved_type_param.stderr index 57ccdda3f43a1..afb9adf4c77cc 100644 --- a/src/test/ui/generator/unresolved_type_param.stderr +++ b/src/test/ui/generator/unresolved_type_param.stderr @@ -1,15 +1,14 @@ error[E0698]: type inside generator must be known in this context - --> $DIR/unresolved_type_param.rs:9:16 + --> $DIR/unresolved_type_param.rs:9:5 | -LL | await!(bar()); - | ^^^ cannot infer type for `T` +LL | bar().await; + | ^^^ cannot infer type for `T` | note: the type is part of the generator because of this `yield` - --> $DIR/unresolved_type_param.rs:9:9 + --> $DIR/unresolved_type_param.rs:9:5 | -LL | await!(bar()); - | ^^^^^^^^^^^^^^ - = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) +LL | bar().await; + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/if/if-let-arm-types.rs b/src/test/ui/if/if-let-arm-types.rs index 819f5dd1cfc35..0f8815f0479f5 100644 --- a/src/test/ui/if/if-let-arm-types.rs +++ b/src/test/ui/if/if-let-arm-types.rs @@ -1,11 +1,12 @@ fn main() { if let Some(b) = None { - //~^ NOTE if let` arms have incompatible types + //~^ NOTE if and else have incompatible types () + //~^ NOTE expected because of this } else { 1 }; - //~^^ ERROR: `if let` arms have incompatible types + //~^^ ERROR: if and else have incompatible types //~| NOTE expected (), found integer //~| NOTE expected type `()` } diff --git a/src/test/ui/if/if-let-arm-types.stderr b/src/test/ui/if/if-let-arm-types.stderr index b986973fe91f4..ff88de20f76cc 100644 --- a/src/test/ui/if/if-let-arm-types.stderr +++ b/src/test/ui/if/if-let-arm-types.stderr @@ -1,14 +1,16 @@ -error[E0308]: `if let` arms have incompatible types - --> $DIR/if-let-arm-types.rs:6:9 +error[E0308]: if and else have incompatible types + --> $DIR/if-let-arm-types.rs:7:9 | LL | / if let Some(b) = None { LL | | LL | | () + | | -- expected because of this +LL | | LL | | } else { LL | | 1 | | ^ expected (), found integer LL | | }; - | |_____- `if let` arms have incompatible types + | |_____- if and else have incompatible types | = note: expected type `()` found type `{integer}` diff --git a/src/test/ui/if/if-no-match-bindings.rs b/src/test/ui/if/if-no-match-bindings.rs new file mode 100644 index 0000000000000..581ce18c1d614 --- /dev/null +++ b/src/test/ui/if/if-no-match-bindings.rs @@ -0,0 +1,22 @@ +// Checks for `if` expressions with respect to default match bindings. +// Specifically, we do not accept `if cond { ... }` where `cond: &mut? bool`. +// Meanwhile, `match cond { true => ..., _ => ... }` does accept that. + +// FIXME(@rust-lang/lang-team): consider relaxing this? + +fn b_ref<'a>() -> &'a bool { &true } +fn b_mut_ref<'a>() -> &'a mut bool { &mut true } + +fn main() { + // This is OK: + match b_ref() { true => {}, _ => {} } + match b_mut_ref() { true => {}, _ => {} } + match &true { true => {}, _ => {} } + match &mut true { true => {}, _ => {} } + + // This is NOT: + if b_ref() {} //~ ERROR mismatched types [E0308] + if b_mut_ref() {} //~ ERROR mismatched types [E0308] + if &true {} //~ ERROR mismatched types [E0308] + if &mut true {} //~ ERROR mismatched types [E0308] +} diff --git a/src/test/ui/if/if-no-match-bindings.stderr b/src/test/ui/if/if-no-match-bindings.stderr new file mode 100644 index 0000000000000..7b0b472121fce --- /dev/null +++ b/src/test/ui/if/if-no-match-bindings.stderr @@ -0,0 +1,39 @@ +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:18:8 + | +LL | if b_ref() {} + | ^^^^^^^ expected bool, found &bool + | + = note: expected type `bool` + found type `&bool` + +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:19:8 + | +LL | if b_mut_ref() {} + | ^^^^^^^^^^^ expected bool, found &mut bool + | + = note: expected type `bool` + found type `&mut bool` + +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:20:8 + | +LL | if &true {} + | ^^^^^ expected bool, found &bool + | + = note: expected type `bool` + found type `&bool` + +error[E0308]: mismatched types + --> $DIR/if-no-match-bindings.rs:21:8 + | +LL | if &mut true {} + | ^^^^^^^^^ expected bool, found &mut bool + | + = note: expected type `bool` + found type `&mut bool` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/if/if-without-else-as-fn-expr.rs b/src/test/ui/if/if-without-else-as-fn-expr.rs index 67e4445629f8c..15892de83854c 100644 --- a/src/test/ui/if/if-without-else-as-fn-expr.rs +++ b/src/test/ui/if/if-without-else-as-fn-expr.rs @@ -3,6 +3,7 @@ fn foo(bar: usize) -> usize { return 3; } //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] } fn foo2(bar: usize) -> usize { @@ -10,6 +11,7 @@ fn foo2(bar: usize) -> usize { return 3; }; //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] x } @@ -18,8 +20,36 @@ fn foo3(bar: usize) -> usize { 3 } //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] } +fn foo_let(bar: usize) -> usize { + if let 0 = 1 { + return 3; + } + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] +} + +fn foo2_let(bar: usize) -> usize { + let x: usize = if let 0 = 1 { + return 3; + }; + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] + x +} + +fn foo3_let(bar: usize) -> usize { + if let 0 = 1 { + 3 + } + //~^^^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] +} + +// FIXME(60254): deduplicate first error in favor of second. + fn main() { let _ = foo(1); } diff --git a/src/test/ui/if/if-without-else-as-fn-expr.stderr b/src/test/ui/if/if-without-else-as-fn-expr.stderr index 0ba72726ca787..06600b1cb9aea 100644 --- a/src/test/ui/if/if-without-else-as-fn-expr.stderr +++ b/src/test/ui/if/if-without-else-as-fn-expr.stderr @@ -1,3 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:2:5 + | +LL | / if bar % 5 == 0 { +LL | | return 3; +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + error[E0317]: if may be missing an else clause --> $DIR/if-without-else-as-fn-expr.rs:2:5 | @@ -13,8 +24,20 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:10:20 + | +LL | let x: usize = if bar % 5 == 0 { + | ____________________^ +LL | | return 3; +LL | | }; + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:9:20 + --> $DIR/if-without-else-as-fn-expr.rs:10:20 | LL | let x: usize = if bar % 5 == 0 { | _________-__________^ @@ -29,8 +52,19 @@ LL | | }; = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:19:5 + | +LL | / if bar % 5 == 0 { +LL | | 3 +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + error[E0317]: if may be missing an else clause - --> $DIR/if-without-else-as-fn-expr.rs:17:5 + --> $DIR/if-without-else-as-fn-expr.rs:19:5 | LL | fn foo3(bar: usize) -> usize { | ----- expected `usize` because of this return type @@ -44,6 +78,87 @@ LL | | } = note: `if` expressions without `else` evaluate to `()` = help: consider adding an `else` block that evaluates to the expected type -error: aborting due to 3 previous errors +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:27:5 + | +LL | / if let 0 = 1 { +LL | | return 3; +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:27:5 + | +LL | fn foo_let(bar: usize) -> usize { + | ----- expected `usize` because of this return type +LL | / if let 0 = 1 { +LL | | return 3; +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:35:20 + | +LL | let x: usize = if let 0 = 1 { + | ____________________^ +LL | | return 3; +LL | | }; + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:35:20 + | +LL | let x: usize = if let 0 = 1 { + | _________-__________^ + | | | + | | expected because of this assignment +LL | | return 3; +LL | | }; + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error[E0308]: mismatched types + --> $DIR/if-without-else-as-fn-expr.rs:44:5 + | +LL | / if let 0 = 1 { +LL | | 3 +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + +error[E0317]: if may be missing an else clause + --> $DIR/if-without-else-as-fn-expr.rs:44:5 + | +LL | fn foo3_let(bar: usize) -> usize { + | ----- expected `usize` because of this return type +LL | / if let 0 = 1 { +LL | | 3 +LL | | } + | |_____^ expected usize, found () + | + = note: expected type `usize` + found type `()` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type + +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0317`. +Some errors have detailed explanations: E0308, E0317. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/impl-trait/bindings-opaque.rs b/src/test/ui/impl-trait/bindings-opaque.rs index 5f623321943a3..d4eef29ed3207 100644 --- a/src/test/ui/impl-trait/bindings-opaque.rs +++ b/src/test/ui/impl-trait/bindings-opaque.rs @@ -1,4 +1,5 @@ #![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash const FOO: impl Copy = 42; diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr index 8b2514c050142..d0a6a4ee578f7 100644 --- a/src/test/ui/impl-trait/bindings-opaque.stderr +++ b/src/test/ui/impl-trait/bindings-opaque.stderr @@ -1,17 +1,23 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/bindings-opaque.rs:1:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope - --> $DIR/bindings-opaque.rs:10:17 + --> $DIR/bindings-opaque.rs:11:17 | LL | let _ = FOO.count_ones(); | ^^^^^^^^^^ error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope - --> $DIR/bindings-opaque.rs:12:17 + --> $DIR/bindings-opaque.rs:13:17 | LL | let _ = BAR.count_ones(); | ^^^^^^^^^^ error[E0599]: no method named `count_ones` found for type `impl std::marker::Copy` in the current scope - --> $DIR/bindings-opaque.rs:14:17 + --> $DIR/bindings-opaque.rs:15:17 | LL | let _ = foo.count_ones(); | ^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/bindings.rs b/src/test/ui/impl-trait/bindings.rs index 91d092634a901..104a44d65662e 100644 --- a/src/test/ui/impl-trait/bindings.rs +++ b/src/test/ui/impl-trait/bindings.rs @@ -1,4 +1,5 @@ #![feature(impl_trait_in_bindings)] +//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash fn a(x: T) { const foo: impl Clone = x; diff --git a/src/test/ui/impl-trait/bindings.stderr b/src/test/ui/impl-trait/bindings.stderr index a5bf583afeaf6..c66836ab8e5af 100644 --- a/src/test/ui/impl-trait/bindings.stderr +++ b/src/test/ui/impl-trait/bindings.stderr @@ -1,23 +1,29 @@ +warning: the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash + --> $DIR/bindings.rs:1:12 + | +LL | #![feature(impl_trait_in_bindings)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:4:29 + --> $DIR/bindings.rs:5:29 | LL | const foo: impl Clone = x; | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:10:33 + --> $DIR/bindings.rs:11:33 | LL | const foo: impl Clone = x; | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:17:33 + --> $DIR/bindings.rs:18:33 | LL | const foo: impl Clone = x; | ^ non-constant value error[E0435]: attempt to use a non-constant value in a constant - --> $DIR/bindings.rs:24:33 + --> $DIR/bindings.rs:25:33 | LL | const foo: impl Clone = x; | ^ non-constant value diff --git a/src/test/ui/impl-trait/can-return-unconstrained-closure.rs b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs index a982b176ecda1..90a7519074b53 100644 --- a/src/test/ui/impl-trait/can-return-unconstrained-closure.rs +++ b/src/test/ui/impl-trait/can-return-unconstrained-closure.rs @@ -16,4 +16,8 @@ fn make_identity() -> impl Sized { |x: &'static i32| x } +fn make_identity_static() -> impl Sized + 'static { + |x: &'static i32| x +} + fn main() {} diff --git a/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs b/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs index 29e271c68ec90..11f1a392239dc 100644 --- a/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs +++ b/src/test/ui/impl-trait/issue-57464-unexpected-regions.rs @@ -17,6 +17,13 @@ fn wrapped_closure() -> impl Sized { A(f) } +fn wrapped_closure_with_bound() -> impl Sized + 'static { + let f = |x| x; + f(&0); + A(f) +} + fn main() { let x: Box = Box::new(wrapped_closure()); + let y: Box = Box::new(wrapped_closure_with_bound()); } diff --git a/src/test/ui/issues/issue-19991.stderr b/src/test/ui/issues/issue-19991.stderr index 4c6d150229a3e..d9ea910adef50 100644 --- a/src/test/ui/issues/issue-19991.stderr +++ b/src/test/ui/issues/issue-19991.stderr @@ -6,11 +6,14 @@ LL | | LL | | LL | | LL | | 765 + | | --- found here LL | | }; | |_____^ expected (), found integer | = note: expected type `()` found type `{integer}` + = note: `if` expressions without `else` evaluate to `()` + = help: consider adding an `else` block that evaluates to the expected type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50518.rs b/src/test/ui/issues/issue-50518.rs new file mode 100644 index 0000000000000..d776d181b6268 --- /dev/null +++ b/src/test/ui/issues/issue-50518.rs @@ -0,0 +1,40 @@ +// compile-pass +use std::marker::PhantomData; + +struct Meta { + value: i32, + type_: PhantomData +} + +trait MetaTrait { + fn get_value(&self) -> i32; +} + +impl MetaTrait for Meta { + fn get_value(&self) -> i32 { self.value } +} + +trait Bar { + fn get_const(&self) -> &dyn MetaTrait; +} + +struct Foo { + _value: A +} + +impl Foo { + const CONST: &'static dyn MetaTrait = &Meta:: { + value: 10, + type_: PhantomData + }; +} + +impl Bar for Foo { + fn get_const(&self) -> &dyn MetaTrait { Self::CONST } +} + +fn main() { + let foo = Foo:: { _value: 10 }; + let bar: &dyn Bar = &foo; + println!("const {}", bar.get_const().get_value()); +} diff --git a/src/test/ui/issues/issue-50577.rs b/src/test/ui/issues/issue-50577.rs index f0f1dc6c28667..bf892a8daa27f 100644 --- a/src/test/ui/issues/issue-50577.rs +++ b/src/test/ui/issues/issue-50577.rs @@ -2,5 +2,6 @@ fn main() { enum Foo { Drop = assert_eq!(1, 1) //~^ ERROR if may be missing an else clause + //~| ERROR mismatched types [E0308] } } diff --git a/src/test/ui/issues/issue-50577.stderr b/src/test/ui/issues/issue-50577.stderr index 0c3ba2ea4f94d..413c8c5c80b52 100644 --- a/src/test/ui/issues/issue-50577.stderr +++ b/src/test/ui/issues/issue-50577.stderr @@ -1,3 +1,13 @@ +error[E0308]: mismatched types + --> $DIR/issue-50577.rs:3:16 + | +LL | Drop = assert_eq!(1, 1) + | ^^^^^^^^^^^^^^^^ expected isize, found () + | + = note: expected type `isize` + found type `()` + = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) + error[E0317]: if may be missing an else clause --> $DIR/issue-50577.rs:3:16 | @@ -13,6 +23,7 @@ LL | Drop = assert_eq!(1, 1) = help: consider adding an `else` block that evaluates to the expected type = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0317`. +Some errors have detailed explanations: E0308, E0317. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-51719.rs b/src/test/ui/issues/issue-51719.rs new file mode 100644 index 0000000000000..2c02ac01142bb --- /dev/null +++ b/src/test/ui/issues/issue-51719.rs @@ -0,0 +1,11 @@ +// edition:2018 +// +// Tests that the .await syntax can't be used to make a generator + +#![feature(async_await)] + +async fn foo() {} + +fn make_generator() { + let _gen = || foo.await; //~ ERROR `await` is only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/issues/issue-51719.stderr b/src/test/ui/issues/issue-51719.stderr new file mode 100644 index 0000000000000..768909b66ec77 --- /dev/null +++ b/src/test/ui/issues/issue-51719.stderr @@ -0,0 +1,8 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-51719.rs:10:19 + | +LL | let _gen = || foo.await; + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-51751.rs b/src/test/ui/issues/issue-51751.rs new file mode 100644 index 0000000000000..7afd7ecc82649 --- /dev/null +++ b/src/test/ui/issues/issue-51751.rs @@ -0,0 +1,13 @@ +// edition:2018 + +#![feature(async_await)] + +async fn inc(limit: i64) -> i64 { + limit + 1 +} + +fn main() { + let result = inc(10000); + let finished = result.await; + //~^ ERROR `await` is only allowed inside `async` functions and blocks +} diff --git a/src/test/ui/issues/issue-51751.stderr b/src/test/ui/issues/issue-51751.stderr new file mode 100644 index 0000000000000..0c4cb034a9381 --- /dev/null +++ b/src/test/ui/issues/issue-51751.stderr @@ -0,0 +1,8 @@ +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/issue-51751.rs:11:20 + | +LL | let finished = result.await; + | ^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-53498.rs b/src/test/ui/issues/issue-53498.rs new file mode 100644 index 0000000000000..c87d423649233 --- /dev/null +++ b/src/test/ui/issues/issue-53498.rs @@ -0,0 +1,17 @@ +pub mod test { + pub struct A; + pub struct B; + pub struct Foo(T); + + impl Foo { + fn foo() {} + } + + impl Foo { + fn foo() {} + } +} + +fn main() { + test::Foo::::foo(); //~ ERROR method `foo` is private +} diff --git a/src/test/ui/issues/issue-53498.stderr b/src/test/ui/issues/issue-53498.stderr new file mode 100644 index 0000000000000..3fd48233daeb4 --- /dev/null +++ b/src/test/ui/issues/issue-53498.stderr @@ -0,0 +1,9 @@ +error[E0624]: method `foo` is private + --> $DIR/issue-53498.rs:16:5 + | +LL | test::Foo::::foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0624`. diff --git a/src/test/ui/issues/issue-60283.rs b/src/test/ui/issues/issue-60283.rs new file mode 100644 index 0000000000000..e5a9caa32fae7 --- /dev/null +++ b/src/test/ui/issues/issue-60283.rs @@ -0,0 +1,17 @@ +pub trait Trait<'a> { + type Item; +} + +impl<'a> Trait<'a> for () { + type Item = (); +} + +pub fn foo(_: T, _: F) +where T: for<'a> Trait<'a>, + F: for<'a> FnMut(>::Item) {} + +fn main() { + foo((), drop) + //~^ ERROR type mismatch in function arguments + //~| ERROR type mismatch resolving +} diff --git a/src/test/ui/issues/issue-60283.stderr b/src/test/ui/issues/issue-60283.stderr new file mode 100644 index 0000000000000..a79b1959dca2f --- /dev/null +++ b/src/test/ui/issues/issue-60283.stderr @@ -0,0 +1,34 @@ +error[E0631]: type mismatch in function arguments + --> $DIR/issue-60283.rs:14:5 + | +LL | foo((), drop) + | ^^^ + | | + | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _` + | found signature of `fn(_) -> _` + | +note: required by `foo` + --> $DIR/issue-60283.rs:9:1 + | +LL | / pub fn foo(_: T, _: F) +LL | | where T: for<'a> Trait<'a>, +LL | | F: for<'a> FnMut(>::Item) {} + | |_________________________________________________^ + +error[E0271]: type mismatch resolving `for<'a> } as std::ops::FnOnce<(<() as Trait<'a>>::Item,)>>::Output == ()` + --> $DIR/issue-60283.rs:14:5 + | +LL | foo((), drop) + | ^^^ expected bound lifetime parameter 'a, found concrete lifetime + | +note: required by `foo` + --> $DIR/issue-60283.rs:9:1 + | +LL | / pub fn foo(_: T, _: F) +LL | | where T: for<'a> Trait<'a>, +LL | | F: for<'a> FnMut(>::Item) {} + | |_________________________________________________^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/src/test/ui/issues/issue-60662.rs b/src/test/ui/issues/issue-60662.rs new file mode 100644 index 0000000000000..fe4eaff742d62 --- /dev/null +++ b/src/test/ui/issues/issue-60662.rs @@ -0,0 +1,11 @@ +// compile-pass +// compile-flags: -Z unpretty=hir + +#![feature(existential_type)] + +trait Animal { +} + +fn main() { + pub existential type ServeFut: Animal; +} diff --git a/src/test/ui/issues/issue-60662.stdout b/src/test/ui/issues/issue-60662.stdout new file mode 100644 index 0000000000000..5acfdf9ed5342 --- /dev/null +++ b/src/test/ui/issues/issue-60662.stdout @@ -0,0 +1,14 @@ +// compile-pass +// compile-flags: -Z unpretty=hir + +#![feature(existential_type)] +#[prelude_import] +use ::std::prelude::v1::*; +#[macro_use] +extern crate std; + +trait Animal { } + +fn main() { + pub existential type ServeFut : Animal; + } diff --git a/src/test/ui/lint/unused_import_warning_issue_45268.rs b/src/test/ui/lint/unused_import_warning_issue_45268.rs new file mode 100644 index 0000000000000..0bd7751113593 --- /dev/null +++ b/src/test/ui/lint/unused_import_warning_issue_45268.rs @@ -0,0 +1,48 @@ +// compile-pass + +#![warn(unused_imports)] // Warning explanation here, it's OK + +mod test { + pub trait A { + fn a(); + } + + impl A for () { + fn a() { } + } + + pub trait B { + fn b(self); + } + + impl B for () { + fn b(self) { } + } + + pub trait Unused { + } +} + +use test::Unused; // This is really unused, so warning is OK +use test::A; // This is used by the test2::func() through import of super::* +use test::B; // This is used by the test2::func() through import of super::* + +mod test2 { + use super::*; + pub fn func() { + let _ = <()>::a(); + let _ = ().b(); + test3::inner_func(); + } + mod test3 { + use super::*; + pub fn inner_func() { + let _ = <()>::a(); + let _ = ().b(); + } + } +} + +fn main() { + test2::func(); +} diff --git a/src/test/ui/lint/unused_import_warning_issue_45268.stderr b/src/test/ui/lint/unused_import_warning_issue_45268.stderr new file mode 100644 index 0000000000000..7392e99f7aef3 --- /dev/null +++ b/src/test/ui/lint/unused_import_warning_issue_45268.stderr @@ -0,0 +1,12 @@ +warning: unused import: `test::Unused` + --> $DIR/unused_import_warning_issue_45268.rs:26:5 + | +LL | use test::Unused; // This is really unused, so warning is OK + | ^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/unused_import_warning_issue_45268.rs:3:9 + | +LL | #![warn(unused_imports)] // Warning explanation here, it's OK + | ^^^^^^^^^^^^^^ + diff --git a/src/test/ui/macros/macro-attribute.stderr b/src/test/ui/macros/macro-attribute.stderr index aa1cd94b0c638..d28ce25341d3a 100644 --- a/src/test/ui/macros/macro-attribute.stderr +++ b/src/test/ui/macros/macro-attribute.stderr @@ -1,8 +1,8 @@ error: unexpected token: `$` - --> $DIR/macro-attribute.rs:1:7 + --> $DIR/macro-attribute.rs:1:9 | LL | #[doc = $not_there] - | ^ + | ^ error: aborting due to previous error diff --git a/src/test/ui/malformed/malformed-interpolated.rs b/src/test/ui/malformed/malformed-interpolated.rs index e452435968bac..7c4ca3c017e7b 100644 --- a/src/test/ui/malformed/malformed-interpolated.rs +++ b/src/test/ui/malformed/malformed-interpolated.rs @@ -2,8 +2,7 @@ macro_rules! check { ($expr: expr) => ( - #[my_attr = $expr] //~ ERROR suffixed literals are not allowed in attributes - //~| ERROR unexpected token: `-0` + #[my_attr = $expr] //~ ERROR unexpected token: `-0` //~| ERROR unexpected token: `0 + 0` use main as _; ); @@ -11,7 +10,7 @@ macro_rules! check { check!("0"); // OK check!(0); // OK -check!(0u8); // ERROR, see above +check!(0u8); //~ ERROR suffixed literals are not allowed in attributes check!(-0); // ERROR, see above check!(0 + 0); // ERROR, see above diff --git a/src/test/ui/malformed/malformed-interpolated.stderr b/src/test/ui/malformed/malformed-interpolated.stderr index efeede0148dac..e805416172bab 100644 --- a/src/test/ui/malformed/malformed-interpolated.stderr +++ b/src/test/ui/malformed/malformed-interpolated.stderr @@ -1,28 +1,25 @@ error: suffixed literals are not allowed in attributes - --> $DIR/malformed-interpolated.rs:5:21 + --> $DIR/malformed-interpolated.rs:13:8 | -LL | #[my_attr = $expr] - | ^^^^^ -... -LL | check!(0u8); // ERROR, see above - | ------------ in this macro invocation +LL | check!(0u8); + | ^^^ | = help: instead of using a suffixed literal (1u8, 1.0f32, etc.), use an unsuffixed version (1, 1.0, etc.). error: unexpected token: `-0` - --> $DIR/malformed-interpolated.rs:5:19 + --> $DIR/malformed-interpolated.rs:5:21 | LL | #[my_attr = $expr] - | ^ + | ^^^^^ ... LL | check!(-0); // ERROR, see above | ----------- in this macro invocation error: unexpected token: `0 + 0` - --> $DIR/malformed-interpolated.rs:5:19 + --> $DIR/malformed-interpolated.rs:5:21 | LL | #[my_attr = $expr] - | ^ + | ^^^^^ ... LL | check!(0 + 0); // ERROR, see above | -------------- in this macro invocation diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index 20041389b3c38..cc5ffca10475e 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -4,9 +4,9 @@ note: No external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_argument_callee[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) i32)), + for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) i32)), ] error: lifetime may not live long enough @@ -30,7 +30,7 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_argument_callee[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_argument_callee[317d]::test[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index b08ec9539318a..fdf95b8acebfc 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -4,9 +4,9 @@ note: No external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_argument[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)), + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) mut &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32)), ] note: No external requirements @@ -21,7 +21,7 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_argument[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_argument[317d]::test[0]) with substs [] error[E0597]: `y` does not live long enough --> $DIR/escape-argument.rs:27:25 diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 7178b22bb5f2d..135de0445a799 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -4,7 +4,7 @@ note: External requirements LL | let mut closure1 = || p = &y; | ^^^^^^^^^ | - = note: defining type: DefId(0/1:10 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:14 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), &'_#1r mut &'_#2r i32, @@ -23,7 +23,7 @@ LL | | closure1(); LL | | }; | |_________^ | - = note: defining type: DefId(0/1:9 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_upvar_nested[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), &'_#1r mut &'_#2r i32, @@ -44,7 +44,7 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_upvar_nested[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_upvar_nested[317d]::test[0]) with substs [] error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-nested.rs:21:40 diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index d129f945f252a..8c37ab7b768c3 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -4,7 +4,7 @@ note: External requirements LL | let mut closure = || p = &y; | ^^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ escape_upvar_ref[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, extern "rust-call" fn(()), &'_#1r mut &'_#2r i32, @@ -25,7 +25,7 @@ LL | | deref(p); LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ escape_upvar_ref[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ escape_upvar_ref[317d]::test[0]) with substs [] error[E0597]: `y` does not live long enough --> $DIR/escape-upvar-ref.rs:23:35 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 4db1f04077043..8916fdcfc88f1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -8,9 +8,9 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: DefId(0/1:20 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:27 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#4r = note: late-bound region is '_#5r @@ -39,7 +39,7 @@ LL | | ); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:23 ~ propagate_approximated_fail_no_postdom[317d]::supply[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 7dedae715bea0..fa8384311ea57 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -9,9 +9,9 @@ LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_ref[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -30,7 +30,7 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_ref[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_ref[317d]::supply[0]) with substs [] error: lifetime may not live long enough --> $DIR/propagate-approximated-ref.rs:45:9 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 6d1baf9f827db..cfaa75b8ef861 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -8,9 +8,9 @@ LL | | LL | | }) | |_____^ | - = note: defining type: DefId(0/1:12 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:18 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>)), ] error[E0521]: borrowed data escapes outside of closure @@ -35,7 +35,7 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:5 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]) with substs [] + = note: defining type: DefId(0:17 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case1[0]) with substs [] note: External requirements --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:35:15 @@ -46,9 +46,9 @@ LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static LL | | }) | |_____^ | - = note: defining type: DefId(0/1:13 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:20 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]::{{closure}}[0]) with closure substs [ i32, - for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>)), + for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>)), ] = note: number of external vids: 2 = note: where '_#1r: '_#0r @@ -65,7 +65,7 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]) with substs [] + = note: defining type: DefId(0:19 ~ propagate_approximated_shorter_to_static_comparing_against_free[317d]::case2[0]) with substs [] error[E0597]: `a` does not live long enough --> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index ea04a47a4804b..601b3577e0eec 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -10,9 +10,9 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r @@ -31,7 +31,7 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_shorter_to_static_no_bound[317d]::supply[0]) with substs [] error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 033357b09fb2e..5b5440e7a9641 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -10,9 +10,9 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -31,7 +31,7 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_shorter_to_static_wrong_bound[317d]::supply[0]) with substs [] error[E0521]: borrowed data escapes outside of function --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5 diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index 223c29f596922..a08cde2c9c635 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -9,9 +9,9 @@ LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_approximated_val[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -30,7 +30,7 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_approximated_val[317d]::test[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_approximated_val[317d]::test[0]) with substs [] error: lifetime may not live long enough --> $DIR/propagate-approximated-val.rs:38:9 diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index d618b4d06a1d8..60847bb2e9290 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -8,9 +8,9 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: DefId(0/1:16 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:23 ~ propagate_despite_same_free_region[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), + for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#3r = note: number of external vids: 4 @@ -28,5 +28,5 @@ LL | | ); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_despite_same_free_region[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:21 ~ propagate_despite_same_free_region[317d]::supply[0]) with substs [] diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 07fb4d0d5e3ae..a660c763bff78 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -9,9 +9,9 @@ LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>)), + for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>)), ] = note: late-bound region is '_#2r = note: late-bound region is '_#3r @@ -39,7 +39,7 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_fail_to_approximate_longer_no_bounds[317d]::supply[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index a0744c27db72c..9671b8ebff3a4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -9,9 +9,9 @@ LL | | LL | | }); | |_____^ | - = note: defining type: DefId(0/1:18 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:25 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 't1)) u32>)), + for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 't1)) u32>)), ] = note: late-bound region is '_#3r = note: late-bound region is '_#4r @@ -39,7 +39,7 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]) with substs [] + = note: defining type: DefId(0:22 ~ propagate_fail_to_approximate_longer_wrong_bounds[317d]::supply[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index 282246f81666b..457b5950b7ff0 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -11,7 +11,7 @@ LL | | require(value); LL | | }); | |_____^ | - = note: defining type: DefId(0/1:16 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:23 ~ propagate_from_trait_match[317d]::supply[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -32,7 +32,7 @@ LL | | }); LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ propagate_from_trait_match[317d]::supply[0]) with substs [ + = note: defining type: DefId(0:20 ~ propagate_from_trait_match[317d]::supply[0]) with substs [ '_#1r, T, ] diff --git a/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs index 66290f2ff230a..5a008ad26b444 100644 --- a/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs +++ b/src/test/ui/nll/closure-requirements/region-lbr1-does-outlive-lbr2-because-implied-bound.rs @@ -3,8 +3,7 @@ // compile-flags:-Zborrowck=mir -Zverbose // compile-pass - -#![allow(warnings)] +// skip-codegen fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 { &**x diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index c5645413c77cd..8aff6d5b89279 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -4,9 +4,9 @@ note: No external requirements LL | expect_sig(|a, b| b); // ought to return `a` | ^^^^^^^^ | - = note: defining type: DefId(0/1:9 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:13 ~ return_wrong_bound_region[317d]::test[0]::{{closure}}[0]) with closure substs [ i16, - for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 'r)) i32, + for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 'r)) i32, ] error: lifetime may not live long enough @@ -27,7 +27,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:3 ~ return_wrong_bound_region[317d]::test[0]) with substs [] + = note: defining type: DefId(0:12 ~ return_wrong_bound_region[317d]::test[0]) with substs [] error: aborting due to previous error diff --git a/src/test/ui/nll/issue-55850.rs b/src/test/ui/nll/issue-55850.rs index 8a016bf87795b..a8f7299f89937 100644 --- a/src/test/ui/nll/issue-55850.rs +++ b/src/test/ui/nll/issue-55850.rs @@ -25,7 +25,7 @@ where fn bug<'a>() -> impl Iterator { GenIter(move || { let mut s = String::new(); - yield &s[..] //~ ERROR `s` does not live long enough [E0597] + yield &s[..] //~ ERROR cannot yield value referencing local variable `s` [E0515] //~| ERROR borrow may still be in use when generator yields }) } diff --git a/src/test/ui/nll/issue-55850.stderr b/src/test/ui/nll/issue-55850.stderr index 66c2995efc880..86a8cdc42ff9f 100644 --- a/src/test/ui/nll/issue-55850.stderr +++ b/src/test/ui/nll/issue-55850.stderr @@ -1,11 +1,11 @@ -error[E0597]: `s` does not live long enough - --> $DIR/issue-55850.rs:28:16 +error[E0515]: cannot yield value referencing local variable `s` + --> $DIR/issue-55850.rs:28:9 | LL | yield &s[..] - | ^ borrowed value does not live long enough -LL | -LL | }) - | - `s` dropped here while still borrowed + | ^^^^^^^-^^^^ + | | | + | | `s` is borrowed here + | yields a value referencing data owned by the current function error[E0626]: borrow may still be in use when generator yields --> $DIR/issue-55850.rs:28:16 @@ -15,5 +15,5 @@ LL | yield &s[..] error: aborting due to 2 previous errors -Some errors have detailed explanations: E0597, E0626. -For more information about an error, try `rustc --explain E0597`. +Some errors have detailed explanations: E0515, E0626. +For more information about an error, try `rustc --explain E0515`. diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index cda1f7d36311c..9fa54e83812f7 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -4,7 +4,7 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:15 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:22 ~ projection_no_regions_closure[317d]::no_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -25,7 +25,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [ + = note: defining type: DefId(0:19 ~ projection_no_regions_closure[317d]::no_region[0]) with substs [ '_#1r, T, ] @@ -44,7 +44,7 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:18 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:26 ~ projection_no_regions_closure[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -64,7 +64,7 @@ LL | | with_signature(x, |mut y| Box::new(y.next())) LL | | } | |_^ | - = note: defining type: DefId(0/0:7 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [ + = note: defining type: DefId(0:23 ~ projection_no_regions_closure[317d]::correct_region[0]) with substs [ '_#1r, T, ] @@ -75,7 +75,7 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:22 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:31 ~ projection_no_regions_closure[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -97,7 +97,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [ + = note: defining type: DefId(0:27 ~ projection_no_regions_closure[317d]::wrong_region[0]) with substs [ '_#1r, '_#2r, T, @@ -117,7 +117,7 @@ note: External requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:26 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:36 ~ projection_no_regions_closure[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -139,7 +139,7 @@ LL | | with_signature(x, |mut y| Box::new(y.next())) LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [ + = note: defining type: DefId(0:32 ~ projection_no_regions_closure[317d]::outlives_region[0]) with substs [ '_#1r, '_#2r, T, diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index 9d716006500b7..10b2bd1af4702 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -4,7 +4,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:19 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:28 ~ projection_one_region_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -27,7 +27,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:24 ~ projection_one_region_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, T, ] @@ -38,7 +38,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:16), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:24 ~ projection_one_region_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(25), 'a))`... error: lifetime may not live long enough --> $DIR/projection-one-region-closure.rs:45:39 @@ -57,7 +57,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:23 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:33 ~ projection_one_region_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -80,7 +80,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:29 ~ projection_one_region_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, T, @@ -111,7 +111,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:38 ~ projection_one_region_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -133,7 +133,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:34 ~ projection_one_region_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, T, @@ -145,7 +145,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_one_region_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -168,7 +168,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [ + = note: defining type: DefId(0:39 ~ projection_one_region_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, T, diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 0fa4060137a3f..b4b74bfc1284f 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:28 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -26,7 +26,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:24 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, T, ] @@ -48,7 +48,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:33 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -70,7 +70,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:29 ~ projection_one_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, T, @@ -93,7 +93,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:38 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -115,7 +115,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:34 ~ projection_one_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, T, @@ -127,7 +127,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -149,7 +149,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [ + = note: defining type: DefId(0:39 ~ projection_one_region_trait_bound_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, T, @@ -161,7 +161,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:47 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -182,7 +182,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [ + = note: defining type: DefId(0:44 ~ projection_one_region_trait_bound_closure[317d]::one_region[0]) with substs [ '_#1r, T, ] diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index f616a7feae3f0..a757a43499f4b 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -4,7 +4,7 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:19 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:28 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -23,7 +23,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:24 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, T, ] @@ -34,7 +34,7 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:23 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:33 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -54,7 +54,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:29 ~ projection_one_region_trait_bound_static_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, T, @@ -66,7 +66,7 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:38 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -86,7 +86,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:34 ~ projection_one_region_trait_bound_static_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, T, @@ -98,7 +98,7 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:31 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -118,7 +118,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [ + = note: defining type: DefId(0:39 ~ projection_one_region_trait_bound_static_closure[317d]::elements_outlive[0]) with substs [ '_#1r, '_#2r, T, @@ -130,7 +130,7 @@ note: No external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:34 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:47 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -149,7 +149,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:12 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [ + = note: defining type: DefId(0:44 ~ projection_one_region_trait_bound_static_closure[317d]::one_region[0]) with substs [ '_#1r, T, ] diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index b761b031444da..a48766cd7340b 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:22 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:31 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -27,7 +27,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ + = note: defining type: DefId(0:26 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]) with substs [ '_#1r, '_#2r, T, @@ -39,7 +39,7 @@ error[E0309]: the associated type `>::AssocType` may LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `>::AssocType: ReFree(DefId(0/0:8 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(1:18), 'a))`... + = help: consider adding an explicit lifetime bound `>::AssocType: ReFree(DefId(0:26 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_late[0]), BrNamed(crate0:DefIndex(27), 'a))`... note: External requirements --> $DIR/projection-two-region-trait-bound-closure.rs:48:29 @@ -47,7 +47,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:27 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:37 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, @@ -70,7 +70,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ + = note: defining type: DefId(0:32 ~ projection_two_region_trait_bound_closure[317d]::no_relationships_early[0]) with substs [ '_#1r, '_#2r, '_#3r, @@ -91,7 +91,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:32 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:43 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, @@ -114,7 +114,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:10 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ + = note: defining type: DefId(0:38 ~ projection_two_region_trait_bound_closure[317d]::projection_outlives[0]) with substs [ '_#1r, '_#2r, '_#3r, @@ -127,7 +127,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:37 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:49 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, @@ -150,7 +150,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:11 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [ + = note: defining type: DefId(0:44 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive1[0]) with substs [ '_#1r, '_#2r, '_#3r, @@ -163,7 +163,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:42 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:55 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, '_#3r, @@ -186,7 +186,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:12 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [ + = note: defining type: DefId(0:50 ~ projection_two_region_trait_bound_closure[317d]::elements_outlive2[0]) with substs [ '_#1r, '_#2r, '_#3r, @@ -199,7 +199,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:46 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:60 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -221,7 +221,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:13 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [ + = note: defining type: DefId(0:56 ~ projection_two_region_trait_bound_closure[317d]::two_regions[0]) with substs [ '_#1r, T, ] @@ -243,7 +243,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:50 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:65 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -265,7 +265,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:14 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [ + = note: defining type: DefId(0:61 ~ projection_two_region_trait_bound_closure[317d]::two_regions_outlive[0]) with substs [ '_#1r, '_#2r, T, @@ -277,7 +277,7 @@ note: External requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:53 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:69 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -298,7 +298,7 @@ LL | | with_signature(cell, t, |cell, t| require(cell, t)); LL | | } | |_^ | - = note: defining type: DefId(0/0:15 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [ + = note: defining type: DefId(0:66 ~ projection_two_region_trait_bound_closure[317d]::one_region[0]) with substs [ '_#1r, T, ] diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 6f3071becfd0e..2ed94df1f3478 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -4,10 +4,10 @@ note: External requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:14 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:20 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) T)), ] = note: number of external vids: 2 = note: where T: '_#1r @@ -21,7 +21,7 @@ LL | | twice(cell, value, |a, b| invoke(a, b)); LL | | } | |_^ | - = note: defining type: DefId(0/0:5 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [ + = note: defining type: DefId(0:18 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [ T, ] @@ -31,10 +31,10 @@ note: External requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:24 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [ T, i16, - for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0:0), 's)) T)), + for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed(crate0:DefIndex(0), 's)) T)), ] = note: late-bound region is '_#2r = note: number of external vids: 3 @@ -49,7 +49,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [ + = note: defining type: DefId(0:21 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [ T, ] @@ -59,7 +59,7 @@ error[E0309]: the parameter type `T` may not live long enough LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(1:15), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:21 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]), BrNamed(crate0:DefIndex(22), 'a))`... error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index cdb715762031f..d689949969d7e 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -4,7 +4,7 @@ note: External requirements LL | with_signature(x, |y| y) | ^^^^^ | - = note: defining type: DefId(0/1:14 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:20 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -25,7 +25,7 @@ LL | | LL | | } | |_^ | - = note: defining type: DefId(0/0:5 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [ + = note: defining type: DefId(0:17 ~ ty_param_closure_outlives_from_return_type[317d]::no_region[0]) with substs [ '_#1r, T, ] diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index 68798a335f9df..11444c9f72bef 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -11,7 +11,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:16 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:23 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]::{{closure}}[0]) with closure substs [ T, i32, extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)), @@ -32,7 +32,7 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [ + = note: defining type: DefId(0:20 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]) with substs [ T, ] @@ -49,7 +49,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:6 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(1:14), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:20 ~ ty_param_closure_outlives_from_where_clause[317d]::no_region[0]), BrNamed(crate0:DefIndex(21), 'a))`... note: External requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26 @@ -64,7 +64,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:19 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:27 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -85,7 +85,7 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:7 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [ + = note: defining type: DefId(0:24 ~ ty_param_closure_outlives_from_where_clause[317d]::correct_region[0]) with substs [ '_#1r, T, ] @@ -101,7 +101,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:23 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:32 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]::{{closure}}[0]) with closure substs [ '_#1r, T, i32, @@ -123,7 +123,7 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [ + = note: defining type: DefId(0:28 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]) with substs [ '_#1r, T, ] @@ -139,7 +139,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0/0:8 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(1:20), 'a))`... + = help: consider adding an explicit lifetime bound `T: ReFree(DefId(0:28 ~ ty_param_closure_outlives_from_where_clause[317d]::wrong_region[0]), BrNamed(crate0:DefIndex(29), 'a))`... note: External requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26 @@ -151,7 +151,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: DefId(0/1:27 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ + = note: defining type: DefId(0:37 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]::{{closure}}[0]) with closure substs [ '_#1r, '_#2r, T, @@ -173,7 +173,7 @@ LL | | }) LL | | } | |_^ | - = note: defining type: DefId(0/0:9 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [ + = note: defining type: DefId(0:33 ~ ty_param_closure_outlives_from_where_clause[317d]::outlives_region[0]) with substs [ '_#1r, '_#2r, T, diff --git a/src/test/ui/parser/ascii-only-character-escape.stderr b/src/test/ui/parser/ascii-only-character-escape.stderr index 8a981e8d62e2b..391677917580b 100644 --- a/src/test/ui/parser/ascii-only-character-escape.stderr +++ b/src/test/ui/parser/ascii-only-character-escape.stderr @@ -1,20 +1,20 @@ error: this form of character escape may only be used with characters in the range [\x00-\x7f] - --> $DIR/ascii-only-character-escape.rs:4:16 + --> $DIR/ascii-only-character-escape.rs:4:14 | LL | let x = "\x80"; - | ^^ + | ^^^^ error: this form of character escape may only be used with characters in the range [\x00-\x7f] - --> $DIR/ascii-only-character-escape.rs:5:16 + --> $DIR/ascii-only-character-escape.rs:5:14 | LL | let y = "\xff"; - | ^^ + | ^^^^ error: this form of character escape may only be used with characters in the range [\x00-\x7f] - --> $DIR/ascii-only-character-escape.rs:6:16 + --> $DIR/ascii-only-character-escape.rs:6:14 | LL | let z = "\xe2"; - | ^^ + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/parser/attr-bad-meta-2.stderr b/src/test/ui/parser/attr-bad-meta-2.stderr index ffbfc583e8a75..2d772dae69125 100644 --- a/src/test/ui/parser/attr-bad-meta-2.stderr +++ b/src/test/ui/parser/attr-bad-meta-2.stderr @@ -1,8 +1,8 @@ error: unexpected token: `]` - --> $DIR/attr-bad-meta-2.rs:1:8 + --> $DIR/attr-bad-meta-2.rs:1:9 | LL | #[path =] - | ^ + | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/byte-literals.stderr b/src/test/ui/parser/byte-literals.stderr index 28385f34f2ab2..58a5797b90776 100644 --- a/src/test/ui/parser/byte-literals.stderr +++ b/src/test/ui/parser/byte-literals.stderr @@ -34,11 +34,11 @@ error: byte constant must be ASCII. Use a \xHH escape for a non-ASCII byte LL | b'é'; | ^ -error: unterminated byte constant: b'a - --> $DIR/byte-literals.rs:14:5 +error: unterminated byte constant + --> $DIR/byte-literals.rs:14:6 | LL | b'a - | ^^^ + | ^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/parser/byte-string-literals.stderr b/src/test/ui/parser/byte-string-literals.stderr index b855484444010..eeb2fcd12320b 100644 --- a/src/test/ui/parser/byte-string-literals.stderr +++ b/src/test/ui/parser/byte-string-literals.stderr @@ -23,10 +23,10 @@ LL | b"é"; | ^ error: unterminated double quote byte string - --> $DIR/byte-string-literals.rs:9:7 + --> $DIR/byte-string-literals.rs:9:6 | LL | b"a - | _______^ + | ______^ LL | | } | |__^ diff --git a/src/test/ui/parser/expr-as-stmt.fixed b/src/test/ui/parser/expr-as-stmt.fixed new file mode 100644 index 0000000000000..1ce6f9c25034f --- /dev/null +++ b/src/test/ui/parser/expr-as-stmt.fixed @@ -0,0 +1,40 @@ +// run-rustfix +#![allow(unused_variables)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +fn foo() -> i32 { + ({2}) + {2} //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn bar() -> i32 { + ({2}) + 2 //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn zul() -> u32 { + let foo = 3; + ({ 42 }) + foo; //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types + 32 +} + +fn baz() -> i32 { + ({ 3 }) * 3 //~ ERROR type `{integer}` cannot be dereferenced + //~^ ERROR mismatched types +} + +fn qux(a: Option, b: Option) -> bool { + (if let Some(x) = a { true } else { false }) + && //~ ERROR expected expression + if let Some(y) = a { true } else { false } +} + +fn moo(x: u32) -> bool { + (match x { + _ => 1, + }) > 0 //~ ERROR expected expression +} + +fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.rs b/src/test/ui/parser/expr-as-stmt.rs new file mode 100644 index 0000000000000..b526c17488eaf --- /dev/null +++ b/src/test/ui/parser/expr-as-stmt.rs @@ -0,0 +1,40 @@ +// run-rustfix +#![allow(unused_variables)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +fn foo() -> i32 { + {2} + {2} //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn bar() -> i32 { + {2} + 2 //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types +} + +fn zul() -> u32 { + let foo = 3; + { 42 } + foo; //~ ERROR expected expression, found `+` + //~^ ERROR mismatched types + 32 +} + +fn baz() -> i32 { + { 3 } * 3 //~ ERROR type `{integer}` cannot be dereferenced + //~^ ERROR mismatched types +} + +fn qux(a: Option, b: Option) -> bool { + if let Some(x) = a { true } else { false } + && //~ ERROR expected expression + if let Some(y) = a { true } else { false } +} + +fn moo(x: u32) -> bool { + match x { + _ => 1, + } > 0 //~ ERROR expected expression +} + +fn main() {} diff --git a/src/test/ui/parser/expr-as-stmt.stderr b/src/test/ui/parser/expr-as-stmt.stderr new file mode 100644 index 0000000000000..a11209998a7d5 --- /dev/null +++ b/src/test/ui/parser/expr-as-stmt.stderr @@ -0,0 +1,92 @@ +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:7:9 + | +LL | {2} + {2} + | --- ^ expected expression + | | + | help: parentheses are required to parse this as an expression: `({2})` + +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:12:9 + | +LL | {2} + 2 + | --- ^ expected expression + | | + | help: parentheses are required to parse this as an expression: `({2})` + +error: expected expression, found `+` + --> $DIR/expr-as-stmt.rs:18:12 + | +LL | { 42 } + foo; + | ------ ^ expected expression + | | + | help: parentheses are required to parse this as an expression: `({ 42 })` + +error: expected expression, found `&&` + --> $DIR/expr-as-stmt.rs:30:5 + | +LL | if let Some(x) = a { true } else { false } + | ------------------------------------------ help: parentheses are required to parse this as an expression: `(if let Some(x) = a { true } else { false })` +LL | && + | ^^ expected expression + +error: expected expression, found `>` + --> $DIR/expr-as-stmt.rs:37:7 + | +LL | } > 0 + | ^ expected expression +help: parentheses are required to parse this as an expression + | +LL | (match x { +LL | _ => 1, +LL | }) > 0 + | + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:7:6 + | +LL | {2} + {2} + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:12:6 + | +LL | {2} + 2 + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:18:7 + | +LL | { 42 } + foo; + | ^^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0308]: mismatched types + --> $DIR/expr-as-stmt.rs:24:7 + | +LL | { 3 } * 3 + | ^ expected (), found integer + | + = note: expected type `()` + found type `{integer}` + +error[E0614]: type `{integer}` cannot be dereferenced + --> $DIR/expr-as-stmt.rs:24:11 + | +LL | { 3 } * 3 + | ----- ^^^ + | | + | help: parentheses are required to parse this as an expression: `({ 3 })` + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0308, E0614. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.rs b/src/test/ui/parser/issue-23620-invalid-escapes.rs index b4b8f1fc0b0ab..53629973a1b5f 100644 --- a/src/test/ui/parser/issue-23620-invalid-escapes.rs +++ b/src/test/ui/parser/issue-23620-invalid-escapes.rs @@ -9,32 +9,27 @@ fn main() { let _ = b'\u'; //~^ ERROR incorrect unicode escape sequence - //~^^ ERROR unicode escape sequences cannot be used as a byte or in a byte string let _ = b'\x5'; //~^ ERROR numeric character escape is too short let _ = b'\xxy'; //~^ ERROR invalid character in numeric character escape: x - //~^^ ERROR invalid character in numeric character escape: y let _ = '\x5'; //~^ ERROR numeric character escape is too short let _ = '\xxy'; //~^ ERROR invalid character in numeric character escape: x - //~^^ ERROR invalid character in numeric character escape: y let _ = b"\u{a4a4} \xf \u"; //~^ ERROR unicode escape sequences cannot be used as a byte or in a byte string //~^^ ERROR invalid character in numeric character escape: //~^^^ ERROR incorrect unicode escape sequence - //~^^^^ ERROR unicode escape sequences cannot be used as a byte or in a byte string let _ = "\xf \u"; //~^ ERROR invalid character in numeric character escape: - //~^^ ERROR form of character escape may only be used with characters in the range [\x00-\x7f] - //~^^^ ERROR incorrect unicode escape sequence + //~^^ ERROR incorrect unicode escape sequence let _ = "\u8f"; //~^ ERROR incorrect unicode escape sequence diff --git a/src/test/ui/parser/issue-23620-invalid-escapes.stderr b/src/test/ui/parser/issue-23620-invalid-escapes.stderr index 295ba3b73e861..5fabc1d7e4326 100644 --- a/src/test/ui/parser/issue-23620-invalid-escapes.stderr +++ b/src/test/ui/parser/issue-23620-invalid-escapes.stderr @@ -18,88 +18,58 @@ LL | let _ = b'\u'; | = help: format of unicode escape sequences is `\u{...}` -error: unicode escape sequences cannot be used as a byte or in a byte string - --> $DIR/issue-23620-invalid-escapes.rs:10:15 - | -LL | let _ = b'\u'; - | ^^ - error: numeric character escape is too short - --> $DIR/issue-23620-invalid-escapes.rs:14:17 + --> $DIR/issue-23620-invalid-escapes.rs:13:15 | LL | let _ = b'\x5'; - | ^ + | ^^^ error: invalid character in numeric character escape: x - --> $DIR/issue-23620-invalid-escapes.rs:17:17 + --> $DIR/issue-23620-invalid-escapes.rs:16:17 | LL | let _ = b'\xxy'; | ^ -error: invalid character in numeric character escape: y - --> $DIR/issue-23620-invalid-escapes.rs:17:18 - | -LL | let _ = b'\xxy'; - | ^ - error: numeric character escape is too short - --> $DIR/issue-23620-invalid-escapes.rs:21:16 + --> $DIR/issue-23620-invalid-escapes.rs:19:14 | LL | let _ = '\x5'; - | ^ + | ^^^ error: invalid character in numeric character escape: x - --> $DIR/issue-23620-invalid-escapes.rs:24:16 + --> $DIR/issue-23620-invalid-escapes.rs:22:16 | LL | let _ = '\xxy'; | ^ -error: invalid character in numeric character escape: y - --> $DIR/issue-23620-invalid-escapes.rs:24:17 - | -LL | let _ = '\xxy'; - | ^ - error: unicode escape sequences cannot be used as a byte or in a byte string - --> $DIR/issue-23620-invalid-escapes.rs:28:15 + --> $DIR/issue-23620-invalid-escapes.rs:25:15 | LL | let _ = b"\u{a4a4} \xf \u"; | ^^^^^^^^ error: invalid character in numeric character escape: - --> $DIR/issue-23620-invalid-escapes.rs:28:27 + --> $DIR/issue-23620-invalid-escapes.rs:25:27 | LL | let _ = b"\u{a4a4} \xf \u"; | ^ error: incorrect unicode escape sequence - --> $DIR/issue-23620-invalid-escapes.rs:28:28 + --> $DIR/issue-23620-invalid-escapes.rs:25:28 | LL | let _ = b"\u{a4a4} \xf \u"; | ^^ incorrect unicode escape sequence | = help: format of unicode escape sequences is `\u{...}` -error: unicode escape sequences cannot be used as a byte or in a byte string - --> $DIR/issue-23620-invalid-escapes.rs:28:28 - | -LL | let _ = b"\u{a4a4} \xf \u"; - | ^^ - error: invalid character in numeric character escape: - --> $DIR/issue-23620-invalid-escapes.rs:34:17 + --> $DIR/issue-23620-invalid-escapes.rs:30:17 | LL | let _ = "\xf \u"; | ^ -error: this form of character escape may only be used with characters in the range [\x00-\x7f] - --> $DIR/issue-23620-invalid-escapes.rs:34:16 - | -LL | let _ = "\xf \u"; - | ^^ - error: incorrect unicode escape sequence - --> $DIR/issue-23620-invalid-escapes.rs:34:18 + --> $DIR/issue-23620-invalid-escapes.rs:30:18 | LL | let _ = "\xf \u"; | ^^ incorrect unicode escape sequence @@ -107,12 +77,12 @@ LL | let _ = "\xf \u"; = help: format of unicode escape sequences is `\u{...}` error: incorrect unicode escape sequence - --> $DIR/issue-23620-invalid-escapes.rs:39:14 + --> $DIR/issue-23620-invalid-escapes.rs:34:14 | LL | let _ = "\u8f"; | ^^-- - | | - | help: format of unicode escape sequences uses braces: `\u{8f}` + | | + | help: format of unicode escape sequences uses braces: `\u{8f}` -error: aborting due to 18 previous errors +error: aborting due to 13 previous errors diff --git a/src/test/ui/parser/lex-bad-char-literals-1.stderr b/src/test/ui/parser/lex-bad-char-literals-1.stderr index 414ad81512ae5..000d155c26833 100644 --- a/src/test/ui/parser/lex-bad-char-literals-1.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-1.stderr @@ -1,14 +1,14 @@ error: numeric character escape is too short - --> $DIR/lex-bad-char-literals-1.rs:3:8 + --> $DIR/lex-bad-char-literals-1.rs:3:6 | LL | '\x1' - | ^ + | ^^^ error: numeric character escape is too short - --> $DIR/lex-bad-char-literals-1.rs:7:8 + --> $DIR/lex-bad-char-literals-1.rs:7:6 | LL | "\x1" - | ^ + | ^^^ error: unknown character escape: \u{25cf} --> $DIR/lex-bad-char-literals-1.rs:11:7 diff --git a/src/test/ui/parser/lex-bad-char-literals-2.stderr b/src/test/ui/parser/lex-bad-char-literals-2.stderr index 4c1c5c29f472e..b0a4ed02434b4 100644 --- a/src/test/ui/parser/lex-bad-char-literals-2.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-2.stderr @@ -3,6 +3,10 @@ error: character literal may only contain one codepoint | LL | 'nope' | ^^^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | "nope" + | ^^^^^^ error[E0601]: `main` function not found in crate `lex_bad_char_literals_2` | diff --git a/src/test/ui/parser/lex-bad-char-literals-4.rs b/src/test/ui/parser/lex-bad-char-literals-4.rs index e13f11f36df48..de0a19df99360 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.rs +++ b/src/test/ui/parser/lex-bad-char-literals-4.rs @@ -1,5 +1,5 @@ // // This test needs to the last one appearing in this file as it kills the parser static c: char = - '● //~ ERROR: character literal may only contain one codepoint + '● //~ ERROR: unterminated character literal ; diff --git a/src/test/ui/parser/lex-bad-char-literals-4.stderr b/src/test/ui/parser/lex-bad-char-literals-4.stderr index 7bcca3761fc60..8f8f806f6cf61 100644 --- a/src/test/ui/parser/lex-bad-char-literals-4.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-4.stderr @@ -1,8 +1,8 @@ -error: character literal may only contain one codepoint: '● +error: unterminated character literal --> $DIR/lex-bad-char-literals-4.rs:4:5 | LL | '● - | ^^ + | ^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index 74959c9a4ed4a..a7bbe05e94b7b 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -3,18 +3,30 @@ error: character literal may only contain one codepoint | LL | let x: &str = 'ab'; | ^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let x: &str = "ab"; + | ^^^^ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:4:19 | LL | let y: char = 'cd'; | ^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let y: char = "cd"; + | ^^^^ error: character literal may only contain one codepoint --> $DIR/lex-bad-char-literals-6.rs:6:13 | LL | let z = 'ef'; | ^^^^ +help: if you meant to write a `str` literal, use double quotes + | +LL | let z = "ef"; + | ^^^^ error[E0277]: can't compare `&str` with `char` --> $DIR/lex-bad-char-literals-6.rs:9:10 diff --git a/src/test/ui/parser/lex-bad-char-literals-7.rs b/src/test/ui/parser/lex-bad-char-literals-7.rs new file mode 100644 index 0000000000000..70eafcb91dacb --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-7.rs @@ -0,0 +1,14 @@ +// compile-flags: -Z continue-parse-after-error +fn main() { + let _: char = ''; + //~^ ERROR: empty character literal + let _: char = '\u{}'; + //~^ ERROR: empty unicode escape (must have at least 1 hex digit) + + // Next two are OK, but may befool error recovery + let _ = '/'; + let _ = b'/'; + + let _ = ' hello // here's a comment + //~^ ERROR: unterminated character literal +} diff --git a/src/test/ui/parser/lex-bad-char-literals-7.stderr b/src/test/ui/parser/lex-bad-char-literals-7.stderr new file mode 100644 index 0000000000000..e1ba3c3ee0f17 --- /dev/null +++ b/src/test/ui/parser/lex-bad-char-literals-7.stderr @@ -0,0 +1,20 @@ +error: empty character literal + --> $DIR/lex-bad-char-literals-7.rs:3:20 + | +LL | let _: char = ''; + | ^ + +error: empty unicode escape (must have at least 1 hex digit) + --> $DIR/lex-bad-char-literals-7.rs:5:20 + | +LL | let _: char = '\u{}'; + | ^^^^ + +error: unterminated character literal + --> $DIR/lex-bad-char-literals-7.rs:12:13 + | +LL | let _ = ' hello // here's a comment + | ^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/parser/macro/literals-are-validated-before-expansion.rs b/src/test/ui/parser/macro/literals-are-validated-before-expansion.rs new file mode 100644 index 0000000000000..c3fc754b5567f --- /dev/null +++ b/src/test/ui/parser/macro/literals-are-validated-before-expansion.rs @@ -0,0 +1,10 @@ +macro_rules! black_hole { + ($($tt:tt)*) => {} +} + +fn main() { + black_hole! { '\u{FFFFFF}' } + //~^ ERROR: invalid unicode character escape + black_hole! { "this is surrogate: \u{DAAA}" } + //~^ ERROR: invalid unicode character escape +} diff --git a/src/test/ui/parser/macro/literals-are-validated-before-expansion.stderr b/src/test/ui/parser/macro/literals-are-validated-before-expansion.stderr new file mode 100644 index 0000000000000..d20eb0fb30a49 --- /dev/null +++ b/src/test/ui/parser/macro/literals-are-validated-before-expansion.stderr @@ -0,0 +1,18 @@ +error: invalid unicode character escape + --> $DIR/literals-are-validated-before-expansion.rs:6:20 + | +LL | black_hole! { '\u{FFFFFF}' } + | ^^^^^^^^^^ + | + = help: unicode escape must be at most 10FFFF + +error: invalid unicode character escape + --> $DIR/literals-are-validated-before-expansion.rs:8:39 + | +LL | black_hole! { "this is surrogate: \u{DAAA}" } + | ^^^^^^^^ + | + = help: unicode escape must not be a surrogate + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/match-arrows-block-then-binop.rs b/src/test/ui/parser/match-arrows-block-then-binop.rs index 1a40d67492990..56c917c7462f2 100644 --- a/src/test/ui/parser/match-arrows-block-then-binop.rs +++ b/src/test/ui/parser/match-arrows-block-then-binop.rs @@ -1,7 +1,7 @@ fn main() { - - match 0 { + let _ = match 0 { 0 => { + 0 } + 5 //~ ERROR expected pattern, found `+` - } + }; } diff --git a/src/test/ui/parser/match-arrows-block-then-binop.stderr b/src/test/ui/parser/match-arrows-block-then-binop.stderr index a844cac189aa1..bb7df30783acd 100644 --- a/src/test/ui/parser/match-arrows-block-then-binop.stderr +++ b/src/test/ui/parser/match-arrows-block-then-binop.stderr @@ -3,6 +3,12 @@ error: expected pattern, found `+` | LL | } + 5 | ^ expected pattern +help: parentheses are required to parse this as an expression + | +LL | 0 => ({ +LL | 0 +LL | }) + 5 + | error: aborting due to previous error diff --git a/src/test/ui/parser/new-unicode-escapes-1.stderr b/src/test/ui/parser/new-unicode-escapes-1.stderr index a8da50951ddf3..22d6a0981ffd6 100644 --- a/src/test/ui/parser/new-unicode-escapes-1.stderr +++ b/src/test/ui/parser/new-unicode-escapes-1.stderr @@ -1,8 +1,8 @@ error: unterminated unicode escape (needed a `}`) - --> $DIR/new-unicode-escapes-1.rs:2:21 + --> $DIR/new-unicode-escapes-1.rs:2:14 | LL | let s = "\u{2603"; - | ^ + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/new-unicode-escapes-2.stderr b/src/test/ui/parser/new-unicode-escapes-2.stderr index ede49cdf7e1d1..b5148279c7450 100644 --- a/src/test/ui/parser/new-unicode-escapes-2.stderr +++ b/src/test/ui/parser/new-unicode-escapes-2.stderr @@ -1,8 +1,8 @@ error: overlong unicode escape (must have at most 6 hex digits) - --> $DIR/new-unicode-escapes-2.rs:2:17 + --> $DIR/new-unicode-escapes-2.rs:2:14 | LL | let s = "\u{260311111111}"; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/parser/new-unicode-escapes-3.stderr b/src/test/ui/parser/new-unicode-escapes-3.stderr index 59cfb988f2897..361698467f97d 100644 --- a/src/test/ui/parser/new-unicode-escapes-3.stderr +++ b/src/test/ui/parser/new-unicode-escapes-3.stderr @@ -1,16 +1,16 @@ error: invalid unicode character escape - --> $DIR/new-unicode-escapes-3.rs:2:14 + --> $DIR/new-unicode-escapes-3.rs:2:15 | LL | let s1 = "\u{d805}"; - | ^^^^^^^^^^ + | ^^^^^^^^ | = help: unicode escape must not be a surrogate error: invalid unicode character escape - --> $DIR/new-unicode-escapes-3.rs:3:14 + --> $DIR/new-unicode-escapes-3.rs:3:15 | LL | let s2 = "\u{ffffff}"; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^ | = help: unicode escape must be at most 10FFFF diff --git a/src/test/ui/parser/pat-tuple-5.stderr b/src/test/ui/parser/pat-tuple-5.stderr index 61ae40b355d38..f9832214c6800 100644 --- a/src/test/ui/parser/pat-tuple-5.stderr +++ b/src/test/ui/parser/pat-tuple-5.stderr @@ -1,8 +1,8 @@ error: unexpected token: `)` - --> $DIR/pat-tuple-5.rs:3:14 + --> $DIR/pat-tuple-5.rs:3:16 | LL | (pat ..) => {} - | ^^ + | ^ error: aborting due to previous error diff --git a/src/test/ui/parser/struct-literal-in-for.stderr b/src/test/ui/parser/struct-literal-in-for.stderr index 3c3f6e7f032f6..29af72a5d23d0 100644 --- a/src/test/ui/parser/struct-literal-in-for.stderr +++ b/src/test/ui/parser/struct-literal-in-for.stderr @@ -6,7 +6,7 @@ LL | for x in Foo { LL | | x: 3 LL | | }.hi() { | |_____^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | for x in (Foo { LL | x: 3 diff --git a/src/test/ui/parser/struct-literal-in-if.stderr b/src/test/ui/parser/struct-literal-in-if.stderr index 851c495abb4b0..e76c1cb45dd4e 100644 --- a/src/test/ui/parser/struct-literal-in-if.stderr +++ b/src/test/ui/parser/struct-literal-in-if.stderr @@ -6,7 +6,7 @@ LL | if Foo { LL | | x: 3 LL | | }.hi() { | |_____^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | if (Foo { LL | x: 3 diff --git a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr index 0058e8981cd25..95b0882b7aeb5 100644 --- a/src/test/ui/parser/struct-literal-in-match-discriminant.stderr +++ b/src/test/ui/parser/struct-literal-in-match-discriminant.stderr @@ -6,7 +6,7 @@ LL | match Foo { LL | | x: 3 LL | | } { | |_____^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | match (Foo { LL | x: 3 diff --git a/src/test/ui/parser/struct-literal-in-while.stderr b/src/test/ui/parser/struct-literal-in-while.stderr index 9959a57be8596..acd31b477dc27 100644 --- a/src/test/ui/parser/struct-literal-in-while.stderr +++ b/src/test/ui/parser/struct-literal-in-while.stderr @@ -6,7 +6,7 @@ LL | while Foo { LL | | x: 3 LL | | }.hi() { | |_____^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | while (Foo { LL | x: 3 diff --git a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr index 81f7a91ddb38a..24078074161e6 100644 --- a/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr +++ b/src/test/ui/parser/struct-literal-restrictions-in-lamda.stderr @@ -6,7 +6,7 @@ LL | while || Foo { LL | | x: 3 LL | | }.hi() { | |_____^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | while || (Foo { LL | x: 3 diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr index 261e95229a76e..260c2e04d74f7 100644 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ b/src/test/ui/pattern/const-pat-ice.stderr @@ -1,4 +1,4 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1071:5 +thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir/hair/pattern/_match.rs:1083:5 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. error: internal compiler error: unexpected panic diff --git a/src/test/ui/proc-macro/no-missing-docs.rs b/src/test/ui/proc-macro/no-missing-docs.rs new file mode 100644 index 0000000000000..e5a5f8beb4585 --- /dev/null +++ b/src/test/ui/proc-macro/no-missing-docs.rs @@ -0,0 +1,16 @@ +//! Verify that the `decls` module implicitly added by the compiler does not cause `missing_docs` +//! warnings. + +// compile-pass +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![deny(missing_docs)] + +extern crate proc_macro; +use proc_macro::*; + +/// Foo1. +#[proc_macro] +pub fn foo1(input: TokenStream) -> TokenStream { input } diff --git a/src/test/ui/reachable/expr_if.rs b/src/test/ui/reachable/expr_if.rs index ed43bd8c6895e..a3d54892de5bb 100644 --- a/src/test/ui/reachable/expr_if.rs +++ b/src/test/ui/reachable/expr_if.rs @@ -4,7 +4,7 @@ #![deny(unreachable_code)] fn foo() { - if {return} { + if {return} { //~ ERROR unreachable block in `if` expression println!("Hello, world!"); } } diff --git a/src/test/ui/reachable/expr_if.stderr b/src/test/ui/reachable/expr_if.stderr index d11471da1a6a3..f1690e595e5d1 100644 --- a/src/test/ui/reachable/expr_if.stderr +++ b/src/test/ui/reachable/expr_if.stderr @@ -1,15 +1,25 @@ -error: unreachable statement - --> $DIR/expr_if.rs:27:5 +error: unreachable block in `if` expression + --> $DIR/expr_if.rs:7:17 | -LL | println!("But I am."); - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | if {return} { + | _________________^ +LL | | println!("Hello, world!"); +LL | | } + | |_____^ | note: lint level defined here --> $DIR/expr_if.rs:4:9 | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ + +error: unreachable statement + --> $DIR/expr_if.rs:27:5 + | +LL | println!("But I am."); + | ^^^^^^^^^^^^^^^^^^^^^^ + | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs new file mode 100644 index 0000000000000..8cb9a8cf1f613 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/auxiliary/uninhabited.rs @@ -0,0 +1,33 @@ +#![crate_type = "rlib"] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs new file mode 100644 index 0000000000000..80b9dc4c1c338 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.rs @@ -0,0 +1,38 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +// This test checks that uninhabited non-exhaustive types cannot coerce to any type, as the never +// type can. + +struct A; + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr new file mode 100644 index 0000000000000..d05ee1d39ec35 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coercions.rs:23:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum` + | + = note: expected type `A` + found type `uninhabited::UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:27:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct` + | + = note: expected type `A` + found type `uninhabited::UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:31:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct` + | + = note: expected type `A` + found type `uninhabited::UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions.rs:35:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `uninhabited::UninhabitedVariants` + | + = note: expected type `A` + found type `uninhabited::UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs new file mode 100644 index 0000000000000..803a542f8aa4b --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.rs @@ -0,0 +1,46 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that uninhabited non-exhaustive types defined in the same crate cannot coerce +// to any type, as the never type can. + +fn can_coerce_never_type_to_anything(x: !) -> A { + x +} + +fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + x //~ ERROR mismatched types +} + +fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + x //~ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr new file mode 100644 index 0000000000000..8f6b709bb1f34 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions_same_crate.stderr @@ -0,0 +1,47 @@ +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:31:5 + | +LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `UninhabitedEnum` + | + = note: expected type `A` + found type `UninhabitedEnum` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:35:5 + | +LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `UninhabitedTupleStruct` + | + = note: expected type `A` + found type `UninhabitedTupleStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:39:5 + | +LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found struct `UninhabitedStruct` + | + = note: expected type `A` + found type `UninhabitedStruct` + +error[E0308]: mismatched types + --> $DIR/coercions_same_crate.rs:43:5 + | +LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { + | - expected `A` because of return type +LL | x + | ^ expected struct `A`, found enum `UninhabitedVariants` + | + = note: expected type `A` + found type `UninhabitedVariants` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs new file mode 100644 index 0000000000000..98a7fdbc5049a --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.rs @@ -0,0 +1,36 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr new file mode 100644 index 0000000000000..af82022e1da99 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `uninhabited::IndirectUninhabitedEnum` is not handled + --> $DIR/indirect_match.rs:19:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `uninhabited::IndirectUninhabitedStruct` is not handled + --> $DIR/indirect_match.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `uninhabited::IndirectUninhabitedTupleStruct` is not handled + --> $DIR/indirect_match.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `uninhabited::IndirectUninhabitedVariants` is not handled + --> $DIR/indirect_match.rs:33:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs new file mode 100644 index 0000000000000..3c8d495e12cb6 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.rs @@ -0,0 +1,52 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from the defining crate will not compile without `#![feature(exhaustive_patterns)]`. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr new file mode 100644 index 0000000000000..27b120792d6d1 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_same_crate.stderr @@ -0,0 +1,59 @@ +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedEnum` of type `IndirectUninhabitedEnum` is not handled + --> $DIR/indirect_match_same_crate.rs:35:11 + | +LL | pub struct IndirectUninhabitedEnum(UninhabitedEnum); + | ---------------------------------------------------- + | | | + | | variant not covered + | `IndirectUninhabitedEnum` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedStruct` of type `IndirectUninhabitedStruct` is not handled + --> $DIR/indirect_match_same_crate.rs:39:11 + | +LL | pub struct IndirectUninhabitedStruct(UninhabitedStruct); + | -------------------------------------------------------- + | | | + | | variant not covered + | `IndirectUninhabitedStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedTupleStruct` of type `IndirectUninhabitedTupleStruct` is not handled + --> $DIR/indirect_match_same_crate.rs:43:11 + | +LL | pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + | ------------------------------------------------------------------ + | | | + | | variant not covered + | `IndirectUninhabitedTupleStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `IndirectUninhabitedVariants` of type `IndirectUninhabitedVariants` is not handled + --> $DIR/indirect_match_same_crate.rs:49:11 + | +LL | pub struct IndirectUninhabitedVariants(UninhabitedVariants); + | ------------------------------------------------------------ + | | | + | | variant not covered + | `IndirectUninhabitedVariants` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs new file mode 100644 index 0000000000000..be86519ecb159 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.rs @@ -0,0 +1,40 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + IndirectUninhabitedEnum, + IndirectUninhabitedStruct, + IndirectUninhabitedTupleStruct, + IndirectUninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type through a level of +// indirection from an extern crate will not compile. In particular, this enables the +// `exhaustive_patterns` feature as this can change the branch used in the compiler to determine +// this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr new file mode 100644 index 0000000000000..17a8d01007205 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty + --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 0000000000000..5dbd38e07df02 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,58 @@ +// compile-pass +// skip-codegen +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub struct IndirectUninhabitedEnum(UninhabitedEnum); + +pub struct IndirectUninhabitedStruct(UninhabitedStruct); + +pub struct IndirectUninhabitedTupleStruct(UninhabitedTupleStruct); + +pub struct IndirectUninhabitedVariants(UninhabitedVariants); + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648. + +fn cannot_empty_match_on_empty_enum_to_anything(x: IndirectUninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: IndirectUninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: IndirectUninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything( + x: IndirectUninhabitedVariants, +) -> A { + match x {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs new file mode 100644 index 0000000000000..e54098d4d48b9 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.rs @@ -0,0 +1,34 @@ +// aux-build:uninhabited.rs +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr new file mode 100644 index 0000000000000..de39688f45a4d --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty + --> $DIR/match.rs:19:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `uninhabited::UninhabitedStruct` is not handled + --> $DIR/match.rs:23:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `uninhabited::UninhabitedTupleStruct` is not handled + --> $DIR/match.rs:27:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: multiple patterns of type `uninhabited::UninhabitedVariants` are not handled + --> $DIR/match.rs:31:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs new file mode 100644 index 0000000000000..6405dd3bd65b7 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.rs @@ -0,0 +1,42 @@ +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr new file mode 100644 index 0000000000000..410285a39a945 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_same_crate.stderr @@ -0,0 +1,49 @@ +error[E0004]: non-exhaustive patterns: pattern `UninhabitedStruct` of type `UninhabitedStruct` is not handled + --> $DIR/match_same_crate.rs:31:11 + | +LL | pub struct UninhabitedStruct { + | - ----------------- variant not covered + | _| + | | +LL | | _priv: !, +LL | | } + | |_- `UninhabitedStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: pattern `UninhabitedTupleStruct` of type `UninhabitedTupleStruct` is not handled + --> $DIR/match_same_crate.rs:35:11 + | +LL | pub struct UninhabitedTupleStruct(!); + | ------------------------------------- + | | | + | | variant not covered + | `UninhabitedTupleStruct` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: multiple patterns of type `UninhabitedVariants` are not handled + --> $DIR/match_same_crate.rs:39:11 + | +LL | / pub enum UninhabitedVariants { +LL | | #[non_exhaustive] Tuple(!), + | | ----- variant not covered +LL | | #[non_exhaustive] Struct { x: ! } + | | ------ variant not covered +LL | | } + | |_- `UninhabitedVariants` defined here +... +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs new file mode 100644 index 0000000000000..900dfff652ea6 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.rs @@ -0,0 +1,37 @@ +// aux-build:uninhabited.rs +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] + +extern crate uninhabited; + +use uninhabited::{ + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from an extern crate +// will not compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} //~ ERROR non-exhaustive patterns +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr new file mode 100644 index 0000000000000..48a888bc50be0 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -0,0 +1,35 @@ +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:22:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:26:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:30:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedVariants` is non-empty + --> $DIR/match_with_exhaustive_patterns.rs:34:11 + | +LL | match x {} + | ^ + | + = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs new file mode 100644 index 0000000000000..74922d4bcb5d5 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns_same_crate.rs @@ -0,0 +1,48 @@ +// compile-pass +// skip-codegen +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +struct A; + +// This test checks that an empty match on a non-exhaustive uninhabited type from the defining crate +// will compile. In particular, this enables the `exhaustive_patterns` feature as this can +// change the branch used in the compiler to determine this. +// Codegen is skipped because tests with long names can cause issues on Windows CI, see #60648. + +fn cannot_empty_match_on_empty_enum_to_anything(x: UninhabitedEnum) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_struct_to_anything(x: UninhabitedStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { + match x {} +} + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} +} + +fn main() {} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs new file mode 100644 index 0000000000000..97061310d19e2 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns.rs @@ -0,0 +1,59 @@ +// aux-build:uninhabited.rs +// compile-pass +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] + +extern crate uninhabited; + +use uninhabited::{ + PartiallyInhabitedVariants, + UninhabitedEnum, + UninhabitedStruct, + UninhabitedTupleStruct, + UninhabitedVariants, +}; + +fn uninhabited_enum() -> Option { + None +} + +fn uninhabited_variant() -> Option { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option { + None +} + +fn uninhabited_tuple_struct() -> Option { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are not considered uninhabited from extern crates. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), // This line would normally error. + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), // This line would normally error. + None => (), + } + + // This line would normally error. + while let PartiallyInhabitedVariants::Struct { x, .. } = partially_inhabited_variant() { + } + + while let Some(_x) = uninhabited_struct() { // This line would normally error. + } + + while let Some(_x) = uninhabited_tuple_struct() { // This line would normally error. + } +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs new file mode 100644 index 0000000000000..302a35cab5f90 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.rs @@ -0,0 +1,71 @@ +#![deny(unreachable_patterns)] +#![feature(exhaustive_patterns)] +#![feature(never_type)] +#![feature(non_exhaustive)] + +#[non_exhaustive] +pub enum UninhabitedEnum { +} + +#[non_exhaustive] +pub struct UninhabitedTupleStruct(!); + +#[non_exhaustive] +pub struct UninhabitedStruct { + _priv: !, +} + +pub enum UninhabitedVariants { + #[non_exhaustive] Tuple(!), + #[non_exhaustive] Struct { x: ! } +} + +pub enum PartiallyInhabitedVariants { + Tuple(u8), + #[non_exhaustive] Struct { x: ! } +} + +fn uninhabited_enum() -> Option { + None +} + +fn uninhabited_variant() -> Option { + None +} + +fn partially_inhabited_variant() -> PartiallyInhabitedVariants { + PartiallyInhabitedVariants::Tuple(3) +} + +fn uninhabited_struct() -> Option { + None +} + +fn uninhabited_tuple_struct() -> Option { + None +} + +// This test checks that non-exhaustive types that would normally be considered uninhabited within +// the defining crate are still considered uninhabited. + +fn main() { + match uninhabited_enum() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + match uninhabited_variant() { + Some(_x) => (), //~ ERROR unreachable pattern + None => (), + } + + while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + //~^ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_struct() { //~ ERROR unreachable pattern + } + + while let Some(_x) = uninhabited_tuple_struct() { //~ ERROR unreachable pattern + } +} diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr new file mode 100644 index 0000000000000..72f37d9a60ba8 --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/patterns_same_crate.stderr @@ -0,0 +1,38 @@ +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:53:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + | +note: lint level defined here + --> $DIR/patterns_same_crate.rs:1:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:58:9 + | +LL | Some(_x) => (), + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:62:15 + | +LL | while let PartiallyInhabitedVariants::Struct { x } = partially_inhabited_variant() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:66:15 + | +LL | while let Some(_x) = uninhabited_struct() { + | ^^^^^^^^ + +error: unreachable pattern + --> $DIR/patterns_same_crate.rs:69:15 + | +LL | while let Some(_x) = uninhabited_tuple_struct() { + | ^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/save-analysis/issue-59134-0.rs b/src/test/ui/save-analysis/issue-59134-0.rs new file mode 100644 index 0000000000000..3158328b3ff15 --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-0.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zsave-analysis + +// Check that this doesn't ICE when processing associated const (field expr). + +pub fn f() { + trait Trait {} + impl Trait { + const FLAG: u32 = bogus.field; //~ ERROR cannot find value `bogus` + } +} + +fn main() {} diff --git a/src/test/ui/save-analysis/issue-59134-0.stderr b/src/test/ui/save-analysis/issue-59134-0.stderr new file mode 100644 index 0000000000000..4e9b2e6fdeb4d --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-0.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `bogus` in this scope + --> $DIR/issue-59134-0.rs:8:27 + | +LL | const FLAG: u32 = bogus.field; + | ^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/save-analysis/issue-59134-1.rs b/src/test/ui/save-analysis/issue-59134-1.rs new file mode 100644 index 0000000000000..3cb629777a497 --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-1.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zsave-analysis + +// Check that this doesn't ICE when processing associated const (type). + +fn func() { + trait Trait { + type MyType; + const CONST: Self::MyType = bogus.field; //~ ERROR cannot find value `bogus` + } +} + +fn main() {} diff --git a/src/test/ui/save-analysis/issue-59134-1.stderr b/src/test/ui/save-analysis/issue-59134-1.stderr new file mode 100644 index 0000000000000..bdc335eaac041 --- /dev/null +++ b/src/test/ui/save-analysis/issue-59134-1.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `bogus` in this scope + --> $DIR/issue-59134-1.rs:8:37 + | +LL | const CONST: Self::MyType = bogus.field; + | ^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/str/str-as-char.fixed b/src/test/ui/str/str-as-char.fixed index accead5c850cc..42bbef8391785 100644 --- a/src/test/ui/str/str-as-char.fixed +++ b/src/test/ui/str/str-as-char.fixed @@ -1,6 +1,5 @@ // run-rustfix fn main() { - println!("{}", "●●"); //~ ERROR character literal may only contain one codepoint - //~^ ERROR format argument must be a string literal + println!("●●"); //~ ERROR character literal may only contain one codepoint } diff --git a/src/test/ui/str/str-as-char.rs b/src/test/ui/str/str-as-char.rs index fb179ec7245d2..09b9dfc590db3 100644 --- a/src/test/ui/str/str-as-char.rs +++ b/src/test/ui/str/str-as-char.rs @@ -2,5 +2,4 @@ fn main() { println!('●●'); //~ ERROR character literal may only contain one codepoint - //~^ ERROR format argument must be a string literal } diff --git a/src/test/ui/str/str-as-char.stderr b/src/test/ui/str/str-as-char.stderr index 162f0888a2947..540a1b55376ff 100644 --- a/src/test/ui/str/str-as-char.stderr +++ b/src/test/ui/str/str-as-char.stderr @@ -8,15 +8,5 @@ help: if you meant to write a `str` literal, use double quotes LL | println!("●●"); | ^^^^ -error: format argument must be a string literal - --> $DIR/str-as-char.rs:4:14 - | -LL | println!('●●'); - | ^^^^ -help: you might be missing a string literal to format with - | -LL | println!("{}", '●●'); - | ^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/struct-literal-variant-in-if.stderr b/src/test/ui/struct-literal-variant-in-if.stderr index 55f23baea7aa8..f91b9d7dce60f 100644 --- a/src/test/ui/struct-literal-variant-in-if.stderr +++ b/src/test/ui/struct-literal-variant-in-if.stderr @@ -3,7 +3,7 @@ error: struct literals are not allowed here | LL | if x == E::I { field1: true, field2: 42 } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | if x == (E::I { field1: true, field2: 42 }) {} | ^ ^ @@ -13,7 +13,7 @@ error: struct literals are not allowed here | LL | if x == E::V { field: false } {} | ^^^^^^^^^^^^^^^^^^^^^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | if x == (E::V { field: false }) {} | ^ ^ @@ -23,7 +23,7 @@ error: struct literals are not allowed here | LL | if x == E::J { field: -42 } {} | ^^^^^^^^^^^^^^^^^^^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | if x == (E::J { field: -42 }) {} | ^ ^ @@ -33,7 +33,7 @@ error: struct literals are not allowed here | LL | if x == E::K { field: "" } {} | ^^^^^^^^^^^^^^^^^^ -help: surround the struct literal with parenthesis +help: surround the struct literal with parentheses | LL | if x == (E::K { field: "" }) {} | ^ ^ diff --git a/src/test/ui/symbol-names/basic.stderr b/src/test/ui/symbol-names/basic.stderr index 6ddd93d632e15..7539cbada8b7b 100644 --- a/src/test/ui/symbol-names/basic.stderr +++ b/src/test/ui/symbol-names/basic.stderr @@ -1,4 +1,4 @@ -error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E) +error: symbol-name(_ZN5basic4main17hd72940ef9669d526E) --> $DIR/basic.rs:3:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.stderr index eda8646b5b4de..20e48782a3a9e 100644 --- a/src/test/ui/symbol-names/impl1.stderr +++ b/src/test/ui/symbol-names/impl1.stderr @@ -1,4 +1,4 @@ -error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E) +error: symbol-name(_ZN5impl13foo3Foo3bar17he53b9bee7600ed8dE) --> $DIR/impl1.rs:8:9 | LL | #[rustc_symbol_name] @@ -10,7 +10,7 @@ error: def-path(foo::Foo::bar) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h38577281258e1527E) +error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h86c41f0462d901d4E) --> $DIR/impl1.rs:18:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs b/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs index 46c083f930591..3e9f612a2afee 100644 --- a/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs +++ b/src/test/ui/traits/trait-object-with-self-in-projection-output-repeated-supertrait.rs @@ -1,5 +1,8 @@ // compile-pass +// FIXME(eddyb) shorten the name so windows doesn't choke on it. +#![crate_name = "trait_test"] + // Regression test related to #56288. Check that a supertrait projection (of // `Output`) that references `Self` is ok if there is another occurence of // the same supertrait that specifies the projection explicitly, even if diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 93d0f61e1d9f0..63b6399bb9034 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -7,4 +7,3 @@ edition = "2018" [dependencies] toml = "0.4" serde = { version = "1.0", features = ["derive"] } -serde_derive = "1.0" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 61cc78ad807af..5efd51b65c14a 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -108,7 +108,7 @@ static TARGETS: &[&str] = &[ "thumbv8m.main-none-eabihf", "wasm32-unknown-emscripten", "wasm32-unknown-unknown", - "wasm32-unknown-wasi", + "wasm32-wasi", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-fortanix-unknown-sgx", diff --git a/src/tools/cargo b/src/tools/cargo index 6be12653dcefb..759b6161a328d 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 6be12653dcefb46ee7b605f063ee75b5e6cba513 +Subproject commit 759b6161a328db1d4863139e90875308ecd25a75 diff --git a/src/tools/clippy b/src/tools/clippy index 2ed0b3bfa05c7..3710ec5996229 160000 --- a/src/tools/clippy +++ b/src/tools/clippy @@ -1 +1 @@ -Subproject commit 2ed0b3bfa05c796c6645ed1814cd372e73f45c66 +Subproject commit 3710ec59962295336ab4aed100267b584dd7df7d diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 00e1a53473cda..336d7e32024b7 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -11,9 +11,8 @@ filetime = "0.2" getopts = "0.2" log = "0.4" regex = "1.0" -serde = "1.0" +serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -serde_derive = "1.0" rustfix = "0.4.1" lazy_static = "1.0" walkdir = "2" diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index 0329fb0db1422..5b3936ffc1e3b 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -7,6 +7,8 @@ use std::io::BufReader; use std::path::Path; use std::str::FromStr; +use log::*; + #[derive(Clone, Debug, PartialEq)] pub enum ErrorKind { Help, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index fb6ada89171ab..dbc477585cbfc 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -4,6 +4,8 @@ use std::io::prelude::*; use std::io::BufReader; use std::path::{Path, PathBuf}; +use log::*; + use crate::common::{self, CompareMode, Config, Mode}; use crate::util; @@ -305,6 +307,9 @@ pub struct TestProps { pub extern_private: Vec, // Environment settings to use for compiling pub rustc_env: Vec<(String, String)>, + // Environment variables to unset prior to compiling. + // Variables are unset before applying 'rustc_env'. + pub unset_rustc_env: Vec, // Environment settings to use during execution pub exec_env: Vec<(String, String)>, // Lines to check if they appear in the expected debugger output @@ -373,6 +378,7 @@ impl TestProps { extern_private: vec![], revisions: vec![], rustc_env: vec![], + unset_rustc_env: vec![], exec_env: vec![], check_lines: vec![], build_aux_docs: false, @@ -499,6 +505,10 @@ impl TestProps { self.rustc_env.push(ee); } + if let Some(ev) = config.parse_name_value_directive(ln, "unset-rustc-env") { + self.unset_rustc_env.push(ev); + } + if let Some(cl) = config.parse_check_line(ln) { self.check_lines.push(cl); } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 26a3c4dee40aa..02b09e21ff022 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -3,8 +3,9 @@ use crate::errors::{Error, ErrorKind}; use crate::runtest::ProcRes; +use serde::Deserialize; use serde_json; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str::FromStr; #[derive(Deserialize)] @@ -18,9 +19,9 @@ struct Diagnostic { } #[derive(Deserialize)] -struct Directive { +struct ArtifactNotification { #[allow(dead_code)] - directive: String, + artifact: PathBuf, } #[derive(Deserialize, Clone)] @@ -75,8 +76,8 @@ pub fn extract_rendered(output: &str) -> String { if line.starts_with('{') { if let Ok(diagnostic) = serde_json::from_str::(line) { diagnostic.rendered - } else if let Ok(_directive) = serde_json::from_str::(line) { - // Swallow the directive. + } else if let Ok(_) = serde_json::from_str::(line) { + // Ignore the notification. None } else { print!( diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index dc5d1b9a853ef..e253934e566a7 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -3,14 +3,6 @@ #![feature(vec_remove_item)] #![deny(warnings, rust_2018_idioms)] -#[cfg(unix)] -extern crate libc; -#[macro_use] -extern crate log; -#[macro_use] -extern crate lazy_static; -#[macro_use] -extern crate serde_derive; extern crate test; use crate::common::CompareMode; @@ -30,6 +22,7 @@ use crate::util::logv; use walkdir::WalkDir; use env_logger; use getopts; +use log::*; use self::header::{EarlyProps, Ignore}; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 42f9cdb7886fd..10b8133326bba 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -29,6 +29,9 @@ use std::path::{Path, PathBuf}; use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::str; +use lazy_static::lazy_static; +use log::*; + use crate::extract_gdb_version; use crate::is_android_gdb_target; @@ -1422,10 +1425,21 @@ impl<'test> TestCx<'test> { } fn compile_test(&self) -> ProcRes { - let mut rustc = self.make_compile_args( - &self.testpaths.file, - TargetLocation::ThisFile(self.make_exe_name()), - ); + // Only use `make_exe_name` when the test ends up being executed. + let will_execute = match self.config.mode { + RunPass | Ui => self.should_run_successfully(), + Incremental => self.revision.unwrap().starts_with("r"), + RunFail | RunPassValgrind | MirOpt | + DebugInfoBoth | DebugInfoGdb | DebugInfoLldb => true, + _ => false, + }; + let output_file = if will_execute { + TargetLocation::ThisFile(self.make_exe_name()) + } else { + TargetLocation::ThisDirectory(self.output_base_dir()) + }; + + let mut rustc = self.make_compile_args(&self.testpaths.file, output_file); rustc.arg("-L").arg(&self.aux_output_dir_name()); @@ -1636,7 +1650,9 @@ impl<'test> TestCx<'test> { (true, None) } else if self.config.target.contains("cloudabi") || self.config.target.contains("emscripten") - || (self.config.target.contains("musl") && !aux_props.force_host) + || (self.config.target.contains("musl") + && !aux_props.force_host + && !self.config.host.contains("musl")) || self.config.target.contains("wasm32") || self.config.target.contains("nvptx") { @@ -1692,6 +1708,9 @@ impl<'test> TestCx<'test> { add_extern_priv(&private_lib, true); } + self.props.unset_rustc_env.clone() + .iter() + .fold(&mut rustc, |rustc, v| rustc.env_remove(v)); rustc.envs(self.props.rustc_env.clone()); self.compose_and_run( rustc, @@ -1882,7 +1901,12 @@ impl<'test> TestCx<'test> { rustc.arg("-o").arg(path); } TargetLocation::ThisDirectory(path) => { - rustc.arg("--out-dir").arg(path); + if is_rustdoc { + // `rustdoc` uses `-o` for the output directory. + rustc.arg("-o").arg(path); + } else { + rustc.arg("--out-dir").arg(path); + } } } @@ -1910,6 +1934,11 @@ impl<'test> TestCx<'test> { } } + // Use dynamic musl for tests because static doesn't allow creating dylibs + if self.config.host.contains("musl") { + rustc.arg("-Ctarget-feature=-crt-static"); + } + rustc.args(&self.props.compile_flags); rustc @@ -2703,6 +2732,12 @@ impl<'test> TestCx<'test> { // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); + // Use dynamic musl for tests because static doesn't allow creating dylibs + if self.config.host.contains("musl") { + cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static") + .env("IS_MUSL_HOST", "1"); + } + if self.config.target.contains("msvc") && self.config.cc != "" { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. @@ -3138,42 +3173,40 @@ impl<'test> TestCx<'test> { } fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String { - let parent_dir = self.testpaths.file.parent().unwrap(); let cflags = self.props.compile_flags.join(" "); let json = cflags.contains("--error-format json") || cflags.contains("--error-format pretty-json") || cflags.contains("--error-format=json") || cflags.contains("--error-format=pretty-json"); - let parent_dir_str = if json { - parent_dir.display().to_string().replace("\\", "\\\\") - } else { - parent_dir.display().to_string() + + let mut normalized = output.to_string(); + + let mut normalize_path = |from: &Path, to: &str| { + let mut from = from.display().to_string(); + if json { + from = from.replace("\\", "\\\\"); + } + normalized = normalized.replace(&from, to); }; - let mut normalized = output.replace(&parent_dir_str, "$DIR"); + let parent_dir = self.testpaths.file.parent().unwrap(); + normalize_path(parent_dir, "$DIR"); // Paths into the libstd/libcore let src_dir = self.config.src_base.parent().unwrap().parent().unwrap(); - let src_dir_str = if json { - src_dir.display().to_string().replace("\\", "\\\\") - } else { - src_dir.display().to_string() - }; - normalized = normalized.replace(&src_dir_str, "$SRC_DIR"); + normalize_path(src_dir, "$SRC_DIR"); // Paths into the build directory let test_build_dir = &self.config.build_base; let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap(); // eg. /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui - normalized = normalized.replace(test_build_dir.to_str().unwrap(), "$TEST_BUILD_DIR"); + normalize_path(test_build_dir, "$TEST_BUILD_DIR"); // eg. /home/user/rust/build - normalized = normalized.replace(&parent_build_dir.to_str().unwrap(), "$BUILD_DIR"); + normalize_path(parent_build_dir, "$BUILD_DIR"); // Paths into lib directory. - let mut lib_dir = parent_build_dir.parent().unwrap().to_path_buf(); - lib_dir.push("lib"); - normalized = normalized.replace(&lib_dir.to_str().unwrap(), "$LIB_DIR"); + normalize_path(&parent_build_dir.parent().unwrap().join("lib"), "$LIB_DIR"); if json { // escaped newlines in json strings should be readable diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 50dce4b55ae86..adc1224bcd367 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -3,6 +3,8 @@ use std::env; use std::path::PathBuf; use crate::common::Config; +use log::*; + /// Conversion table from triple OS name to Rust SYSNAME const OS_TABLE: &'static [(&'static str, &'static str)] = &[ ("android", "android"), diff --git a/src/tools/rls b/src/tools/rls index 20e32686df573..5b8e99bb61958 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 20e32686df573fc44ac1052bf3e6982b0da27cfc +Subproject commit 5b8e99bb61958ca8abcb7c5eda70521726be1065 diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index 433e9264dd1dc..eeac6cfbb30e0 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -6,6 +6,5 @@ edition = "2018" [dependencies] regex = "1" -serde = "1.0.8" -serde_derive = "1.0.8" +serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index e90737febd5bf..8626ba060bf71 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -5,7 +5,7 @@ use std::fs; use std::path::Path; use std::process::Command; -use serde_derive::Deserialize; +use serde::Deserialize; use serde_json; const LICENSES: &[&str] = &[ diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index f9f3623679e17..637f10c5ae745 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -191,7 +191,7 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { // We allow rustc-internal features to omit a tracking issue. // To make tidy accept omitting a tracking issue, group the list of features - // without one inside `// no tracking issue START` and `// no tracking issue END`. + // without one inside `// no-tracking-issue` and `// no-tracking-issue-end`. let mut next_feature_omits_tracking_issue = false; let mut in_feature_group = false; @@ -201,13 +201,13 @@ pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { .filter_map(|(line, line_number)| { let line = line.trim(); - // Within START and END, the tracking issue can be omitted. + // Within -start and -end, the tracking issue can be omitted. match line { - "// no tracking issue START" => { + "// no-tracking-issue-start" => { next_feature_omits_tracking_issue = true; return None; } - "// no tracking issue END" => { + "// no-tracking-issue-end" => { next_feature_omits_tracking_issue = false; return None; }