Markus Westerlind <marwes91@gmail.com> Markus <marwes91@gmail.com>
Martin Hafskjold Thoresen <martinhath@gmail.com>
Matej Lach <matej.lach@gmail.com> Matej Ľach <matej.lach@gmail.com>
+Mateusz Mikuła <matti@marinelayer.io> <mati865@gmail.com>
+Mateusz Mikuła <matti@marinelayer.io> <mati865@users.noreply.github.com>
Matt Brubeck <mbrubeck@limpet.net> <mbrubeck@cs.hmc.edu>
Matthew Auld <matthew.auld@intel.com>
Matthew McPherrin <matthew@mcpherrin.ca> <matt@mcpherrin.ca>
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "aho-corasick"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "alloc"
version = "0.0.0"
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)",
"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.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (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)",
]
+[[package]]
+name = "bstr"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "bufstream"
version = "0.1.4"
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)",
]
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crates-io 0.25.0",
- "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)",
"curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.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)",
"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)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-workspace-hack 1.0.0",
"rustc_tools_util 0.1.1",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"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)",
+ "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.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)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfix 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "crossbeam-channel"
-version = "0.3.4"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"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)",
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)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-utils"
-version = "0.6.2"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
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)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "globset"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
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)",
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
]
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)",
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "ignore"
-version = "0.4.6"
+version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"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)",
[[package]]
name = "lazy_static"
-version = "1.2.0"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
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]]
"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)",
"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)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "measureme"
-version = "0.2.1"
+version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
]
"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)",
"rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rusty-fork 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
"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)",
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)",
[[package]]
name = "regex"
-version = "1.1.0"
+version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
-version = "0.6.4"
+version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo 0.37.0",
"cargo_metadata 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy_lints 0.0.212",
- "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"racer 2.1.22 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
+ "measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
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)",
]
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)",
]
"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)",
"env_logger 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
- "ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.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)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-ap-rustc_target 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-ap-syntax 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-ap-syntax_pos 407.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
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)",
]
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)",
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",
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]]
name = "tidy"
version = "0.1.0"
dependencies = [
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_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)",
]
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.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)",
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
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)",
]
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)",
- "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
dependencies = [
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "winapi-util"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[metadata]
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
+"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477"
"checksum annotate-snippets 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e8bcdcd5b291ce85a78f2b9d082a8de9676c12b1840d386d67bc5eea6f9d2b4e"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
+"checksum bstr 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "853b090ce0f45d0265902666bf88039ea3da825e33796716c511a1ec9c170036"
"checksum bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "40e38929add23cdf8a366df9b0e088953150724bcbe5fc330b0d8eb3b328eec8"
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb"
"checksum crc32fast 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192"
-"checksum crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2a9ea8f77c7f9efd317a8a5645f515d903a2d86ee14d2337a5facd1bd52c12"
+"checksum crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "0f0ed1a4de2235cabda8558ff5840bffb97fcb64c97827f354a451307df5f72b"
"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
-"checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72"
+"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4"
"checksum curl 0.4.21 (registry+https://github.com/rust-lang/crates.io-index)" = "a85f2f95f2bd277d316d1aa8a477687ab4a6942258c7db7c89c187534669979c"
"checksum curl-sys 0.4.18 (registry+https://github.com/rust-lang/crates.io-index)" = "9d91a0052d5b982887d8e829bee0faffc7218ea3c6ebd3d6c2c8f678a93c9a42"
"checksum git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7339329bfa14a00223244311560d11f8f489b453fb90092af97f267a6090ab0"
"checksum git2-curl 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d58551e903ed7e2d6fe3a2f3c7efa3a784ec29b19d0fbb035aaf0497c183fbdd"
"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
-"checksum globset 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4743617a7464bbda3c8aec8558ff2f9429047e025771037df561d383337ff865"
+"checksum globset 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4feaabe24a0a658fd9cf4a9acf6ed284f045c77df0f49020ba3245cfb7b454"
"checksum handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d89ec99d1594f285d4590fc32bac5f75cdab383f1123d504d27862c644a807dd"
"checksum handlebars 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d82e5750d8027a97b9640e3fefa66bbaf852a35228e1c90790efd13c4b09c166"
"checksum hashbrown 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "570178d5e4952010d138b0f1d581271ff3a02406d990f887d1e87e3d6e43b0ac"
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec"
-"checksum ignore 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ad03ca67dc12474ecd91fdb94d758cbd20cb4e7a78ebe831df26a9b7511e1162"
+"checksum ignore 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc57fa12805f367736a38541ac1a9fc6a52812a0ca959b1d4d4b640a89eb002"
"checksum im-rc 12.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9460397452f537fd51808056ff209f4c4c4c9d20d42ae952f517708726284972"
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
"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"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
"checksum mdbook 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba0d44cb4089c741b9a91f3e5218298a40699c2f3a070a85014eed290c60819"
-"checksum measureme 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "36bb2b263a6795d352035024d6b30ce465bb79a5e5280d74c3b5f8464c657bcc"
+"checksum measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d09de7dafa3aa334bc806447c7e4de69419723312f4b88b80b561dea66601ce8"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum redox_users 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "214a97e49be64fd2c86f568dd0cb2c757d2cc53de95b273b6ad0a1c908482f26"
"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384"
-"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f"
+"checksum regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8f0a0bcab2fd7d1d7c54fa9eae6f43eddeb9ce2e7352f8518a814a4f65d60c58"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
-"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1"
+"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rls-analysis 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d53d49a28f75da9d02790d9256fecf6c0481e0871374326023c7a33131295579"
"checksum rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ce1fdac03e138c4617ff87b194e1ff57a39bb985a044ccbd8673d30701e411"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
+"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
#### MSVC
[windows-msvc]: #windows-msvc
-MSVC builds of Rust additionally require an installation of Visual Studio 2013
-(or later) so `rustc` can use its linker. Make sure to check the “C++ tools”
-option.
+MSVC builds of Rust additionally require an installation of Visual Studio 2017
+(or later) so `rustc` can use its linker. The simplest way is to get the
+[Visual Studio Build Tools] and check the “C++ build tools” workload.
+
+[Visual Studio Build Tools]: https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019
+
+At last check (cmake 3.14.3 and msvc 16.0.3) using the 2019 tools fails to
+build the in-tree LLVM build with a CMake error, so use 2017 instead by
+including the “MSVC v141 – VS 2017 C++ x64/x86 build tools (v14.16)” component.
With these dependencies installed, you can build the compiler in a `cmd.exe`
shell with:
+Version 1.35.0 (2019-05-23)
+==========================
+
+Language
+--------
+- [`FnOnce`, `FnMut`, and the `Fn` traits are now implemented for `Box<FnOnce>`,
+ `Box<FnMut>`, and `Box<Fn>` respectively.][59500]
+- [You can now coerce closures into unsafe function pointers.][59580] e.g.
+ ```rust
+ unsafe fn call_unsafe(func: unsafe fn()) {
+ func()
+ }
+
+ pub fn main() {
+ unsafe { call_unsafe(|| {}); }
+ }
+ ```
+
+
+Compiler
+--------
+- [Added the `armv6-unknown-freebsd-gnueabihf` and
+ `armv7-unknown-freebsd-gnueabihf` targets.][58080]
+- [Added the `wasm32-unknown-wasi` target.][59464]
+
+
+Libraries
+---------
+- [`Thread` will now show its ID in `Debug` output.][59460]
+- [`StdinLock`, `StdoutLock`, and `StderrLock` now implement `AsRawFd`.][59512]
+- [`alloc::System` now implements `Default`.][59451]
+- [Expanded `Debug` output (`{:#?}`) for structs now has a trailing comma on the
+ last field.][59076]
+- [`char::{ToLowercase, ToUppercase}` now
+ implement `ExactSizeIterator`.][58778]
+- [All `NonZero` numeric types now implement `FromStr`.][58717]
+- [Removed the `Read` trait bounds
+ on the `BufReader::{get_ref, get_mut, into_inner}` methods.][58423]
+- [You can now call the `dbg!` macro without any parameters to print the file
+ and line where it is called.][57847]
+- [In place ASCII case conversions are now up to 4× faster.][59283]
+ e.g. `str::make_ascii_lowercase`
+- [`hash_map::{OccupiedEntry, VacantEntry}` now implement `Sync`
+ and `Send`.][58369]
+
+Stabilized APIs
+---------------
+- [`f32::copysign`]
+- [`f64::copysign`]
+- [`RefCell::replace_with`]
+- [`RefCell::map_split`]
+- [`ptr::hash`]
+- [`Range::contains`]
+- [`RangeFrom::contains`]
+- [`RangeTo::contains`]
+- [`RangeInclusive::contains`]
+- [`RangeToInclusive::contains`]
+- [`Option::copied`]
+
+Cargo
+-----
+- [You can now set `cargo:rustc-cdylib-link-arg` at build time to pass custom
+ linker arguments when building a `cdylib`.][cargo/6298] Its usage is highly
+ platform specific.
+
+Misc
+----
+- [The Rust toolchain is now available natively for musl based distros.][58575]
+
+[59460]: https://github.com/rust-lang/rust/pull/59460/
+[59464]: https://github.com/rust-lang/rust/pull/59464/
+[59500]: https://github.com/rust-lang/rust/pull/59500/
+[59512]: https://github.com/rust-lang/rust/pull/59512/
+[59580]: https://github.com/rust-lang/rust/pull/59580/
+[59283]: https://github.com/rust-lang/rust/pull/59283/
+[59451]: https://github.com/rust-lang/rust/pull/59451/
+[59076]: https://github.com/rust-lang/rust/pull/59076/
+[58778]: https://github.com/rust-lang/rust/pull/58778/
+[58717]: https://github.com/rust-lang/rust/pull/58717/
+[58369]: https://github.com/rust-lang/rust/pull/58369/
+[58423]: https://github.com/rust-lang/rust/pull/58423/
+[58080]: https://github.com/rust-lang/rust/pull/58080/
+[57847]: https://github.com/rust-lang/rust/pull/57847/
+[58575]: https://github.com/rust-lang/rust/pull/58575
+[cargo/6298]: https://github.com/rust-lang/cargo/pull/6298/
+[`f32::copysign`]: https://doc.rust-lang.org/stable/std/primitive.f32.html#method.copysign
+[`f64::copysign`]: https://doc.rust-lang.org/stable/std/primitive.f64.html#method.copysign
+[`RefCell::replace_with`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.replace_with
+[`RefCell::map_split`]: https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.map_split
+[`ptr::hash`]: https://doc.rust-lang.org/stable/std/ptr/fn.hash.html
+[`Range::contains`]: https://doc.rust-lang.org/std/ops/struct.Range.html#method.contains
+[`RangeFrom::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeFrom.html#method.contains
+[`RangeTo::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeTo.html#method.contains
+[`RangeInclusive::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html#method.contains
+[`RangeToInclusive::contains`]: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html#method.contains
+[`Option::copied`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.copied
+
+Version 1.34.2 (2019-05-14)
+===========================
+
+* [Destabilize the `Error::type_id` function due to a security
+ vulnerability][60785] ([CVE-2019-12083])
+
+[60785]: https://github.com/rust-lang/rust/pull/60785
+[CVE-2019-12083]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-12083
+
Version 1.34.1 (2019-04-25)
===========================
# 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
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"
# The goal here is to come up with the same triple as LLVM would,
# at least for the subset of platforms we're willing to target.
ostype_mapper = {
- 'Bitrig': 'unknown-bitrig',
'Darwin': 'apple-darwin',
'DragonFly': 'unknown-dragonfly',
'FreeBSD': 'unknown-freebsd',
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;
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
use std::sync::Mutex;
use std::cmp::{PartialOrd, Ord, Ordering};
+use lazy_static::lazy_static;
+
use crate::builder::Step;
pub struct Interned<T>(usize, PhantomData<*const T>);
use std::io::{self, ErrorKind};
use std::path::Path;
+use build_helper::t;
+
use crate::Build;
pub fn clean(build: &Build, all: bool) {
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;
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;
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;
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};
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};
#![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;
#[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};
use std::collections::HashSet;
use build_helper::output;
+use serde::Deserialize;
use serde_json;
use crate::{Build, Crate};
use std::path::{Path, PathBuf};
use std::process::Command;
-use build_helper::output;
+use build_helper::{output, t};
use cmake;
use cc;
fn configure_cmake(builder: &Builder<'_>,
target: Interned<String>,
cfg: &mut cmake::Config) {
+ // Do not print installation messages for up-to-date files.
+ // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
+ cfg.define("CMAKE_INSTALL_MESSAGE", "LAZY");
+
if builder.config.ninja {
cfg.generator("Ninja");
}
use std::path::PathBuf;
use std::process::Command;
-use build_helper::output;
+use build_helper::{output, t};
use crate::Build;
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};
Err(_) => p,
}
})
- .filter(|p| p.starts_with(suite_path) && p.is_file())
- .map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap())
+ .filter(|p| p.starts_with(suite_path) && (p.is_dir() || p.is_file()))
+ .filter_map(|p| {
+ // Since test suite paths are themselves directories, if we don't
+ // specify a directory or file, we'll get an empty string here
+ // (the result of the test suite directory without its suite prefix).
+ // Therefore, we need to filter these out, as only the first --test-args
+ // flag is respected, so providing an empty --test-args conflicts with
+ // any following it.
+ match p.strip_prefix(suite_path).ok().and_then(|p| p.to_str()) {
+ Some(s) if s != "" => Some(s),
+ _ => None,
+ }
+ })
.collect();
test_args.append(&mut builder.config.cmd.test_args());
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");
}
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};
+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
use std::process::Command;
use std::time::{SystemTime, Instant};
+use build_helper::t;
+
use crate::config::Config;
use crate::builder::Builder;
}
pub fn make(host: &str) -> PathBuf {
- if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd")
+ if host.contains("dragonfly") || host.contains("freebsd")
|| host.contains("netbsd") || host.contains("openbsd")
{
PathBuf::from("gmake")
-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 \
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'
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
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
# 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
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
# 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
--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
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
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++
-FROM ubuntu:18.10
+FROM ubuntu:19.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
state = cur[os_name]
new_state = toolstate.get(tool, '')
if verb == 'regressed':
- updated = new_state < state
+ if tool == 'rls':
+ # Temporary override until
+ # https://github.com/rust-lang/rust/issues/60848 is fixed.
+ updated = False
+ else:
+ updated = new_state < state
elif verb == 'changed':
updated = new_state != state
else:
-FROM ubuntu:18.10
+FROM ubuntu:19.04
RUN apt-get update && apt-get install -y --no-install-recommends \
g++ \
## `-L`: add a directory to the library search path
-When looking for external crates, a directory passed to this flag will be searched.
+When looking for external crates or libraries, a directory passed to this flag
+will be searched.
+
+The kind of search path can optionally be specified with the form `-L
+KIND=PATH` where `KIND` may be one of:
+
+- `dependency` — Only search for transitive dependencies in this directory.
+- `crate` — Only search for this crate's direct dependencies in this
+ directory.
+- `native` — Only search for native libraries in this directory.
+- `framework` — Only search for macOS frameworks in this directory.
+- `all` — Search for all library kinds in this directory. This is the default
+ if `KIND` is not specified.
## `-l`: link the generated crate to a native library
This flag allows you to specify linking to a specific native library when building
a crate.
+The kind of library can optionally be specified with the form `-l KIND=lib`
+where `KIND` may be one of:
+
+- `dylib` — A native dynamic library.
+- `static` — A native static library (such as a `.a` archive).
+- `framework` — A macOS framework.
+
+The kind of library can be specified in a [`#[link]`
+attribute][link-attribute]. If the kind is not specified in the `link`
+attribute or on the command-line, it will link a dynamic library if available,
+otherwise it will use a static library. If the kind is specified on the
+command-line, it will override the kind specified in a `link` attribute.
+
+The name used in a `link` attribute may be overridden using the form `-l
+ATTR_NAME:LINK_NAME` where `ATTR_NAME` is the name in the `link` attribute,
+and `LINK_NAME` is the name of the actual library that will be linked.
+
+[link-attribute]: ../reference/items/external-blocks.html#the-link-attribute
+
## `--crate-type`: a list of types of crates for the compiler to emit
-This instructs `rustc` on which crate type to build.
+This instructs `rustc` on which crate type to build. This flag accepts a
+comma-separated list of values, and may be specified multiple times. The valid
+crate types are:
+
+- `lib` — Generates a library kind preferred by the compiler, currently
+ defaults to `rlib`.
+- `rlib` — A Rust static library.
+- `staticlib` — A native static library.
+- `dylib` — A Rust dynamic library.
+- `cdylib` — A native dynamic library.
+- `bin` — A runnable executable program.
+- `proc-macro` — Generates a format suitable for a procedural macro library
+ that may be loaded by the compiler.
+
+The crate type may be specified with the [`crate_type` attribute][crate_type].
+The `--crate-type` command-line value will override the `crate_type`
+attribute.
+
+More details may be found in the [linkage chapter] of the reference.
+
+[linkage chapter]: ../reference/linkage.html
+[crate_type]: ../reference/linkage.html
## `--crate-name`: specify the name of the crate being built
This informs `rustc` of the name of your crate.
-## `--emit`: emit output other than a crate
-
-Instead of producing a crate, this flag can print out things like the assembly or LLVM-IR.
+## `--edition`: specify the edition to use
+
+This flag takes a value of `2015` or `2018`. The default is `2015`. More
+information about editions may be found in the [edition guide].
+
+[edition guide]: ../edition-guide/introduction.html
+
+## `--emit`: specifies the types of output files to generate
+
+This flag controls the types of output files generated by the compiler. It
+accepts a comma-separated list of values, and may be specified multiple times.
+The valid emit kinds are:
+
+- `asm` — Generates a file with the crate's assembly code. The default output
+ filename is `CRATE_NAME.s`.
+- `dep-info` — Generates a file with Makefile syntax that indicates all the
+ source files that were loaded to generate the crate. The default output
+ filename is `CRATE_NAME.d`.
+- `link` — Generates the crates specified by `--crate-type`. The default
+ output filenames depend on the crate type and platform. This is the default
+ if `--emit` is not specified.
+- `llvm-bc` — Generates a binary file containing the [LLVM bitcode]. The
+ default output filename is `CRATE_NAME.bc`.
+- `llvm-ir` — Generates a file containing [LLVM IR]. The default output
+ filename is `CRATE_NAME.ll`.
+- `metadata` — Generates a file containing metadata about the crate. The
+ default output filename is `CRATE_NAME.rmeta`.
+- `mir` — Generates a file containing rustc's mid-level intermediate
+ representation. The default output filename is `CRATE_NAME.mir`.
+- `obj` — Generates a native object file. The default output filename is
+ `CRATE_NAME.o`.
+
+The output filename can be set with the `-o` flag. A suffix may be added to
+the filename with the `-C extra-filename` flag. The files are written to the
+current directory unless the `--out-dir` flag is used. Each emission type may
+also specify the output filename with the form `KIND=PATH`, which takes
+precedence over the `-o` flag.
+
+[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
+[LLVM IR]: https://llvm.org/docs/LangRef.html
## `--print`: print compiler information
-This flag prints out various information about the compiler.
+This flag prints out various information about the compiler. This flag may be
+specified multiple times, and the information is printed in the order the
+flags are specified. Specifying a `--print` flag will usually disable the
+`--emit` step and will only print the requested information. The valid types
+of print values are:
+
+- `crate-name` — The name of the crate.
+- `file-names` — The names of the files created by the `link` emit kind.
+- `sysroot` — Path to the sysroot.
+- `cfg` — List of cfg values. See [conditional compilation] for more
+ information about cfg values.
+- `target-list` — List of known targets. The target may be selected with the
+ `--target` flag.
+- `target-cpus` — List of available CPU values for the current target. The
+ target CPU may be selected with the `-C target-cpu=val` flag.
+- `target-features` — List of available target features for the current
+ target. Target features may be enabled with the `-C target-feature=val`
+ flag.
+- `relocation-models` — List of relocation models. Relocation models may be
+ selected with the `-C relocation-model=val` flag.
+- `code-models` — List of code models. Code models may be selected with the
+ `-C code-model=val` flag.
+- `tls-models` — List of Thread Local Storage models supported. The model may
+ be selected with the `-Z tls-model=val` flag.
+- `native-static-libs` — This may be used when creating a `staticlib` crate
+ type. If this is the only flag, it will perform a full compilation and
+ include a diagnostic note that indicates the linker flags to use when
+ linking the resulting static library. The note starts with the text
+ `native-static-libs:` to make it easier to fetch the output.
+
+[conditional compilation]: ../reference/conditional-compilation.html
## `-g`: include debug information
## `--out-dir`: directory to write the output in
-The outputted crate will be written to this directory.
+The outputted crate will be written to this directory. This flag is ignored if
+the `-o` flag is used.
## `--explain`: provide a detailed explanation of an error message
## `--extern`: specify where an external library is located
-This flag allows you to pass the name and location of an external crate that will
-be linked into the crate you're buildling.
+This flag allows you to pass the name and location of an external crate that
+will be linked into the crate you are building. This flag may be specified
+multiple times. The format of the value should be `CRATENAME=PATH`.
## `--sysroot`: Override the system root
## `--error-format`: control how errors are produced
-This flag lets you control the format of errors.
+This flag lets you control the format of messages. Messages are printed to
+stderr. The valid options are:
+
+- `human` — Human-readable output. This is the default.
+- `json` — Structured JSON output.
+- `short` — Short, one-line messages.
## `--color`: configure coloring of output
-This flag lets you control color settings of the output.
+This flag lets you control color settings of the output. The valid options
+are:
+
+- `auto` — Use colors if output goes to a tty. This is the default.
+- `always` — Always use colors.
+- `never` — Never colorize output.
+
+## `--remap-path-prefix`: remap source names in output
+
+Remap source path prefixes in all output, including compiler diagnostics,
+debug information, macro expansions, etc. It takes a value of the form
+`FROM=TO` where a path prefix equal to `FROM` is rewritten to the value `TO`.
+The `FROM` may itself contain an `=` symbol, but the `TO` value may not. This
+flag may be specified multiple times.
+
+This is useful for normalizing build products, for example by removing the
+current directory out of pathnames emitted into the object files. The
+replacement is purely textual, with no consideration of the current system's
+pathname syntax. For example `--remap-path-prefix foo=bar` will match
+`foo/lib.rs` but not `./foo/lib.rs`.
#![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
```
+### `html_root_url`
+
+The `#[doc(html_root_url = "…")]` attribute value indicates the URL for
+generating links to external crates. When rustdoc needs to generate a link to
+an item in an external crate, it will first check if the extern crate has been
+documented locally on-disk, and if so link directly to it. Failing that, it
+will use the URL given by the `--extern-html-root-url` command-line flag if
+available. If that is not available, then it will use the `html_root_url`
+value in the extern crate if it is available. If that is not available, then
+the extern items will not be linked.
+
+```rust,ignore
+#![doc(html_root_url = "https://docs.rs/serde/1.0")]
+```
+
### `html_no_source`
By default, `rustdoc` will include the source code of your program, with links
`rustdoc` can also generate HTML from standalone Markdown files. Let's
give it a try: create a `README.md` file with these contents:
-```text
- # Docs
+````text
+# Docs
- This is a project to test out `rustdoc`.
+This is a project to test out `rustdoc`.
- [Here is a link!](https://www.rust-lang.org)
+[Here is a link!](https://www.rust-lang.org)
- ## Subheading
+## Subheading
- ```rust
- fn foo() -> i32 {
- 1 + 1
- }
- ```
+```rust
+fn foo() -> i32 {
+ 1 + 1
+}
```
+````
And call `rustdoc` on it:
/// // 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<T> {
data: Vec<T>,
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<&'a T> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<T> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<T> {
+ self.next_back()
+ }
}
#[stable(feature = "drain", since = "1.6.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.length, Some(self.length))
}
+
+ #[inline]
+ fn last(mut self) -> Option<(&'a K, &'a V)> {
+ self.next_back()
+ }
}
#[stable(feature = "fused", since = "1.26.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.length, Some(self.length))
}
+
+ #[inline]
+ fn last(mut self) -> Option<(&'a K, &'a mut V)> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.length, Some(self.length))
}
+
+ #[inline]
+ fn last(mut self) -> Option<(K, V)> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<&'a K> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<&'a V> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
unsafe { Some(self.next_unchecked()) }
}
}
+
+ #[inline]
+ fn last(mut self) -> Option<(&'a K, &'a V)> {
+ self.next_back()
+ }
}
#[stable(feature = "map_values_mut", since = "1.10.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<&'a mut V> {
+ self.next_back()
+ }
}
#[stable(feature = "map_values_mut", since = "1.10.0")]
unsafe { Some(self.next_unchecked()) }
}
}
+
+ #[inline]
+ fn last(mut self) -> Option<(&'a K, &'a mut V)> {
+ self.next_back()
+ }
}
impl<'a, K, V> RangeMut<'a, K, V> {
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<&'a T> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<T> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next(&mut self) -> Option<&'a T> {
self.iter.next().map(|(k, _)| k)
}
+
+ #[inline]
+ fn last(mut self) -> Option<&'a T> {
+ self.next_back()
+ }
}
#[stable(feature = "btree_range", since = "1.17.0")]
/// 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
///
/// 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<F>(&mut self, mut f: F)
where F: FnMut(&T) -> bool
}
}
+/// 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<T: ?Sized + Eq> RcEqIdent<T> for Rc<T> {
#[inline]
/// 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
///
///
/// 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<F>(&mut self, mut f: F)
}
}
+#[stable(feature = "from_ref_string", since = "1.35.0")]
+impl From<&String> for String {
+ #[inline]
+ fn from(s: &String) -> String {
+ s.clone()
+ }
+}
+
// note: test pulls in libstd, which causes errors here
#[cfg(not(test))]
#[stable(feature = "string_from_box", since = "1.18.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+ #[inline]
+ fn last(mut self) -> Option<char> {
+ self.next_back()
+ }
}
#[stable(feature = "drain", since = "1.6.0")]
}
}
+/// 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<T: ?Sized + Eq> ArcEqIdent<T> for Arc<T> {
#[inline]
/// 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
///
/// 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<F>(&mut self, mut f: F)
where F: FnMut(&T) -> bool
fn count(self) -> usize {
self.len()
}
+
+ #[inline]
+ fn last(mut self) -> Option<T> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<T> {
+ self.next_back()
+ }
}
#[stable(feature = "drain", since = "1.6.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.drain.size_hint()
}
+
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "vec_splice", since = "1.21.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;
}
}
+#[stable(feature = "try_from_slice_error", since = "1.36.0")]
+impl From<Infallible> for TryFromSliceError {
+ fn from(x: Infallible) -> TryFromSliceError {
+ match x {}
+ }
+}
+
macro_rules! __impl_slice_eq1 {
($Lhs: ty, $Rhs: ty) => {
__impl_slice_eq1! { $Lhs, $Rhs, Sized }
type Item = u8;
fn next(&mut self) -> Option<u8> { self.range.next().map(|i| self.data[i]) }
fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() }
+ #[inline]
+ fn last(mut self) -> Option<u8> { self.next_back() }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl DoubleEndedIterator for EscapeDefault {
/// If you need to do a costly conversion it is better to implement [`From`] with type
/// `&T` or write a custom function.
///
-///
/// `AsRef` has the same signature as [`Borrow`], but `Borrow` is different in few aspects:
///
/// - Unlike `AsRef`, `Borrow` has a blanket impl for any `T`, and can be used to accept either
/// converted a the specified type `T`.
///
/// For example: By creating a generic function that takes an `AsRef<str>` we express that we
-/// want to accept all references that can be converted to &str as an argument.
+/// want to accept all references that can be converted to `&str` as an argument.
/// Since both [`String`] and `&str` implement `AsRef<str>` we can accept both as input argument.
///
/// [`String`]: ../../std/string/struct.String.html
/// let s = "hello".to_string();
/// is_hello(s);
/// ```
-///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsRef<T: ?Sized> {
/// Performs the conversion.
/// write a function `add_one`that takes all arguments that can be converted to `&mut u64`.
/// Because [`Box<T>`] implements `AsMut<T>` `add_one` accepts arguments of type
/// `&mut Box<u64>` as well:
+///
/// ```
/// fn add_one<T: AsMut<u64>>(num: &mut T) {
/// *num.as_mut() += 1;
/// add_one(&mut boxed_num);
/// assert_eq!(*boxed_num, 1);
/// ```
-/// [`Box<T>`]: ../../std/boxed/struct.Box.html
///
+/// [`Box<T>`]: ../../std/boxed/struct.Box.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait AsMut<T: ?Sized> {
/// Performs the conversion.
/// A value-to-value conversion that consumes the input value. The
/// opposite of [`From`].
///
-/// One should only implement [`Into`] if a conversion to a type outside the current crate is
-/// required. Otherwise one should always prefer implementing [`From`] over [`Into`] because
-/// implementing [`From`] automatically provides one with a implementation of [`Into`] thanks to
+/// One should only implement `Into` if a conversion to a type outside the current crate is
+/// required. Otherwise one should always prefer implementing [`From`] over `Into` because
+/// implementing [`From`] automatically provides one with a implementation of `Into` thanks to
/// the blanket implementation in the standard library. [`From`] cannot do these type of
/// conversions because of Rust's orphaning rules.
///
///
/// # Generic Implementations
///
-/// - [`From<T>`]` for U` implies `Into<U> for T`
-/// - [`Into`]` is reflexive, which means that `Into<T> for T` is implemented
+/// - [`From`]`<T> for U` implies `Into<U> for T`
+/// - `Into` is reflexive, which means that `Into<T> for T` is implemented
///
/// # Implementing `Into` for conversions to external types
///
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
/// [`String`]: ../../std/string/struct.String.html
-/// [From]: trait.From.html
+/// [`From`]: trait.From.html
/// [`into`]: trait.Into.html#tymethod.into
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Into<T>: Sized {
/// Used to do value-to-value conversions while consuming the input value. It is the reciprocal of
/// [`Into`].
///
-/// One should always prefer implementing [`From`] over [`Into`]
-/// because implementing [`From`] automatically provides one with a implementation of [`Into`]
+/// One should always prefer implementing `From` over [`Into`]
+/// because implementing `From` automatically provides one with a implementation of [`Into`]
/// thanks to the blanket implementation in the standard library.
///
/// Only implement [`Into`] if a conversion to a type outside the current crate is required.
-/// [`From`] cannot do these type of conversions because of Rust's orphaning rules.
+/// `From` cannot do these type of conversions because of Rust's orphaning rules.
/// See [`Into`] for more details.
///
-/// Prefer using [`Into`] over using [`From`] when specifying trait bounds on a generic function.
+/// Prefer using [`Into`] over using `From` when specifying trait bounds on a generic function.
/// This way, types that directly implement [`Into`] can be used as arguments as well.
///
-/// The [`From`] is also very useful when performing error handling. When constructing a function
+/// The `From` is also very useful when performing error handling. When constructing a function
/// that is capable of failing, the return type will generally be of the form `Result<T, E>`.
/// The `From` trait simplifies error handling by allowing a function to return a single error type
/// that encapsulate multiple error types. See the "Examples" section and [the book][book] for more
///
/// # Generic Implementations
///
-/// - [`From<T>`]` for U` implies [`Into<U>`]` for T`
-/// - [`From`] is reflexive, which means that `From<T> for T` is implemented
+/// - `From<T> for U` implies [`Into`]`<U> for T`
+/// - `From` is reflexive, which means that `From<T> for T` is implemented
///
/// # Examples
///
/// [`String`] implements `From<&str>`:
///
-/// An explicit conversion from a &str to a String is done as follows:
+/// An explicit conversion from a `&str` to a String is done as follows:
+///
/// ```
/// let string = "hello".to_string();
/// let other_string = String::from("hello");
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
/// [`String`]: ../../std/string/struct.String.html
-/// [`Into<U>`]: trait.Into.html
+/// [`Into`]: trait.Into.html
/// [`from`]: trait.From.html#tymethod.from
/// [book]: ../../book/ch09-00-error-handling.html
#[stable(feature = "rust1", since = "1.0.0")]
///
/// # Generic Implementations
///
-/// - `TryFrom<T> for U` implies [`TryInto<U>`]` for T`
+/// - `TryFrom<T> for U` implies [`TryInto`]`<U> for T`
/// - [`try_from`] is reflexive, which means that `TryFrom<T> for T`
/// is implemented and cannot fail -- the associated `Error` type for
/// calling `T::try_from()` on a value of type `T` is `Infallible`.
/// When using a future, you generally won't call `poll` directly, but instead
/// `await!` the value.
#[doc(spotlight)]
-#[must_use = "futures do nothing unless polled"]
+#[must_use = "futures do nothing unless you `.await` or poll them"]
#[stable(feature = "futures_api", since = "1.36.0")]
pub trait Future {
/// The type of value produced on completion.
{
self.iter.position(predicate)
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
// #[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);
/// 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::<T>() as *mut T;
/// 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<U>(self) -> NonNull<U> {
unsafe {
NonNull::new_unchecked(self.as_ptr() as *mut U)
/// The caller must ensure that the slice outlives the pointer this
/// function returns, or else it will end up pointing to garbage.
///
+ /// The caller must also ensure that the memory the pointer (non-transitively) points to
+ /// is never written to (except inside an `UnsafeCell`) using this pointer or any pointer
+ /// derived from it. If you need to mutate the contents of the slice, use [`as_mut_ptr`].
+ ///
/// Modifying the container referenced by this slice may cause its buffer
/// to be reallocated, which would also make any pointers to it invalid.
///
/// }
/// }
/// ```
+ ///
+ /// [`as_mut_ptr`]: #method.as_mut_ptr
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub const fn as_ptr(&self) -> *const T {
(1, Some(self.v.len() + 1))
}
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
(1, Some(self.v.len() + 1))
}
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "slice_rsplit", since = "1.27.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "slice_rsplit", since = "1.27.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
/// [`u8`]. This pointer will be pointing to the first byte of the string
/// slice.
///
+ /// The caller must ensure that the returned pointer is never written to.
+ /// If you need to mutate the contents of the string slice, use [`as_mut_ptr`].
+ ///
/// [`u8`]: primitive.u8.html
+ /// [`as_mut_ptr`]: #method.as_mut_ptr
///
/// # Examples
///
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "split_whitespace", since = "1.1.0")]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
#![feature(slice_partition_dedup)]
#![feature(copy_within)]
#![feature(int_error_matching)]
-#![deny(rust_2018_idioms)]
+#![warn(rust_2018_idioms)]
extern crate test;
chalk-engine = { version = "0.9.0", default-features=false }
rustc_fs_util = { path = "../librustc_fs_util" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }
-measureme = "0.2.1"
+measureme = "0.3"
# Note that these dependencies are a lie, they're just here to get linkage to
# work.
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]
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)]
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)
}
}
// ```
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();
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 {
continue
}
}
- "packed" => {
+ sym::packed => {
if target != Target::Struct &&
target != Target::Union {
("a", "struct or union")
continue
}
}
- "simd" => {
+ sym::simd => {
is_simd = true;
if target != Target::Struct {
("a", "struct")
continue
}
}
- "transparent" => {
+ sym::transparent => {
is_transparent = true;
if target != Target::Struct {
("a", "struct")
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")
// 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,
_ => 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,
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");
}
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);
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;
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};
const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF;
pub struct LoweringContext<'a> {
- crate_root: Option<&'static str>,
+ crate_root: Option<Symbol>,
/// Used to assign ids to HIR nodes that do not directly correspond to an AST node.
sess: &'a Session,
fn resolve_str_path(
&mut self,
span: Span,
- crate_root: Option<&str>,
- components: &[&str],
+ crate_root: Option<Symbol>,
+ components: &[Symbol],
is_value: bool,
) -> hir::Path;
}
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,
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<Lrc<[Symbol]>>,
- ) -> 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<R>(
&mut self,
anonymous_lifetime_mode: AnonymousLifetimeMode,
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![
].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])
}
// 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,
) -> 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,
// ::std::future::Future<future_params>
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 {
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(),
};
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,
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 {
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()))
}
// 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(
}),
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![
|x: P<hir::Expr>| 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)
})
}
self.expr_call_std_assoc_fn(
id,
e.span,
- &["ops", "RangeInclusive"],
+ &[sym::ops, sym::RangeInclusive],
"new",
hir_vec![e1, e2],
)
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")
.collect::<P<[hir::Field]>>();
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));
arms.push(self.arm(pats, body_expr));
}
- // _ => [<else_opt>|()]
+ // _ => [<else_opt>|{}]
{
let wildcard_arm: Option<&Expr> = else_opt.as_ref().map(|p| &**p);
let wildcard_pattern = self.pat_wild(e.span);
let body = if let Some(else_expr) = wildcard_arm {
- P(self.lower_expr(else_expr))
+ self.lower_expr(else_expr)
} else {
- P(self.expr_tuple(e.span, hir_vec![]))
+ self.expr_block_empty(e.span)
};
- arms.push(self.arm(hir_vec![wildcard_pattern], body));
+ arms.push(self.arm(hir_vec![wildcard_pattern], P(body)));
}
let contains_else_clause = else_opt.is_some();
// expand <head>
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,
let match_expr = {
let iter = P(self.expr_ident(head_sp, iter, iter_pat_nid));
let ref_mut_iter = self.expr_mut_addr_of(head_sp, iter);
- let next_path = &["iter", "Iterator", "next"];
+ let next_path = &[sym::iter, sym::Iterator, sym::next];
let next_expr = P(self.expr_call_std_path(
head_sp,
next_path,
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));
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,
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
- let into_iter_path = &["iter", "IntoIterator", "into_iter"];
+ let into_iter_path =
+ &[sym::iter, sym::IntoIterator, sym::into_iter];
P(self.expr_call_std_path(
head_sp,
into_iter_path,
// 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![
].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![
// expand <expr>
let sub_expr = self.lower_expr(sub_expr);
- let path = &["ops", "Try", "into_result"];
+ let path = &[sym::ops, sym::Try, sym::into_result];
P(self.expr_call_std_path(
unstable_span,
path,
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 from_path = &["convert", "From", "from"];
+ let from_path = &[sym::convert, sym::From, sym::from];
let err_expr = self.expr_ident(try_span, err_ident, err_local_nid);
self.expr_call_std_path(try_span, from_path, hir_vec![err_expr])
};
let from_err_expr =
- self.wrap_in_try_constructor("from_error", from_expr, unstable_span);
+ self.wrap_in_try_constructor(sym::from_error, from_expr, unstable_span);
let thin_attrs = ThinVec::from(attrs);
let catch_scope = self.catch_scopes.last().map(|x| *x);
let ret_expr = if let Some(catch_node) = catch_scope {
.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({
fn expr_call_std_path(
&mut self,
span: Span,
- path_components: &[&str],
+ path_components: &[Symbol],
args: hir::HirVec<hir::Expr>,
) -> hir::Expr {
let path = P(self.expr_std_path(span, path_components, None, ThinVec::new()));
&mut self,
ty_path_id: hir::HirId,
span: Span,
- ty_path_components: &[&str],
+ ty_path_components: &[Symbol],
assoc_fn_name: &str,
args: hir::HirVec<hir::Expr>,
) -> hir::ExprKind {
fn expr_std_path(
&mut self,
span: Span,
- components: &[&str],
+ components: &[Symbol],
params: Option<P<hir::GenericArgs>>,
attrs: ThinVec<Attribute>,
) -> hir::Expr {
}
}
+ 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<P<hir::Expr>>,
+ span: Span,
+ init: Option<P<hir::Expr>>,
pat: P<hir::Pat>,
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::Expr>) -> hir::Block {
)
}
+ /// Constructs a `true` or `false` literal pattern.
+ fn pat_bool(&mut self, span: Span, val: bool) -> P<hir::Pat> {
+ 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<hir::Pat>) -> P<hir::Pat> {
- 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<hir::Pat>) -> P<hir::Pat> {
- 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<hir::Pat>) -> P<hir::Pat> {
- 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<hir::Pat> {
- 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<hir::Pat>>,
) -> P<hir::Pat> {
let path = self.std_path(span, components, None, true);
fn std_path(
&mut self,
span: Span,
- components: &[&str],
+ components: &[Symbol],
params: Option<P<hir::GenericArgs>>,
is_value: bool,
) -> hir::Path {
fn wrap_in_try_constructor(
&mut self,
- method: &'static str,
+ method: Symbol,
e: hir::Expr,
unstable_span: Span,
) -> P<hir::Expr> {
- 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]))
);
self.sess.abort_if_errors();
}
- let span = self.mark_span_with_reason(
+ let span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
None,
);
- let gen_future_span = self.mark_span_with_reason(
+ let gen_future_span = self.sess.source_map().mark_span_with_reason(
CompilerDesugaringKind::Await,
await_span,
Some(vec![Symbol::intern("gen_future")].into()),
let new_unchecked_expr_kind = self.expr_call_std_assoc_fn(
pin_ty_id,
span,
- &["pin", "Pin"],
+ &[sym::pin, sym::Pin],
"new_unchecked",
hir_vec![ref_mut_pinned],
);
let unsafe_expr = self.expr_unsafe(new_unchecked);
P(self.expr_call_std_path(
gen_future_span,
- &["future", "poll_with_tls_context"],
+ &[sym::future, sym::poll_with_tls_context],
hir_vec![unsafe_expr],
))
};
let x_expr = P(self.expr_ident(span, x_ident, x_pat_hid));
let ready_pat = self.pat_std_enum(
span,
- &["task", "Poll", "Ready"],
+ &[sym::task, sym::Poll, sym::Ready],
hir_vec![x_pat],
);
let break_x = self.with_loop_scope(loop_node_id, |this| {
let pending_arm = {
let pending_pat = self.pat_std_enum(
span,
- &["task", "Poll", "Pending"],
+ &[sym::task, sym::Poll, sym::Pending],
hir_vec![],
);
- let empty_block = P(hir::Block {
- stmts: hir_vec![],
- expr: None,
- hir_id: self.next_id(),
- rules: hir::DefaultBlock,
- span,
- targeted_by_break: false,
- });
- let empty_block = P(self.expr_block(empty_block, ThinVec::new()));
+ let empty_block = P(self.expr_block_empty(span));
self.arm(hir_vec![pending_pat], empty_block)
};
hir_vec![ready_arm, pending_arm],
hir::MatchSource::AwaitDesugar,
));
- hir::Stmt {
- hir_id: self.next_id(),
- node: hir::StmtKind::Expr(match_expr),
- span,
- }
+ self.stmt(span, hir::StmtKind::Expr(match_expr))
};
let yield_stmt = {
hir::ExprKind::Yield(P(unit)),
ThinVec::new(),
));
- hir::Stmt {
- hir_id: self.next_id(),
- node: hir::StmtKind::Expr(yield_expr),
- span,
- }
+ self.stmt(span, hir::StmtKind::Expr(yield_expr))
};
let loop_block = P(self.block_all(
None => return false,
Some((node_id, name)) => (node_id, name),
};
- if mod_name != &**part {
+ if mod_name.as_str() != *part {
return false;
}
cursor = self.map.get_parent_item(mod_id);
// We are looking at some node `n` with a given name and parent
// id; do their names match what I am seeking?
fn matches_names(&self, parent_of_n: HirId, name: Name) -> bool {
- name == &**self.item_name && self.suffix_matches(parent_of_n)
+ name.as_str() == *self.item_name && self.suffix_matches(parent_of_n)
}
fn matches_suffix(&self, hir: HirId) -> bool {
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;
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]
}
}
+/// A literal.
+pub type Lit = Spanned<LitKind>;
+
/// 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)
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,
ExprKind::MethodCall(..) |
ExprKind::Struct(..) |
ExprKind::Tup(..) |
- ExprKind::If(..) |
ExprKind::Match(..) |
ExprKind::Closure(..) |
ExprKind::Block(..) |
/// This construct only exists to tweak the drop order in HIR lowering.
/// An example of that is the desugaring of `for` loops.
DropTemps(P<Expr>),
- /// An `if` block, with an optional else block.
- ///
- /// I.e., `if <expr> { <expr> } else { <expr> }`.
- If(P<Expr>, P<Expr>, Option<P<Expr>>),
/// A while loop, with an optional label
///
/// I.e., `'label: while expr { <block> }`.
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,
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};
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> {
pub s: pp::Printer<'a>,
cm: Option<&'a SourceMap>,
comments: Option<Vec<comments::Comment>>,
- literals: Peekable<vec::IntoIter<comments::Literal>>,
cur_cmnt: usize,
boxes: Vec<pp::Breaks>,
ann: &'a (dyn PpAnn + '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<comments::Literal> {
- self.literals.next()
- }
}
#[allow(non_upper_case_globals)]
/// 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<dyn Write + 'a>,
- 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.
filename: FileName,
input: &mut dyn Read,
out: Box<dyn Write + 'a>,
- 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<dyn Write + 'a>,
ann: &'a dyn PpAnn,
- comments: Option<Vec<comments::Comment>>,
- literals: Option<Vec<comments::Literal>>)
+ comments: Option<Vec<comments::Comment>>)
-> 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,
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,
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 {
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))
}
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)?;
// 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)?;
/// 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(..) |
fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
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
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),
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 });
}
}
+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>,
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);
}
});
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
+ IfTemporary,
Async,
Await,
QuestionMark,
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;
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,
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;
}
}
}
- 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 {
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,
_ => { }
}
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),
}
}
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<LintSet>,
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,
};
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
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"
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");
}
}
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,
_ => None,
}
}
+
+ /// Converts a symbol to a level.
+ pub fn from_symbol(x: Symbol) -> Option<Level> {
+ 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.
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)
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
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;
}
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;
}
// 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;
}
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
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;
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;
/// are also extracted out when found.
pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
attrs.iter().find_map(|attr| Some(match attr {
- _ if attr.check_name("lang") => (attr.value_str()?, attr.span),
- _ if attr.check_name("panic_handler") => (Symbol::intern("panic_impl"), attr.span),
- _ if attr.check_name("alloc_error_handler") => (Symbol::intern("oom"), attr.span),
+ _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span),
+ _ if attr.check_name(sym::panic_handler) => (Symbol::intern("panic_impl"), attr.span),
+ _ if attr.check_name(sym::alloc_error_handler) => (Symbol::intern("oom"), attr.span),
_ => return None,
}))
}
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;
}
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, 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 (..)]`).
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,
_ => {}
}
}
// 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));
}
}
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;
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;
}
}
}
// live nodes required for interesting control flow:
- hir::ExprKind::If(..) |
hir::ExprKind::Match(..) |
hir::ExprKind::While(..) |
hir::ExprKind::Loop(..) => {
})
}
- 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)
}
}
// 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(..) |
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;
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(..) |
// 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);
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<usize>, name: &str, default: usize) {
+fn update_limit(krate: &ast::Crate, limit: &Once<usize>, name: Symbol, default: usize) {
for attr in &krate.attrs {
if !attr.check_name(name) {
continue;
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);
}
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};
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 {
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;
// 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");
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;
}
// 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;
}
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);
}
}
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");
}
}
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};
pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> {
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
}
}
Other {
- query target_features_whitelist(_: CrateNum) -> Lrc<FxHashMap<String, Option<String>>> {
+ query target_features_whitelist(_: CrateNum) -> Lrc<FxHashMap<String, Option<Symbol>>> {
eval_always
desc { "looking up the whitelist of target features" }
}
opt::multi_s(
"",
"print",
- "Comma separated list of compiler information to \
- print on stdout",
+ "Compiler information to print on stdout",
"[crate-name|file-names|sysroot|cfg|target-list|\
target-cpus|target-features|relocation-models|\
code-models|tls-models|target-spec-json|native-static-libs]",
// 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()]) {
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());
});
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;
/// in order to avoid redundantly verbose output (Issue #24690, #44953).
pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
pub plugin_llvm_passes: OneThread<RefCell<Vec<String>>>,
- pub plugin_attributes: Lock<Vec<(String, AttributeType)>>,
+ pub plugin_attributes: Lock<Vec<(Symbol, AttributeType)>>,
pub crate_types: Once<Vec<config::CrateType>>,
pub dependency_formats: Once<dependency_format::Dependencies>,
/// The crate_disambiguator is constructed out of all the `-C metadata`
//! [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.
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> {
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> {
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
use syntax::ast::{MetaItem, NestedMetaItem};
use syntax::attr;
+use syntax::symbol::sym;
use syntax_pos::Span;
use syntax_pos::symbol::LocalInternedString;
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() {
{
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);
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};
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!()
use rustc_data_structures::bit_set::GrowableBitSet;
use rustc_data_structures::sync::Lock;
use rustc_target::spec::abi::Abi;
+use std::cell::Cell;
use std::cmp;
use std::fmt::{self, Display};
use std::iter;
/// selection-context's freshener. Used to check for recursion.
fresh_trait_ref: ty::PolyTraitRef<'tcx>,
+ /// Starts out as false -- if, during evaluation, we encounter a
+ /// cycle, then we will set this flag to true for all participants
+ /// in the cycle (apart from the "head" node). These participants
+ /// will then forego caching their results. This is not the most
+ /// efficient solution, but it addresses #60010. The problem we
+ /// are trying to prevent:
+ ///
+ /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait`
+ /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok)
+ /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok)
+ ///
+ /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait`
+ /// is `EvaluatedToOk`; this is because they were only considered
+ /// ok on the premise that if `A: AutoTrait` held, but we indeed
+ /// encountered a problem (later on) with `A: AutoTrait. So we
+ /// currently set a flag on the stack node for `B: AutoTrait` (as
+ /// well as the second instance of `A: AutoTrait`) to supress
+ /// caching.
+ ///
+ /// This is a simple, targeted fix. A more-performant fix requires
+ /// deeper changes, but would permit more caching: we could
+ /// basically defer caching until we have fully evaluated the
+ /// tree, and then cache the entire tree at once. In any case, the
+ /// performance impact here shouldn't be so horrible: every time
+ /// this is hit, we do cache at least one trait, so we only
+ /// evaluate each member of a cycle up to N times, where N is the
+ /// length of the cycle. This means the performance impact is
+ /// bounded and we shouldn't have any terrible worst-cases.
+ in_cycle: Cell<bool>,
+
previous: TraitObligationStackList<'prev, 'tcx>,
}
let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
let result = result?;
- debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
- self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+ if !stack.in_cycle.get() {
+ debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result);
+ self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+ } else {
+ debug!(
+ "evaluate_trait_predicate_recursively: skipping cache because {:?} \
+ is a cycle participant",
+ fresh_trait_ref,
+ );
+ }
Ok(result)
}
{
debug!("evaluate_stack({:?}) --> recursive", stack.fresh_trait_ref);
+ // If we have a stack like `A B C D E A`, where the top of
+ // the stack is the final `A`, then this will iterate over
+ // `A, E, D, C, B` -- i.e., all the participants apart
+ // from the cycle head. We mark them as participating in a
+ // cycle. This suppresses caching for those nodes. See
+ // `in_cycle` field for more details.
+ for item in stack.iter().take(rec_index + 1) {
+ debug!("evaluate_stack: marking {:?} as cycle participant", item.fresh_trait_ref);
+ item.in_cycle.set(true);
+ }
+
// Subtle: when checking for a coinductive cycle, we do
// not compare using the "freshened trait refs" (which
// have erased regions) but rather the fully explicit
TraitObligationStack {
obligation,
fresh_trait_ref,
+ in_cycle: Cell::new(false),
previous: previous_stack,
}
}
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;
}
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<T: ?Sized + Lift<'tcx>>(self, value: &T) -> Option<T::Lifted> {
};
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)
};
}
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())
+ }))
+ }
}
}
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)
+ }))
+ }
}
}
StableHasherResult};
pub use rustc_target::abi::*;
+use rustc_target::spec::{HasTargetSpec, abi::Abi as SpecAbi};
+use rustc_target::abi::call::{
+ ArgAttribute, ArgAttributes, ArgType, Conv, FnType, IgnoreMode, PassMode, Reg, RegKind
+};
+
+
pub trait IntegerExt {
fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, signed: bool) -> Ty<'tcx>;
}
}
}
+
+pub trait FnTypeExt<'tcx, C>
+where
+ C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+ + HasDataLayout
+ + HasTargetSpec
+ + HasTyCtxt<'tcx>
+ + HasParamEnv<'tcx>,
+{
+ fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self;
+ fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+ fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self;
+ fn new_internal(
+ cx: &C,
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>],
+ mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+ ) -> Self;
+ fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
+}
+
+impl<'tcx, C> FnTypeExt<'tcx, C> for call::FnType<'tcx, Ty<'tcx>>
+where
+ C: LayoutOf<Ty = Ty<'tcx>, TyLayout = TyLayout<'tcx>>
+ + HasDataLayout
+ + HasTargetSpec
+ + HasTyCtxt<'tcx>
+ + HasParamEnv<'tcx>,
+{
+ fn of_instance(cx: &C, instance: &ty::Instance<'tcx>) -> Self {
+ let sig = instance.fn_sig(cx.tcx());
+ let sig = cx
+ .tcx()
+ .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
+ call::FnType::new(cx, sig, &[])
+ }
+
+ fn new(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+ call::FnType::new_internal(cx, sig, extra_args, |ty, _| ArgType::new(cx.layout_of(ty)))
+ }
+
+ fn new_vtable(cx: &C, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
+ FnTypeExt::new_internal(cx, sig, extra_args, |ty, arg_idx| {
+ let mut layout = cx.layout_of(ty);
+ // Don't pass the vtable, it's not an argument of the virtual fn.
+ // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
+ // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
+ if arg_idx == Some(0) {
+ let fat_pointer_ty = if layout.is_unsized() {
+ // unsized `self` is passed as a pointer to `self`
+ // FIXME (mikeyhew) change this to use &own if it is ever added to the language
+ cx.tcx().mk_mut_ptr(layout.ty)
+ } else {
+ match layout.abi {
+ Abi::ScalarPair(..) => (),
+ _ => bug!("receiver type has unsupported layout: {:?}", layout),
+ }
+
+ // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
+ // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
+ // elsewhere in the compiler as a method on a `dyn Trait`.
+ // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
+ // get a built-in pointer type
+ let mut fat_pointer_layout = layout;
+ 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
+ && !fat_pointer_layout.ty.is_region_ptr()
+ {
+ 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
+ let field_layout = fat_pointer_layout.field(cx, i);
+
+ if !field_layout.is_zst() {
+ fat_pointer_layout = field_layout;
+ continue 'descend_newtypes;
+ }
+ }
+
+ bug!(
+ "receiver has no non-zero-sized fields {:?}",
+ fat_pointer_layout
+ );
+ }
+
+ fat_pointer_layout.ty
+ };
+
+ // we now have a type like `*mut RcBox<dyn Trait>`
+ // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
+ // this is understood as a special case elsewhere in the compiler
+ let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
+ layout = cx.layout_of(unit_pointer_ty);
+ layout.ty = fat_pointer_ty;
+ }
+ ArgType::new(layout)
+ })
+ }
+
+ fn new_internal(
+ cx: &C,
+ sig: ty::FnSig<'tcx>,
+ extra_args: &[Ty<'tcx>],
+ mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
+ ) -> Self {
+ debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
+
+ use rustc_target::spec::abi::Abi::*;
+ let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::C,
+
+ // It's the ABI's job to select this, not ours.
+ System => bug!("system abi should be selected elsewhere"),
+
+ Stdcall => Conv::X86Stdcall,
+ Fastcall => Conv::X86Fastcall,
+ Vectorcall => Conv::X86VectorCall,
+ Thiscall => Conv::X86ThisCall,
+ C => Conv::C,
+ Unadjusted => Conv::C,
+ Win64 => Conv::X86_64Win64,
+ SysV64 => Conv::X86_64SysV,
+ Aapcs => Conv::ArmAapcs,
+ PtxKernel => Conv::PtxKernel,
+ Msp430Interrupt => Conv::Msp430Intr,
+ X86Interrupt => Conv::X86Intr,
+ AmdGpuKernel => Conv::AmdGpuKernel,
+
+ // These API constants ought to be more specific...
+ Cdecl => Conv::C,
+ };
+
+ let mut inputs = sig.inputs();
+ let extra_args = if sig.abi == RustCall {
+ assert!(!sig.c_variadic && extra_args.is_empty());
+
+ match sig.inputs().last().unwrap().sty {
+ ty::Tuple(tupled_arguments) => {
+ inputs = &sig.inputs()[0..sig.inputs().len() - 1];
+ tupled_arguments.iter().map(|k| k.expect_ty()).collect()
+ }
+ _ => {
+ bug!(
+ "argument to function with \"rust-call\" ABI \
+ is not a tuple"
+ );
+ }
+ }
+ } else {
+ assert!(sig.c_variadic || extra_args.is_empty());
+ extra_args.to_vec()
+ };
+
+ let target = &cx.tcx().sess.target.target;
+ let win_x64_gnu =
+ target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu";
+ let linux_s390x =
+ target.target_os == "linux" && target.arch == "s390x" && target.target_env == "gnu";
+ let linux_sparc64 =
+ target.target_os == "linux" && target.arch == "sparc64" && target.target_env == "gnu";
+ let rust_abi = match sig.abi {
+ RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
+ _ => false,
+ };
+
+ // Handle safe Rust thin and fat pointers.
+ let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
+ scalar: &Scalar,
+ layout: TyLayout<'tcx>,
+ offset: Size,
+ is_return: bool| {
+ // Booleans are always an i1 that needs to be zero-extended.
+ if scalar.is_bool() {
+ attrs.set(ArgAttribute::ZExt);
+ return;
+ }
+
+ // Only pointer types handled below.
+ if scalar.value != Pointer {
+ return;
+ }
+
+ if scalar.valid_range.start() < scalar.valid_range.end() {
+ if *scalar.valid_range.start() > 0 {
+ attrs.set(ArgAttribute::NonNull);
+ }
+ }
+
+ if let Some(pointee) = layout.pointee_info_at(cx, offset) {
+ if let Some(kind) = pointee.safe {
+ attrs.pointee_size = pointee.size;
+ attrs.pointee_align = Some(pointee.align);
+
+ // `Box` pointer parameters never alias because ownership is transferred
+ // `&mut` pointer parameters never alias other parameters,
+ // or mutable global data
+ //
+ // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
+ // and can be marked as both `readonly` and `noalias`, as
+ // LLVM's definition of `noalias` is based solely on memory
+ // dependencies rather than pointer equality
+ let no_alias = match kind {
+ PointerKind::Shared => false,
+ PointerKind::UniqueOwned => true,
+ PointerKind::Frozen | PointerKind::UniqueBorrowed => !is_return,
+ };
+ if no_alias {
+ attrs.set(ArgAttribute::NoAlias);
+ }
+
+ if kind == PointerKind::Frozen && !is_return {
+ attrs.set(ArgAttribute::ReadOnly);
+ }
+ }
+ }
+ };
+
+ // Store the index of the last argument. This is useful for working with
+ // C-compatible variadic arguments.
+ let last_arg_idx = if sig.inputs().is_empty() {
+ None
+ } else {
+ Some(sig.inputs().len() - 1)
+ };
+
+ let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
+ let is_return = arg_idx.is_none();
+ let mut arg = mk_arg_type(ty, arg_idx);
+ if arg.layout.is_zst() {
+ // For some forsaken reason, x86_64-pc-windows-gnu
+ // doesn't ignore zero-sized struct arguments.
+ // The same is true for s390x-unknown-linux-gnu
+ // and sparc64-unknown-linux-gnu.
+ if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
+ arg.mode = PassMode::Ignore(IgnoreMode::Zst);
+ }
+ }
+
+ // If this is a C-variadic function, this is not the return value,
+ // and there is one or more fixed arguments; ensure that the `VaList`
+ // is ignored as an argument.
+ if sig.c_variadic {
+ match (last_arg_idx, arg_idx) {
+ (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
+ let va_list_did = match cx.tcx().lang_items().va_list() {
+ Some(did) => did,
+ None => bug!("`va_list` lang item required for C-variadic functions"),
+ };
+ match ty.sty {
+ ty::Adt(def, _) if def.did == va_list_did => {
+ // This is the "spoofed" `VaList`. Set the arguments mode
+ // so that it will be ignored.
+ arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
+ }
+ _ => (),
+ }
+ }
+ _ => {}
+ }
+ }
+
+ // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
+ if !is_return && rust_abi {
+ if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
+ let mut a_attrs = ArgAttributes::new();
+ let mut b_attrs = ArgAttributes::new();
+ adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false);
+ adjust_for_rust_scalar(
+ &mut b_attrs,
+ b,
+ arg.layout,
+ a.value.size(cx).align_to(b.value.align(cx).abi),
+ false,
+ );
+ arg.mode = PassMode::Pair(a_attrs, b_attrs);
+ return arg;
+ }
+ }
+
+ if let Abi::Scalar(ref scalar) = arg.layout.abi {
+ if let PassMode::Direct(ref mut attrs) = arg.mode {
+ adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return);
+ }
+ }
+
+ arg
+ };
+
+ let mut fn_ty = FnType {
+ ret: arg_of(sig.output(), None),
+ args: inputs
+ .iter()
+ .cloned()
+ .chain(extra_args)
+ .enumerate()
+ .map(|(i, ty)| arg_of(ty, Some(i)))
+ .collect(),
+ c_variadic: sig.c_variadic,
+ conv,
+ };
+ fn_ty.adjust_for_abi(cx, sig.abi);
+ fn_ty
+ }
+
+ fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi) {
+ if abi == SpecAbi::Unadjusted {
+ return;
+ }
+
+ if abi == SpecAbi::Rust
+ || abi == SpecAbi::RustCall
+ || abi == SpecAbi::RustIntrinsic
+ || abi == SpecAbi::PlatformIntrinsic
+ {
+ let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
+ if arg.is_ignore() {
+ return;
+ }
+
+ match arg.layout.abi {
+ Abi::Aggregate { .. } => {}
+
+ // This is a fun case! The gist of what this is doing is
+ // that we want callers and callees to always agree on the
+ // ABI of how they pass SIMD arguments. If we were to *not*
+ // make these arguments indirect then they'd be immediates
+ // in LLVM, which means that they'd used whatever the
+ // appropriate ABI is for the callee and the caller. That
+ // means, for example, if the caller doesn't have AVX
+ // enabled but the callee does, then passing an AVX argument
+ // across this boundary would cause corrupt data to show up.
+ //
+ // This problem is fixed by unconditionally passing SIMD
+ // arguments through memory between callers and callees
+ // which should get them all to agree on ABI regardless of
+ // target feature sets. Some more information about this
+ // issue can be found in #44367.
+ //
+ // Note that the platform intrinsic ABI is exempt here as
+ // that's how we connect up to LLVM and it's unstable
+ // anyway, we control all calls to it in libstd.
+ Abi::Vector { .. }
+ if abi != SpecAbi::PlatformIntrinsic
+ && cx.tcx().sess.target.target.options.simd_types_indirect =>
+ {
+ arg.make_indirect();
+ return;
+ }
+
+ _ => return,
+ }
+
+ let size = arg.layout.size;
+ if arg.layout.is_unsized() || size > Pointer.size(cx) {
+ arg.make_indirect();
+ } else {
+ // We want to pass small aggregates as immediates, but using
+ // a LLVM aggregate type for this leads to bad optimizations,
+ // so we pick an appropriately sized integer type instead.
+ arg.cast_to(Reg {
+ kind: RegKind::Integer,
+ size,
+ });
+ }
+ };
+ fixup(&mut self.ret);
+ for arg in &mut self.args {
+ fixup(arg);
+ }
+ if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
+ attrs.set(ArgAttribute::StructRet);
+ }
+ return;
+ }
+
+ if let Err(msg) = self.adjust_for_cabi(cx, abi) {
+ cx.tcx().sess.fatal(&msg);
+ }
+ }
+}
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;
);
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;
}
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;
}
}
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() {
}
/// 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)
}
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)]
// 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<T:Clone>`).
- 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![];
}
mut_visit::{self, MutVisitor},
parse::ParseSess,
ptr::P,
- symbol::Symbol
+ symbol::{Symbol, sym}
};
use syntax_pos::Span;
fn flat_map_item(&mut self, item: P<Item>) -> SmallVec<[P<Item>; 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);
use rustc_codegen_ssa::traits::*;
-use rustc_target::abi::{HasDataLayout, LayoutOf, Size, TyLayout, Abi as LayoutAbi};
-use rustc::ty::{self, Ty, Instance};
-use rustc::ty::layout::{self, PointerKind};
+use rustc_target::abi::{HasDataLayout, LayoutOf};
+use rustc::ty::{Ty};
+use rustc::ty::layout::{self};
use libc::c_uint;
}
}
-pub trait FnTypeExt<'tcx> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self;
- fn new(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self;
- fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self;
- fn new_internal(
- cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>],
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
- ) -> Self;
- fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'ll, 'tcx>,
- abi: Abi);
+pub trait FnTypeLlvmExt<'tcx> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn ptr_to_llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type;
fn llvm_cconv(&self) -> llvm::CallConv;
fn apply_attrs_callsite(&self, bx: &mut Builder<'a, 'll, 'tcx>, callsite: &'ll Value);
}
-impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
- fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
- let sig = instance.fn_sig(cx.tcx);
- let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
- FnType::new(cx, sig, &[])
- }
-
- fn new(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
- FnType::new_internal(cx, sig, extra_args, |ty, _| {
- ArgType::new(cx.layout_of(ty))
- })
- }
-
- fn new_vtable(cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]) -> Self {
- FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| {
- let mut layout = cx.layout_of(ty);
- // Don't pass the vtable, it's not an argument of the virtual fn.
- // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
- // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
- if arg_idx == Some(0) {
- let fat_pointer_ty = if layout.is_unsized() {
- // unsized `self` is passed as a pointer to `self`
- // FIXME (mikeyhew) change this to use &own if it is ever added to the language
- cx.tcx.mk_mut_ptr(layout.ty)
- } else {
- match layout.abi {
- LayoutAbi::ScalarPair(..) => (),
- _ => bug!("receiver type has unsupported layout: {:?}", layout)
- }
-
- // In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
- // with a Scalar (not ScalarPair) ABI. This is a hack that is understood
- // elsewhere in the compiler as a method on a `dyn Trait`.
- // To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
- // get a built-in pointer type
- let mut fat_pointer_layout = layout;
- 'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
- && !fat_pointer_layout.ty.is_region_ptr()
- {
- 'iter_fields: for i in 0..fat_pointer_layout.fields.count() {
- let field_layout = fat_pointer_layout.field(cx, i);
-
- if !field_layout.is_zst() {
- fat_pointer_layout = field_layout;
- continue 'descend_newtypes
- }
- }
-
- bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
- }
-
- fat_pointer_layout.ty
- };
-
- // we now have a type like `*mut RcBox<dyn Trait>`
- // change its layout to that of `*mut ()`, a thin pointer, but keep the same type
- // this is understood as a special case elsewhere in the compiler
- let unit_pointer_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_unit());
- layout = cx.layout_of(unit_pointer_ty);
- layout.ty = fat_pointer_ty;
- }
- ArgType::new(layout)
- })
- }
-
- fn new_internal(
- cx: &CodegenCx<'ll, 'tcx>,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>],
- mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgType<'tcx, Ty<'tcx>>,
- ) -> Self {
- debug!("FnType::new_internal({:?}, {:?})", sig, extra_args);
-
- use self::Abi::*;
- let conv = match cx.sess().target.target.adjust_abi(sig.abi) {
- RustIntrinsic | PlatformIntrinsic |
- Rust | RustCall => Conv::C,
-
- // It's the ABI's job to select this, not ours.
- System => bug!("system abi should be selected elsewhere"),
-
- Stdcall => Conv::X86Stdcall,
- Fastcall => Conv::X86Fastcall,
- Vectorcall => Conv::X86VectorCall,
- Thiscall => Conv::X86ThisCall,
- C => Conv::C,
- Unadjusted => Conv::C,
- Win64 => Conv::X86_64Win64,
- SysV64 => Conv::X86_64SysV,
- Aapcs => Conv::ArmAapcs,
- PtxKernel => Conv::PtxKernel,
- Msp430Interrupt => Conv::Msp430Intr,
- X86Interrupt => Conv::X86Intr,
- AmdGpuKernel => Conv::AmdGpuKernel,
-
- // These API constants ought to be more specific...
- Cdecl => Conv::C,
- };
-
- let mut inputs = sig.inputs();
- let extra_args = if sig.abi == RustCall {
- assert!(!sig.c_variadic && extra_args.is_empty());
-
- match sig.inputs().last().unwrap().sty {
- ty::Tuple(tupled_arguments) => {
- inputs = &sig.inputs()[0..sig.inputs().len() - 1];
- tupled_arguments.iter().map(|k| k.expect_ty()).collect()
- }
- _ => {
- bug!("argument to function with \"rust-call\" ABI \
- is not a tuple");
- }
- }
- } else {
- assert!(sig.c_variadic || extra_args.is_empty());
- extra_args.to_vec()
- };
-
- let target = &cx.sess().target.target;
- let win_x64_gnu = target.target_os == "windows"
- && target.arch == "x86_64"
- && target.target_env == "gnu";
- let linux_s390x = target.target_os == "linux"
- && target.arch == "s390x"
- && target.target_env == "gnu";
- let linux_sparc64 = target.target_os == "linux"
- && target.arch == "sparc64"
- && target.target_env == "gnu";
- let rust_abi = match sig.abi {
- RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
- _ => false
- };
-
- // Handle safe Rust thin and fat pointers.
- let adjust_for_rust_scalar = |attrs: &mut ArgAttributes,
- scalar: &layout::Scalar,
- layout: TyLayout<'tcx, Ty<'tcx>>,
- offset: Size,
- is_return: bool| {
- // Booleans are always an i1 that needs to be zero-extended.
- if scalar.is_bool() {
- attrs.set(ArgAttribute::ZExt);
- return;
- }
-
- // Only pointer types handled below.
- if scalar.value != layout::Pointer {
- return;
- }
-
- if scalar.valid_range.start() < scalar.valid_range.end() {
- if *scalar.valid_range.start() > 0 {
- attrs.set(ArgAttribute::NonNull);
- }
- }
-
- if let Some(pointee) = layout.pointee_info_at(cx, offset) {
- if let Some(kind) = pointee.safe {
- attrs.pointee_size = pointee.size;
- attrs.pointee_align = Some(pointee.align);
-
- // `Box` pointer parameters never alias because ownership is transferred
- // `&mut` pointer parameters never alias other parameters,
- // or mutable global data
- //
- // `&T` where `T` contains no `UnsafeCell<U>` is immutable,
- // and can be marked as both `readonly` and `noalias`, as
- // LLVM's definition of `noalias` is based solely on memory
- // dependencies rather than pointer equality
- let no_alias = match kind {
- PointerKind::Shared => false,
- PointerKind::UniqueOwned => true,
- PointerKind::Frozen |
- PointerKind::UniqueBorrowed => !is_return
- };
- if no_alias {
- attrs.set(ArgAttribute::NoAlias);
- }
-
- if kind == PointerKind::Frozen && !is_return {
- attrs.set(ArgAttribute::ReadOnly);
- }
- }
- }
- };
-
- // Store the index of the last argument. This is useful for working with
- // C-compatible variadic arguments.
- let last_arg_idx = if sig.inputs().is_empty() {
- None
- } else {
- Some(sig.inputs().len() - 1)
- };
-
- let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
- let is_return = arg_idx.is_none();
- let mut arg = mk_arg_type(ty, arg_idx);
- if arg.layout.is_zst() {
- // For some forsaken reason, x86_64-pc-windows-gnu
- // doesn't ignore zero-sized struct arguments.
- // The same is true for s390x-unknown-linux-gnu
- // and sparc64-unknown-linux-gnu.
- if is_return || rust_abi || (!win_x64_gnu && !linux_s390x && !linux_sparc64) {
- arg.mode = PassMode::Ignore(IgnoreMode::Zst);
- }
- }
-
- // If this is a C-variadic function, this is not the return value,
- // and there is one or more fixed arguments; ensure that the `VaList`
- // is ignored as an argument.
- if sig.c_variadic {
- match (last_arg_idx, arg_idx) {
- (Some(last_idx), Some(cur_idx)) if last_idx == cur_idx => {
- let va_list_did = match cx.tcx.lang_items().va_list() {
- Some(did) => did,
- None => bug!("`va_list` lang item required for C-variadic functions"),
- };
- match ty.sty {
- ty::Adt(def, _) if def.did == va_list_did => {
- // This is the "spoofed" `VaList`. Set the arguments mode
- // so that it will be ignored.
- arg.mode = PassMode::Ignore(IgnoreMode::CVarArgs);
- },
- _ => (),
- }
- }
- _ => {}
- }
- }
-
- // FIXME(eddyb) other ABIs don't have logic for scalar pairs.
- if !is_return && rust_abi {
- if let layout::Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
- let mut a_attrs = ArgAttributes::new();
- let mut b_attrs = ArgAttributes::new();
- adjust_for_rust_scalar(&mut a_attrs,
- a,
- arg.layout,
- Size::ZERO,
- false);
- adjust_for_rust_scalar(&mut b_attrs,
- b,
- arg.layout,
- a.value.size(cx).align_to(b.value.align(cx).abi),
- false);
- arg.mode = PassMode::Pair(a_attrs, b_attrs);
- return arg;
- }
- }
-
- if let layout::Abi::Scalar(ref scalar) = arg.layout.abi {
- if let PassMode::Direct(ref mut attrs) = arg.mode {
- adjust_for_rust_scalar(attrs,
- scalar,
- arg.layout,
- Size::ZERO,
- is_return);
- }
- }
-
- arg
- };
-
- let mut fn_ty = FnType {
- ret: arg_of(sig.output(), None),
- args: inputs.iter().cloned().chain(extra_args).enumerate().map(|(i, ty)| {
- arg_of(ty, Some(i))
- }).collect(),
- c_variadic: sig.c_variadic,
- conv,
- };
- fn_ty.adjust_for_abi(cx, sig.abi);
- fn_ty
- }
-
- fn adjust_for_abi(&mut self,
- cx: &CodegenCx<'ll, 'tcx>,
- abi: Abi) {
- if abi == Abi::Unadjusted { return }
-
- if abi == Abi::Rust || abi == Abi::RustCall ||
- abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
- let fixup = |arg: &mut ArgType<'tcx, Ty<'tcx>>| {
- if arg.is_ignore() { return; }
-
- match arg.layout.abi {
- layout::Abi::Aggregate { .. } => {}
-
- // This is a fun case! The gist of what this is doing is
- // that we want callers and callees to always agree on the
- // ABI of how they pass SIMD arguments. If we were to *not*
- // make these arguments indirect then they'd be immediates
- // in LLVM, which means that they'd used whatever the
- // appropriate ABI is for the callee and the caller. That
- // means, for example, if the caller doesn't have AVX
- // enabled but the callee does, then passing an AVX argument
- // across this boundary would cause corrupt data to show up.
- //
- // This problem is fixed by unconditionally passing SIMD
- // arguments through memory between callers and callees
- // which should get them all to agree on ABI regardless of
- // target feature sets. Some more information about this
- // issue can be found in #44367.
- //
- // Note that the platform intrinsic ABI is exempt here as
- // that's how we connect up to LLVM and it's unstable
- // anyway, we control all calls to it in libstd.
- layout::Abi::Vector { .. }
- if abi != Abi::PlatformIntrinsic &&
- cx.sess().target.target.options.simd_types_indirect =>
- {
- arg.make_indirect();
- return
- }
-
- _ => return
- }
-
- let size = arg.layout.size;
- if arg.layout.is_unsized() || size > layout::Pointer.size(cx) {
- arg.make_indirect();
- } else {
- // We want to pass small aggregates as immediates, but using
- // a LLVM aggregate type for this leads to bad optimizations,
- // so we pick an appropriately sized integer type instead.
- arg.cast_to(Reg {
- kind: RegKind::Integer,
- size
- });
- }
- };
- fixup(&mut self.ret);
- for arg in &mut self.args {
- fixup(arg);
- }
- if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode {
- attrs.set(ArgAttribute::StructRet);
- }
- return;
- }
-
- if let Err(msg) = self.adjust_for_cabi(cx, abi) {
- cx.sess().fatal(&msg);
- }
- }
-
+impl<'tcx> FnTypeLlvmExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
fn llvm_type(&self, cx: &CodegenCx<'ll, 'tcx>) -> &'ll Type {
let args_capacity: usize = self.args.iter().map(|arg|
if arg.pad.is_some() { 1 } else { 0 } +
}
}
-impl AbiMethods<'tcx> for CodegenCx<'ll, 'tcx> {
- fn new_fn_type(&self, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>> {
- FnType::new(&self, sig, extra_args)
- }
- fn new_vtable(
- &self,
- sig: ty::FnSig<'tcx>,
- extra_args: &[Ty<'tcx>]
- ) -> FnType<'tcx, Ty<'tcx>> {
- FnType::new_vtable(&self, sig, extra_args)
- }
- fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>> {
- FnType::of_instance(&self, instance)
- }
-}
-
impl AbiBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
fn apply_attrs_callsite(
&mut self,
// 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())
}
};
use rustc_codegen_ssa::base::to_immediate;
use rustc_codegen_ssa::mir::operand::{OperandValue, OperandRef};
use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_target::spec::{HasTargetSpec, Target};
use std::borrow::Cow;
use std::ops::{Deref, Range};
use std::ptr;
}
}
+impl HasTargetSpec for Builder<'_, '_, 'tcx> {
+ fn target_spec(&self) -> &Target {
+ &self.cx.target_spec()
+ }
+}
+
impl ty::layout::LayoutOf for Builder<'_, '_, 'tcx> {
type Ty = Ty<'tcx>;
type TyLayout = TyLayout<'tcx>;
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::*;
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);
}
}
use rustc_codegen_ssa::traits::*;
use syntax::attr;
+use syntax::symbol::sym;
/// Inserts a side-effect free instruction sequence that makes sure that the
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 &&
use crate::llvm;
use crate::llvm::AttributePlace::Function;
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType, FnTypeLlvmExt};
use crate::attributes;
use crate::context::CodegenCx;
use crate::type_::Type;
use crate::value::Value;
use rustc::ty::{self, PolyFnSig};
-use rustc::ty::layout::LayoutOf;
+use rustc::ty::layout::{FnTypeExt, LayoutOf};
use rustc::session::config::Sanitizer;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_codegen_ssa::traits::*;
use libc::c_int;
use std::ffi::CString;
use syntax::feature_gate::UnstableFeatures;
+use syntax::symbol::sym;
use std::str;
use std::slice;
// 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<Symbol>)] = &[
+ ("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<Symbol>)] = &[
+ ("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<Symbol>)] = &[
+ ("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<Symbol>)] = &[
+ ("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<Symbol>)] = &[
+ ("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<Symbol>)] = &[
+ ("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<Symbol>)] = &[
+ ("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
///
/// 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<Item=(&'static str, Option<&'static str>)> {
+pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<Symbol>)> {
ARM_WHITELIST.iter().cloned()
.chain(AARCH64_WHITELIST.iter().cloned())
.chain(X86_WHITELIST.iter().cloned())
}
pub fn target_feature_whitelist(sess: &Session)
- -> &'static [(&'static str, Option<&'static str>)]
+ -> &'static [(&'static str, Option<Symbol>)]
{
match &*sess.target.target.arch {
"arm" => ARM_WHITELIST,
use crate::common;
use crate::type_of::LayoutLlvmExt;
-use crate::abi::{LlvmType, FnTypeExt};
+use crate::abi::{LlvmType, FnTypeLlvmExt};
use syntax::ast;
use rustc::ty::Ty;
use rustc::ty::layout::{self, Align, Size, TyLayout};
-use crate::abi::{FnType, FnTypeExt};
+use crate::abi::{FnType};
use crate::common::*;
use crate::type_::Type;
use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, Align, LayoutOf, PointeeInfo, Size, TyLayout};
+use rustc::ty::layout::{self, Align, LayoutOf, FnTypeExt, PointeeInfo, Size, TyLayout};
use rustc_target::abi::{FloatTy, TyLayoutMethods};
use rustc_mir::monomorphize::item::DefPathBasedNames;
use rustc_codegen_ssa::traits::*;
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;
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));
use rustc::middle::lang_items;
use rustc::ty::{self, Ty, TypeFoldable};
-use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
+use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Place, PlaceBase, Static, StaticKind};
use rustc::mir::interpret::InterpError;
use rustc_target::abi::call::{ArgType, FnType, PassMode, IgnoreMode};
ty::ParamEnv::reveal_all(),
&sig,
);
- let fn_ty = bx.new_vtable(sig, &[]);
+ let fn_ty = FnType::new_vtable(&bx, sig, &[]);
let vtable = args[1];
args = &args[..1];
(meth::DESTRUCTOR.get_fn(&mut bx, vtable, &fn_ty), fn_ty)
}
_ => {
(bx.get_fn(drop_fn),
- bx.fn_type_of_instance(&drop_fn))
+ FnType::of_instance(&bx, &drop_fn))
}
};
helper.do_call(self, &mut bx, fn_ty, drop_fn, args,
// Obtain the panic entry point.
let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
let instance = ty::Instance::mono(bx.tcx(), def_id);
- let fn_ty = bx.fn_type_of_instance(&instance);
+ let fn_ty = FnType::of_instance(&bx, &instance);
let llfn = bx.get_fn(instance);
// Codegen the actual panic invoke/call.
let fn_ty = match def {
Some(ty::InstanceDef::Virtual(..)) => {
- bx.new_vtable(sig, &extra_args)
+ FnType::new_vtable(&bx, sig, &extra_args)
}
Some(ty::InstanceDef::DropGlue(_, None)) => {
// Empty drop glue; a no-op.
helper.funclet_br(self, &mut bx, target);
return;
}
- _ => bx.new_fn_type(sig, &extra_args)
+ _ => FnType::new(&bx, sig, &extra_args)
};
// Emit a panic or a no-op for `panic_if_uninhabited`.
let def_id =
common::langcall(bx.tcx(), Some(span), "", lang_items::PanicFnLangItem);
let instance = ty::Instance::mono(bx.tcx(), def_id);
- let fn_ty = bx.fn_type_of_instance(&instance);
+ let fn_ty = FnType::of_instance(&bx, &instance);
let llfn = bx.get_fn(instance);
// Codegen the actual panic invoke/call.
use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts};
-use rustc::ty::layout::{TyLayout, HasTyCtxt};
+use rustc::ty::layout::{TyLayout, HasTyCtxt, FnTypeExt};
use rustc::mir::{self, Mir};
use rustc::session::config::DebugInfo;
use rustc_mir::monomorphize::Instance;
) {
assert!(!instance.substs.needs_infer());
- let fn_ty = cx.new_fn_type(sig, &[]);
+ let fn_ty = FnType::new(cx, sig, &[]);
debug!("fn_ty: {:?}", fn_ty);
let mut debug_context =
cx.create_function_debug_context(instance, sig, llfn, mir);
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;
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))
use super::BackendTypes;
-use rustc::ty::{FnSig, Instance, Ty};
+use rustc::ty::{Ty};
use rustc_target::abi::call::FnType;
-pub trait AbiMethods<'tcx> {
- fn new_fn_type(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
- fn new_vtable(&self, sig: FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> FnType<'tcx, Ty<'tcx>>;
- fn fn_type_of_instance(&self, instance: &Instance<'tcx>) -> FnType<'tcx, Ty<'tcx>>;
-}
-
pub trait AbiBuilderMethods<'tcx>: BackendTypes {
fn apply_attrs_callsite(&mut self, ty: &FnType<'tcx, Ty<'tcx>>, callsite: Self::Value);
fn get_param(&self, index: usize) -> Self::Value;
use crate::MemFlags;
use rustc::ty::Ty;
use rustc::ty::layout::{Align, Size, HasParamEnv};
+use rustc_target::spec::{HasTargetSpec};
use std::ops::Range;
use std::iter::TrustedLen;
+ AsmBuilderMethods<'tcx>
+ StaticBuilderMethods<'tcx>
+ HasParamEnv<'tcx>
+ + HasTargetSpec
{
fn new_block<'b>(cx: &'a Self::CodegenCx, llfn: Self::Value, name: &'b str) -> Self;
mod type_;
mod write;
-pub use self::abi::{AbiBuilderMethods, AbiMethods};
+pub use self::abi::{AbiBuilderMethods};
pub use self::asm::{AsmBuilderMethods, AsmMethods};
pub use self::backend::{Backend, BackendTypes, ExtraBackendMethods};
pub use self::builder::{BuilderMethods, OverflowOp};
ArgTypeMethods, BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods,
};
pub use self::write::{ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
-use rustc::ty::layout::{HasParamEnv};
+use rustc::ty::layout::{HasParamEnv, HasTyCtxt};
+use rustc_target::spec::{HasTargetSpec};
use std::fmt;
+ ConstMethods<'tcx>
+ StaticMethods
+ DebugInfoMethods<'tcx>
- + AbiMethods<'tcx>
+ DeclareMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>
+ HasParamEnv<'tcx>
+ + HasTyCtxt<'tcx>
+ + HasTargetSpec
{
}
+ ConstMethods<'tcx>
+ StaticMethods
+ DebugInfoMethods<'tcx>
- + AbiMethods<'tcx>
+ DeclareMethods<'tcx>
+ AsmMethods<'tcx>
+ PreDefineMethods<'tcx>
+ HasParamEnv<'tcx>
+ + HasTyCtxt<'tcx>
+ + HasTargetSpec
{
}
use rustc::ty::TyCtxt;
use rustc::hir::def_id::LOCAL_CRATE;
+use syntax::symbol::sym;
pub mod link;
pub mod codegen_backend;
/// 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");
}
}
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,
// 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);
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
}
#[cfg(any(target_os = "dragonfly",
- target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd"))]
mod os {
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;
// 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
}
src_name,
&mut rdr,
box out,
- annotation.pp_ann(),
- true)
+ annotation.pp_ann())
})
}
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)?;
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<Diagnostic>) {
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(|| {
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() {
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
// nodes.
pub struct FindAllAttrs<'a, 'tcx:'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- attr_names: Vec<&'static str>,
+ attr_names: Vec<Symbol>,
found_attrs: Vec<&'tcx Attribute>,
}
pub struct PluginInfo {
syntax_exts: Vec<NamedSyntaxExtension>,
- attributes: Vec<(String, AttributeType)>,
+ attributes: Vec<(Symbol, AttributeType)>,
}
pub fn register_plugins<'a>(
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<DefId> {
tcx.proc_macro_decls_static(LOCAL_CRATE)
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);
}
}
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};
let attr_types: Vec<config::CrateType> = 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 {
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;
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");
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;
}
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;
}
}
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);
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(
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 { .. } => {}
}
}
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]";
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");
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,
use syntax::ast;
use syntax::attr;
use syntax::errors::Applicability;
+use syntax::symbol::sym;
use syntax_pos::{BytePos, symbol::Ident, Span};
#[derive(PartialEq)]
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| {
}
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);
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(..) => {
/// 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,
}
}
-fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &ast::Lit) -> Option<String> {
+fn get_bin_hex_repr(cx: &LateContext<'_, '_>, lit: &hir::Lit) -> Option<String> {
let src = cx.sess().source_map().span_to_snippet(lit.span).ok()?;
let firstch = src.chars().next()?;
cx: &LateContext<'a, 'tcx>,
type_limits: &TypeLimits,
e: &'tcx hir::Expr,
- lit: &ast::Lit,
+ lit: &hir::Lit,
t: ast::IntTy,
v: u128,
) {
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 {
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) => {
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;
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);
}
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;
}
// 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 {
#[allow(non_camel_case_types)]
mod kw {
syn::custom_keyword!(Keywords);
- syn::custom_keyword!(Other);
+ syn::custom_keyword!(Symbols);
}
struct Keyword {
}
}
-struct Symbol(Ident);
+struct Symbol {
+ name: Ident,
+ value: Option<LitStr>,
+}
impl Parse for Symbol {
fn parse(input: ParseStream<'_>) -> Result<Self> {
- let ident: Ident = input.parse()?;
+ let name = input.parse()?;
+ let value = match input.parse::<Token![:]>() {
+ Ok(_) => Some(input.parse()?),
+ Err(_) => None,
+ };
input.parse::<Token![,]>()?;
- Ok(Symbol(ident))
+ Ok(Symbol {
+ name,
+ value,
+ })
}
}
braced!(content in input);
let keywords = content.parse()?;
- input.parse::<kw::Other>()?;
+ input.parse::<kw::Symbols>()?;
let content;
braced!(content in input);
let symbols = content.parse()?;
}
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
])
}
}
- })
+ });
+
+ // To see the generated code generated, uncomment this line, recompile, and
+ // run the resulting output through `rustfmt`.
+ //eprintln!("{}", tt);
+
+ tt
}
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};
/// 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 {
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 ||
let mut uses_std = false;
self.cstore.iter_crate_data(|_, data| {
- if data.name == "std" {
+ if data.name == sym::std {
uses_std = true;
}
});
// 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;
});
// 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;
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)
}
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
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;
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;
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};
// 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);
}
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};
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);
} 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,
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<String> {
let mut collector = Collector {
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());
}
}
// 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());
}
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};
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));
}
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<NativeLibrary> {
}
// 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,
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,
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
} 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 => {
}
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");
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");
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));
// 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;
}
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};
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(
);
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;
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<DiagnosticBuilder<'cx>> {
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"
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 => {
let mut err = tcx.cannot_return_reference_to_local(
return_span,
+ return_kind,
reference_desc,
&place_desc,
Origin::Mir,
err.span_label(borrow_span, note);
}
- err
+ Some(err)
}
fn report_escaping_closure_capture(
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={:?}",
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
}
}
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};
) {
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;
}
MatchedAdtAndSegment(Span),
AnonRegionFromUpvar(Span, String),
AnonRegionFromOutput(Span, String, String),
+ AnonRegionFromYieldTy(Span, String),
}
impl RegionName {
RegionNameSource::MatchedHirTy(..) |
RegionNameSource::MatchedAdtAndSegment(..) |
RegionNameSource::AnonRegionFromUpvar(..) |
- RegionNameSource::AnonRegionFromOutput(..) => false,
+ RegionNameSource::AnonRegionFromOutput(..) |
+ RegionNameSource::AnonRegionFromYieldTy(..) => false,
}
}
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 => {},
}
}
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);
"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;
}
})
}
+ 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<RegionName> {
+ // 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 {
| ExprKind::Pointer { .. }
| ExprKind::Repeat { .. }
| ExprKind::Borrow { .. }
- | ExprKind::If { .. }
| ExprKind::Match { .. }
| ExprKind::Loop { .. }
| ExprKind::Block { .. }
ExprKind::Literal { .. }
| ExprKind::Block { .. }
| ExprKind::Match { .. }
- | ExprKind::If { .. }
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
| ExprKind::Loop { .. }
| ExprKind::ValueTypeAscription { .. } => Some(Category::Place),
ExprKind::LogicalOp { .. }
- | ExprKind::If { .. }
| ExprKind::Match { .. }
| ExprKind::NeverToAny { .. }
| ExprKind::Use { .. }
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:
//
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;
fn propagate(&mut self) { self.flow_state.propagate(); }
}
-pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
+pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option<MetaItem> {
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() {
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,
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()),
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};
// 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();
cast: PointerCast,
source: ExprRef<'tcx>,
},
- If {
- condition: ExprRef<'tcx>,
- then: ExprRef<'tcx>,
- otherwise: Option<ExprRef<'tcx>>,
- },
Loop {
condition: Option<ExprRef<'tcx>>,
body: ExprRef<'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(),
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");
.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
}
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,
use std::fmt;
use syntax::ast;
use syntax::ptr::P;
+use syntax::symbol::sym;
use syntax_pos::Span;
#[derive(Clone, Debug)]
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, \
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);
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::{
// 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,
use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor, MutatingUseContext};
-use syntax::symbol::Symbol;
+use syntax::symbol::{Symbol, sym};
use std::ops::Bound;
fn builtin_derive_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option<DefId> {
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 {
use rustc::hir::def::DefKind;
use rustc::mir::{
- Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local,
+ AggregateKind, Constant, Location, Place, PlaceBase, Mir, Operand, Rvalue, Local,
NullOp, UnOp, StatementKind, Statement, LocalKind, Static, StaticKind,
TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, ProjectionElem,
SourceScope, SourceScopeLocalData, LocalDecl, Promoted,
};
-use rustc::mir::visit::{Visitor, PlaceContext, MutatingUseContext, NonMutatingUseContext};
+use rustc::mir::visit::{
+ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext,
+};
use rustc::mir::interpret::{InterpError, Scalar, GlobalId, EvalResult};
use rustc::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
-use syntax::source_map::DUMMY_SP;
+use syntax_pos::{Span, DUMMY_SP};
use rustc::ty::subst::InternalSubsts;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::ty::layout::{
HasTyCtxt, TargetDataLayout, HasDataLayout,
};
-use crate::interpret::{InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind};
+use crate::interpret::{self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind};
use crate::const_eval::{
CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
};
},
}
}
+
+ fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> {
+ Operand::Constant(Box::new(
+ Constant {
+ span,
+ ty,
+ user_ty: None,
+ literal: self.tcx.mk_const(ty::Const::from_scalar(
+ scalar,
+ ty,
+ ))
+ }
+ ))
+ }
+
+ fn replace_with_const(&self, rval: &mut Rvalue<'tcx>, value: Const<'tcx>, span: Span) {
+ self.ecx.validate_operand(
+ value,
+ vec![],
+ None,
+ true,
+ ).expect("value should already be a valid const");
+
+ if let interpret::Operand::Immediate(im) = *value {
+ match im {
+ interpret::Immediate::Scalar(ScalarMaybeUndef::Scalar(scalar)) => {
+ *rval = Rvalue::Use(self.operand_from_scalar(scalar, value.layout.ty, span));
+ },
+ Immediate::ScalarPair(
+ ScalarMaybeUndef::Scalar(one),
+ ScalarMaybeUndef::Scalar(two)
+ ) => {
+ let ty = &value.layout.ty.sty;
+ if let ty::Tuple(substs) = ty {
+ *rval = Rvalue::Aggregate(
+ Box::new(AggregateKind::Tuple),
+ vec![
+ self.operand_from_scalar(one, substs[0].expect_ty(), span),
+ self.operand_from_scalar(two, substs[1].expect_ty(), span),
+ ],
+ );
+ }
+ },
+ _ => { }
+ }
+ }
+ }
}
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
-impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
+impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
fn visit_constant(
&mut self,
- constant: &Constant<'tcx>,
+ constant: &mut Constant<'tcx>,
location: Location,
) {
trace!("visit_constant: {:?}", constant);
fn visit_statement(
&mut self,
- statement: &Statement<'tcx>,
+ statement: &mut Statement<'tcx>,
location: Location,
) {
trace!("visit_statement: {:?}", statement);
- if let StatementKind::Assign(ref place, ref rval) = statement.kind {
+ if let StatementKind::Assign(ref place, ref mut rval) = statement.kind {
let place_ty: Ty<'tcx> = place
.ty(&self.local_decls, self.tcx)
.ty;
trace!("storing {:?} to {:?}", value, local);
assert!(self.places[local].is_none());
self.places[local] = Some(value);
+
+ if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
+ self.replace_with_const(rval, value, statement.source_info.span);
+ }
}
}
}
fn visit_terminator(
&mut self,
- terminator: &Terminator<'tcx>,
+ terminator: &mut Terminator<'tcx>,
location: Location,
) {
self.super_terminator(terminator, location);
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;
!allowed ||
cx.tcx.get_attrs(def_id).iter().any(
- |attr| attr.check_name("thread_local"
- ))
+ |attr| attr.check_name(sym::thread_local)
+ )
}
}
}
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 \
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",
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",
);
// 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",
// 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),
// 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));
// 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),
// 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)));
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;
}
}
fn args_required_const(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<FxHashSet<usize>> {
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 {
use rustc_target::spec::abi::{Abi};
use syntax::ast;
+use syntax::symbol::sym;
use syntax_pos::Span;
use rustc::ty::{self, TyCtxt};
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 {
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");
}
}
fn cannot_return_reference_to_local(
self,
span: Span,
+ return_kind: &str,
reference_desc: &str,
path_desc: &str,
o: Origin,
self,
span,
E0515,
- "cannot return {REFERENCE} {LOCAL}{OGN}",
+ "cannot {RETURN} {REFERENCE} {LOCAL}{OGN}",
+ RETURN=return_kind,
REFERENCE=reference_desc,
LOCAL=path_desc,
OGN = o
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)
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 {
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
/// 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();
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 {
// }
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<D::Path>)> = (0..size).map(|i| {
(self.place.clone().elem(ProjectionElem::ConstantIndex{
offset: i,
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 {
};
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.
ptr_based)
});
- let succ = self.succ; // FIXME(#43234)
let loop_block = self.drop_loop(
- succ,
+ self.succ,
cur,
&length_or_end,
ety,
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(),
// 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
write!(w, r#"{:?}: {}; // {}<br align="left"/>"#,
Place::Base(PlaceBase::Local(local)), escape(&decl.ty), name)?;
} else {
- write!(w, r#"let mut {:?}: {};<br align="left"/>"#,
+ write!(w, r#"{:?}: {};<br align="left"/>"#,
Place::Base(PlaceBase::Local(local)), escape(&decl.ty))?;
}
}
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};
has_proc_macro_decls: bool,
has_global_allocator: bool,
- // Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
- // Nested `impl Trait` _is_ allowed in associated type position,
- // e.g `impl Iterator<Item=impl Debug>`
+ /// Used to ban nested `impl Trait`, e.g., `impl Into<impl Debug>`.
+ /// Nested `impl Trait` _is_ allowed in associated type position,
+ /// e.g `impl Iterator<Item=impl Debug>`
outer_impl_trait: Option<OuterImplTrait>,
- // Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
- // or `Foo::Bar<impl Trait>`
+ /// Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
+ /// or `Foo::Bar<impl Trait>`
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,
}
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;
}
}
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);
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 {
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);
}
}
// 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!(
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::*;
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;
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);
//! 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;
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));
}
}
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.
// 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;
}
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);
}
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![]);
}
}
}
}
- fn load_plugin(&mut self, span: Span, name: &str, args: Vec<ast::NestedMetaItem>) {
+ fn load_plugin(&mut self, span: Span, name: Symbol, args: Vec<ast::NestedMetaItem>) {
let registrar = self.reader.find_plugin_registrar(span, name);
if let Some((lib, disambiguator)) = registrar {
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;
pub llvm_passes: Vec<String>,
#[doc(hidden)]
- pub attributes: Vec<(String, AttributeType)>,
+ pub attributes: Vec<(Symbol, AttributeType)>,
}
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 {
/// 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));
}
}
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};
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";
}
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";
}
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};
}
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(
};
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);
}
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)
});
// 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() {
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.
// 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));
}
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");
/// 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 {
} else {
err.emit();
}
- } else if !attr.check_name("macro_use") {
+ } else if !attr.check_name(sym::macro_use) {
continue;
}
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};
fn resolve_str_path(
&mut self,
span: Span,
- crate_root: Option<&str>,
- components: &[&str],
+ crate_root: Option<Symbol>,
+ components: &[Symbol],
is_value: bool
) -> hir::Path {
let root = if crate_root.is_some() {
.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::<Vec<_>>();
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();
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());
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};
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 \
path.span,
&name,
&msg,
- "custom_attribute",
+ sym::custom_attribute,
);
}
}
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,
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);
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();
}
}
}
}
- 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.
.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| {
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)
});
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`");
}
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 {
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);
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};
// 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));
}
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;
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());
// (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 {
}
// 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.
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()));
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());
fn lower_attributes(attrs: Vec<Attribute>, scx: &SaveContext<'_, '_>) -> Vec<rls_data::Attribute> {
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
//
// Here we detect what version is being requested, defaulting to 10.7. ELF
// TLS is flagged as enabled if it looks to be supported.
- let version = macos_deployment_target().unwrap_or((10, 7));
+ let version = macos_deployment_target();
TargetOptions {
// macOS has -dead_strip, which doesn't rely on function_sections
}
}
-fn macos_deployment_target() -> Option<(u32, u32)> {
+fn macos_deployment_target() -> (u32, u32) {
let deployment_target = env::var("MACOSX_DEPLOYMENT_TARGET").ok();
let version = deployment_target.as_ref().and_then(|s| {
let mut i = s.splitn(2, '.');
a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok()
});
- version
+ version.unwrap_or((10, 7))
}
pub fn macos_llvm_target(arch: &str) -> String {
- let version = macos_deployment_target();
- let llvm_target = match version {
- Some((major, minor)) => {
- format!("{}-apple-macosx{}.{}.0", arch, major, minor)
- },
- None => format!("{}-apple-darwin", arch)
- };
-
- llvm_target
+ let (major, minor) = macos_deployment_target();
+ format!("{}-apple-macosx{}.{}.0", arch, major, minor)
}
+++ /dev/null
-use crate::spec::{TargetOptions, RelroLevel};
-use std::default::Default;
-
-pub fn opts() -> TargetOptions {
- TargetOptions {
- dynamic_linking: true,
- executables: true,
- target_family: Some("unix".to_string()),
- linker_is_gnu: true,
- has_rpath: true,
- position_independent_executables: true,
- relro_level: RelroLevel::Full,
-
- .. Default::default()
- }
-}
mod apple_base;
mod apple_ios_base;
mod arm_base;
-mod bitrig_base;
mod cloudabi_base;
mod dragonfly_base;
mod freebsd_base;
("i686-unknown-dragonfly", i686_unknown_dragonfly),
("x86_64-unknown-dragonfly", x86_64_unknown_dragonfly),
- ("x86_64-unknown-bitrig", x86_64_unknown_bitrig),
-
("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
("i686-unknown-openbsd", i686_unknown_openbsd),
("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
("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),
+++ /dev/null
-//! The `wasm32-unknown-wasi` target is a new and still (as of March 2019)
-//! experimental target. The definition in this file is likely to be tweaked
-//! over time and shouldn't be relied on too much.
-//!
-//! The `wasi` target is a proposal to define a standardized set of syscalls
-//! that WebAssembly files can interoperate with. This set of syscalls is
-//! intended to empower WebAssembly binaries with native capabilities such as
-//! filesystem access, network access, etc.
-//!
-//! You can see more about the proposal at https://wasi.dev
-//!
-//! The Rust target definition here is interesting in a few ways. We want to
-//! 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.
-//!
-//! * 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`.
-//!
-//! 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
-//! that (ab)uses the `crt-static` target feature to indicate which one you're
-//! in.
-//!
-//! ## No interop with C required
-//!
-//! By default the `crt-static` target feature is enabled, and when enabled
-//! this means that the the bundled version of `libc.a` found in `liblibc.rlib`
-//! is used. This isn't intended really for interoperation with a C because it
-//! may be the case that Rust's bundled C library is incompatible with a
-//! foreign-compiled C library. In this use case, though, we use `rust-lld` and
-//! some copied crt startup object files to ensure that you can download the
-//! wasi target for Rust and you're off to the races, no further configuration
-//! 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).
-//!
-//! ## Interop with C required
-//!
-//! For the second goal we repurpose the `target-feature` flag, meaning that
-//! you'll need to do a few things to have C/Rust code interoperate.
-//!
-//! 1. All Rust code needs to be compiled with `-C target-feature=-crt-static`,
-//! indicating that the bundled C standard library in the Rust sysroot will
-//! not be used.
-//!
-//! 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.
-//!
-//! 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.
-//!
-//! ## Remember, this is all in flux
-//!
-//! The wasi target is **very** new in its specification. It's likely going to
-//! be a long effort to get it standardized and stable. We'll be following it as
-//! best we can with this target. Don't start relying on too much here unless
-//! you know what you're getting in to!
-
-use super::wasm32_base;
-use super::{LinkerFlavor, LldFlavor, Target};
-
-pub fn target() -> Result<Target, String> {
- let mut options = wasm32_base::options();
-
- options
- .pre_link_args
- .entry(LinkerFlavor::Gcc)
- .or_insert(Vec::new())
- .push("--target=wasm32-unknown-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.
- options.pre_link_objects_exe_crt.push("crt1.o".to_string());
-
- // Right now this is a bit of a workaround but we're currently saying that
- // the target by default has a static crt which we're taking as a signal
- // for "use the bundled crt". If that's turned off then the system's crt
- // will be used, but this means that default usage of this target doesn't
- // need an external compiler but it's still interoperable with an external
- // compiler if configured correctly.
- options.crt_static_default = true;
- options.crt_static_respected = true;
-
- Ok(Target {
- llvm_target: "wasm32-unknown-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(),
- 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),
- options,
- })
-}
--- /dev/null
+//! 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.
+//!
+//! The `wasi` target is a proposal to define a standardized set of syscalls
+//! that WebAssembly files can interoperate with. This set of syscalls is
+//! intended to empower WebAssembly binaries with native capabilities such as
+//! filesystem access, network access, etc.
+//!
+//! You can see more about the proposal at https://wasi.dev
+//!
+//! The Rust target definition here is interesting in a few ways. We want to
+//! 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-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-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
+//! that (ab)uses the `crt-static` target feature to indicate which one you're
+//! in.
+//!
+//! ## No interop with C required
+//!
+//! By default the `crt-static` target feature is enabled, and when enabled
+//! this means that the the bundled version of `libc.a` found in `liblibc.rlib`
+//! is used. This isn't intended really for interoperation with a C because it
+//! may be the case that Rust's bundled C library is incompatible with a
+//! foreign-compiled C library. In this use case, though, we use `rust-lld` and
+//! some copied crt startup object files to ensure that you can download the
+//! wasi target for Rust and you're off to the races, no further configuration
+//! necessary.
+//!
+//! All in all, by default, no external dependencies are required. You can
+//! 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
+//!
+//! For the second goal we repurpose the `target-feature` flag, meaning that
+//! you'll need to do a few things to have C/Rust code interoperate.
+//!
+//! 1. All Rust code needs to be compiled with `-C target-feature=-crt-static`,
+//! indicating that the bundled C standard library in the Rust sysroot will
+//! not be used.
+//!
+//! 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-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_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
+//!
+//! The wasi target is **very** new in its specification. It's likely going to
+//! be a long effort to get it standardized and stable. We'll be following it as
+//! best we can with this target. Don't start relying on too much here unless
+//! you know what you're getting in to!
+
+use super::wasm32_base;
+use super::{LinkerFlavor, LldFlavor, Target};
+
+pub fn target() -> Result<Target, String> {
+ let mut options = wasm32_base::options();
+
+ options
+ .pre_link_args
+ .entry(LinkerFlavor::Gcc)
+ .or_insert(Vec::new())
+ .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.
+ options.pre_link_objects_exe_crt.push("crt1.o".to_string());
+
+ // Right now this is a bit of a workaround but we're currently saying that
+ // the target by default has a static crt which we're taking as a signal
+ // for "use the bundled crt". If that's turned off then the system's crt
+ // will be used, but this means that default usage of this target doesn't
+ // need an external compiler but it's still interoperable with an external
+ // compiler if configured correctly.
+ options.crt_static_default = true;
+ options.crt_static_respected = true;
+
+ Ok(Target {
+ 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: 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),
+ options,
+ })
+}
+++ /dev/null
-use crate::spec::{LinkerFlavor, Target, TargetResult};
-
-pub fn target() -> TargetResult {
- let mut base = super::bitrig_base::opts();
- base.cpu = "x86-64".to_string();
- base.max_atomic_width = Some(64);
- base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
- base.stack_probes = true;
-
- Ok(Target {
- llvm_target: "x86_64-unknown-bitrig".to_string(),
- target_endian: "little".to_string(),
- target_pointer_width: "64".to_string(),
- target_c_int_width: "32".to_string(),
- data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
- arch: "x86_64".to_string(),
- target_os: "bitrig".to_string(),
- target_env: String::new(),
- target_vendor: "unknown".to_string(),
- linker_flavor: LinkerFlavor::Gcc,
- options: base,
- })
-}
use rustc::ty::{self, List, TyCtxt};
use rustc::ty::subst::{Subst, InternalSubsts};
use syntax::ast;
+use syntax::symbol::sym;
use std::iter;
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));
}
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;
} 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);
}
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 {
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;
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;
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
pat: &'gcx hir::Pat,
mut expected: Ty<'tcx>,
mut def_bm: ty::BindingMode,
- match_discrim_span: Option<Span>,
+ discrim_span: Option<Span>,
) {
let tcx = self.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, _) => {
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) => {
// `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);
}
}
// 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
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();
// 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 {
elem,
&element_tys[i].expect_ty(),
def_bm,
- match_discrim_span,
+ discrim_span,
);
}
pat_ty
// 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
}
}
}
};
- 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
}
}
};
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
}
) -> 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.
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.
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();
}
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),
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);
}
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,
etc: bool,
expected: Ty<'tcx>,
def_bm: ty::BindingMode,
- match_discrim_span: Option<Span>,
+ discrim_span: Option<Span>,
) -> Ty<'tcx>
{
// Resolve the path and check the definition for errors.
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)
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> {
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);
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);
}
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;
//
// 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
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)
});
}
}
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 {
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(
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;`
// ^^^^
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,
+ );
+ }
}
}
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};
// 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
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")
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");
/// 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);
}
}
// AST fragment checking
fn check_lit(&self,
- lit: &ast::Lit,
+ lit: &hir::Lit,
expected: Expectation<'tcx>)
-> Ty<'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
}
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,
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")
}
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;
}
}
// ... 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);
}
}
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
match expression.node {
ExprKind::Call(..) |
ExprKind::MethodCall(..) |
- ExprKind::If(..) |
ExprKind::While(..) |
ExprKind::Loop(..) |
ExprKind::Match(..) |
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,
+ ));
}
}
}
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
}
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;
// 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!(
use rustc::util::nodemap::DefIdSet;
use rustc_data_structures::sync::Lrc;
use std::mem;
+use syntax::symbol::sym;
use syntax_pos::Span;
///////////////////////////////////////////////////////////////////////////
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 {
let hir_id = self.tcx().hir().as_local_hir_id(def_id).unwrap();
let instantiated_ty = self.resolve(&opaque_defn.concrete_ty, &hir_id);
+ debug_assert!(!instantiated_ty.has_escaping_bound_vars());
+
let generics = self.tcx().generics_of(def_id);
let definition_ty = if generics.parent.is_some() {
},
lt_op: |region| {
match region {
- // ignore static regions
- ty::ReStatic => region,
+ // Skip static and bound regions: they don't
+ // require substitution.
+ ty::ReStatic | ty::ReLateBound(..) => region,
_ => {
trace!("checking {:?}", region);
for (subst, p) in opaque_defn.substs.iter().zip(&generics.params) {
}
}
- 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",
+ );
}
}
}
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};
_ => 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,
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)
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
}
}
}
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
}
}
}
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
}
}
}
tcx: TyCtxt<'_, '_, '_>,
id: DefId,
attr: &ast::Attribute,
- whitelist: &FxHashMap<String, Option<String>>,
+ whitelist: &FxHashMap<String, Option<Symbol>>,
target_features: &mut Vec<Symbol>,
) {
let list = match attr.meta_item_list() {
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);
};
// 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),
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 {
"`#[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,
}
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";
&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!(
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) {
"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!(
});
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);
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");
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;
.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<String> = predicates
.iter()
.map(|out_pred| match out_pred {
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()
// 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,
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 });
// 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,
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;
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,
}
}
("debug_assertions", None) => "debug-assertions enabled",
("target_os", Some(os)) => match &*os.as_str() {
"android" => "Android",
- "bitrig" => "Bitrig",
"dragonfly" => "DragonFly BSD",
"emscripten" => "Emscripten",
"freebsd" => "FreeBSD",
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 {
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]);
#[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]);
use syntax::ast;
use syntax::ext::base::{MacroKind, SyntaxExtension};
+use syntax::symbol::sym;
use syntax_pos::Span;
use rustc::hir;
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,
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};
// `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);
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;
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() {
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.
pub struct ListAttributesIter<'a> {
attrs: slice::Iter<'a, ast::Attribute>,
current_list: vec::IntoIter<ast::NestedMetaItem>,
- name: &'a str
+ name: Symbol,
}
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(),
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<I: IntoIterator<Item=ast::NestedMetaItem>> 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))
}
}
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] {
{
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
let mut contents: Option<String> = 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());
}
})
}
- 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)) {
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 = "..."]
// treat #[target_feature(enable = "feat")] attributes as if they were
// #[doc(cfg(target_feature = "feat"))] attributes as well
- for attr in attrs.lists("target_feature") {
- if attr.check_name("enable") {
+ for attr in attrs.lists(sym::target_feature) {
+ if attr.check_name(sym::enable) {
if let Some(feat) = attr.value_str() {
let meta = attr::mk_name_value_item_str(Ident::from_str("target_feature"),
dummy_spanned(feat));
}
let 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);
}
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)
}
}
impl Clean<Item> 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,
fn clean(&self, cx: &DocContext<'_>) -> Vec<Item> {
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,
}
});
// #[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 {
// Start of code copied from rust-clippy
-pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId> {
+pub fn path_to_def_local(tcx: TyCtxt<'_, '_, '_>, path: &[Symbol]) -> Option<DefId> {
let krate = tcx.hir().krate();
let mut items = krate.module.item_ids.clone();
let mut path_it = path.iter().peekable();
}
}
-pub fn path_to_def(tcx: TyCtxt<'_, '_, '_>, path: &[&str]) -> Option<DefId> {
+pub fn path_to_def(tcx: TyCtxt<'_, '_, '_>, path: &[Symbol]) -> Option<DefId> {
let crates = tcx.crates();
let krate = crates
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;
};
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();
// 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");
}
}
- 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;
}
// Number literals.
token::Integer(..) | token::Float(..) => Class::Number,
+
+ token::Bool(..) => panic!("literal token contains `Lit::Bool`"),
}
}
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;
// 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;
}
_ => {}
// 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();
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())
}
}
-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()) {
use syntax::attr;
use syntax_pos::FileName;
+use syntax::symbol::sym;
use std::collections::BTreeMap;
use std::ops;
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
// 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(())
};
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",
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();
fn fold_item(&mut self, i: Item) -> Option<Item> {
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),
use rustc::util::nodemap::DefIdSet;
use std::mem;
+use syntax::symbol::sym;
use crate::clean::{self, AttributesExt, NestedAttributesExt};
use crate::clean::Item;
impl<'a> DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
- 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 {
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;
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;
};
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));
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;
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
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")
};
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;
}
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 {
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
// (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) |
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,
}
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;
// Updates node level and returns the updated level
fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
- 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
} else if target.contains("netbsd") {
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=rt");
- } else if target.contains("dragonfly") || target.contains("bitrig") ||
- target.contains("openbsd") {
+ } else if target.contains("dragonfly") || target.contains("openbsd") {
println!("cargo:rustc-link-lib=pthread");
} else if target.contains("solaris") {
println!("cargo:rustc-link-lib=socket");
self.inner.next().map(|s| s.into_string().unwrap())
}
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+ #[inline]
+ fn last(mut self) -> Option<String> {
+ self.next_back()
+ }
}
#[stable(feature = "env", since = "1.0.0")]
type Item = OsString;
fn next(&mut self) -> Option<OsString> { self.inner.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+ #[inline]
+ fn last(mut self) -> Option<OsString> { self.next_back() }
}
#[stable(feature = "env", since = "1.0.0")]
/// - ios
/// - freebsd
/// - dragonfly
- /// - bitrig
/// - netbsd
/// - openbsd
/// - solaris
fn source(&self) -> Option<&(dyn Error + 'static)> { None }
/// Gets the `TypeId` of `self`
- #[stable(feature = "error_type_id", since = "1.34.0")]
+ #[doc(hidden)]
+ #[unstable(feature = "error_type_id",
+ reason = "this is memory unsafe to override in user code",
+ issue = "60784")]
fn type_id(&self) -> TypeId where Self: 'static {
TypeId::of::<Self>()
}
/// `CString` implements a [`as_ptr`] method through the [`Deref`]
/// trait. This method will give you a `*const c_char` which you can
/// feed directly to extern functions that expect a nul-terminated
-/// string, like C's `strdup()`.
+/// string, like C's `strdup()`. Notice that [`as_ptr`] returns a
+/// read-only pointer; if the C code writes to it, that causes
+/// undefined behavior.
///
/// # Extracting a slice of the whole C string
///
///
/// Once you have the kind of slice you need (with or without a nul
/// terminator), you can call the slice's own
-/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to
+/// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to
/// extern functions. See the documentation for that function for a
/// discussion on ensuring the lifetime of the raw pointer.
///
///
/// **WARNING**
///
+ /// The returned pointer is read-only; writing to it (including passing it
+ /// to C code that writes to it) causes undefined behavior.
+ ///
/// It is your responsibility to make sure that the underlying memory is not
/// freed too early. For example, the following code will cause undefined
/// behavior when `ptr` is used inside the `unsafe` block:
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default)]
pub struct Cursor<T> {
inner: T,
pos: u64,
#![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
};
}
-/// 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
// s has been moved into the tsa call
}
- // FIXME: figure out why this fails on openbsd and bitrig and fix it
+ // FIXME: figure out why this fails on openbsd and fix it
#[test]
- #[cfg(not(any(windows, target_os = "openbsd", target_os = "bitrig")))]
+ #[cfg(not(any(windows, target_os = "openbsd")))]
fn to_socket_addr_str_bad() {
assert!(tsa("1200::AB00:1234::2552:7777:1313:34300").is_err());
}
assert_eq!(format!("{:?}", stream), compare);
}
- // FIXME: re-enabled bitrig/openbsd tests once their socket timeout code
+ // FIXME: re-enabled openbsd tests once their socket timeout code
// no longer has rounding errors.
- #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+ #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)]
#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31
#[test]
fn timeouts() {
assert_eq!(format!("{:?}", udpsock), compare);
}
- // FIXME: re-enabled bitrig/openbsd/netbsd tests once their socket timeout code
+ // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code
// no longer has rounding errors.
- #[cfg_attr(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"), ignore)]
+ #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd"), ignore)]
#[test]
fn timeouts() {
let addr = next_test_ip4();
+++ /dev/null
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use crate::fs::Metadata;
-use crate::sys_common::AsInner;
-
-#[allow(deprecated)]
-use crate::os::bitrig::raw;
-
-/// OS-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
- /// Gain a reference to the underlying `stat` structure which contains
- /// the raw information returned by the OS.
- ///
- /// The contents of the returned `stat` are **not** consistent across
- /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
- /// cross-Unix abstractions contained within the raw stat.
- #[stable(feature = "metadata_ext", since = "1.1.0")]
- #[rustc_deprecated(since = "1.8.0",
- reason = "deprecated in favor of the accessor \
- methods of this trait")]
- #[allow(deprecated)]
- fn as_raw_stat(&self) -> &raw::stat;
-
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_dev(&self) -> u64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_ino(&self) -> u64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_mode(&self) -> u32;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_nlink(&self) -> u64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_uid(&self) -> u32;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_gid(&self) -> u32;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_rdev(&self) -> u64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_size(&self) -> u64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_atime(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_atime_nsec(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_mtime(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_mtime_nsec(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_ctime(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_ctime_nsec(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_birthtime(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_birthtime_nsec(&self) -> i64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_blksize(&self) -> u64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_blocks(&self) -> u64;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_flags(&self) -> u32;
- #[stable(feature = "metadata_ext2", since = "1.8.0")]
- fn st_gen(&self) -> u32;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
- #[allow(deprecated)]
- fn as_raw_stat(&self) -> &raw::stat {
- unsafe {
- &*(self.as_inner().as_inner() as *const libc::stat
- as *const raw::stat)
- }
- }
- fn st_dev(&self) -> u64 {
- self.as_inner().as_inner().st_dev as u64
- }
- fn st_ino(&self) -> u64 {
- self.as_inner().as_inner().st_ino as u64
- }
- fn st_mode(&self) -> u32 {
- self.as_inner().as_inner().st_mode as u32
- }
- fn st_nlink(&self) -> u64 {
- self.as_inner().as_inner().st_nlink as u64
- }
- fn st_uid(&self) -> u32 {
- self.as_inner().as_inner().st_uid as u32
- }
- fn st_gid(&self) -> u32 {
- self.as_inner().as_inner().st_gid as u32
- }
- fn st_rdev(&self) -> u64 {
- self.as_inner().as_inner().st_rdev as u64
- }
- fn st_size(&self) -> u64 {
- self.as_inner().as_inner().st_size as u64
- }
- fn st_atime(&self) -> i64 {
- self.as_inner().as_inner().st_atime as i64
- }
- fn st_atime_nsec(&self) -> i64 {
- self.as_inner().as_inner().st_atime_nsec as i64
- }
- fn st_mtime(&self) -> i64 {
- self.as_inner().as_inner().st_mtime as i64
- }
- fn st_mtime_nsec(&self) -> i64 {
- self.as_inner().as_inner().st_mtime_nsec as i64
- }
- fn st_ctime(&self) -> i64 {
- self.as_inner().as_inner().st_ctime as i64
- }
- fn st_ctime_nsec(&self) -> i64 {
- self.as_inner().as_inner().st_ctime_nsec as i64
- }
- fn st_birthtime(&self) -> i64 {
- self.as_inner().as_inner().st_birthtime as i64
- }
- fn st_birthtime_nsec(&self) -> i64 {
- self.as_inner().as_inner().st_birthtime_nsec as i64
- }
- fn st_blksize(&self) -> u64 {
- self.as_inner().as_inner().st_blksize as u64
- }
- fn st_blocks(&self) -> u64 {
- self.as_inner().as_inner().st_blocks as u64
- }
- fn st_gen(&self) -> u32 {
- self.as_inner().as_inner().st_gen as u32
- }
- fn st_flags(&self) -> u32 {
- self.as_inner().as_inner().st_flags as u32
- }
-}
+++ /dev/null
-//! Bitrig-specific definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-pub mod raw;
-pub mod fs;
+++ /dev/null
-//! Bitrig-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(since = "1.8.0",
- reason = "these type aliases are no longer supported by \
- the standard library, the `libc` crate on \
- crates.io should be used instead for the correct \
- definitions")]
-#![allow(deprecated)]
-
-use crate::os::raw::c_long;
-use crate::os::unix::raw::{uid_t, gid_t};
-
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub type pthread_t = usize;
-
-#[repr(C)]
-#[derive(Clone)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub struct stat {
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_mode: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_dev: i32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_ino: u64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_nlink: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_uid: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_gid: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_rdev: i32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_atime: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_atime_nsec: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_mtime: u64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_mtime_nsec: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_ctime: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_ctime_nsec: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_size: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_blocks: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_blksize: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_flags: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_gen: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_birthtime: i64,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_birthtime_nsec: i64,
-}
}
#[cfg(target_os = "android")] pub mod android;
-#[cfg(target_os = "bitrig")] pub mod bitrig;
#[cfg(target_os = "dragonfly")] pub mod dragonfly;
#[cfg(target_os = "freebsd")] pub mod freebsd;
#[cfg(target_os = "haiku")] pub mod haiku;
fn next(&mut self) -> Option<&'a OsStr> {
self.inner.next().map(Component::as_os_str)
}
+
+ #[inline]
+ fn last(mut self) -> Option<&'a OsStr> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
None
}
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
type Item = OsString;
fn next(&mut self) -> Option<OsString> { self.iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+ #[inline]
+ fn last(mut self) -> Option<OsString> { self.next_back() }
}
impl ExactSizeIterator for Args {
target_os = "android",
target_os = "freebsd",
target_os = "dragonfly",
- target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd",
target_os = "solaris",
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "bitrig")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "bitrig";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
#[cfg(target_os = "netbsd")]
pub mod os {
pub const FAMILY: &str = "unix";
#[cfg(any(target_os = "linux", target_os = "android",
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
- target_os = "haiku", target_os = "bitrig"))]
+ target_os = "haiku"))]
use libc::MSG_NOSIGNAL;
#[cfg(not(any(target_os = "linux", target_os = "android",
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
- target_os = "haiku", target_os = "bitrig")))]
+ target_os = "haiku")))]
const MSG_NOSIGNAL: libc::c_int = 0x0;
fn sun_path_offset() -> usize {
}))
}
- #[cfg(any(target_os = "bitrig",
- target_os = "freebsd",
+ #[cfg(any(target_os = "freebsd",
target_os = "openbsd",
target_os = "macos",
target_os = "ios"))]
}))
}
- #[cfg(not(any(target_os = "bitrig",
- target_os = "freebsd",
+ #[cfg(not(any(target_os = "freebsd",
target_os = "openbsd",
target_os = "macos",
target_os = "ios")))]
#[cfg(any(target_os = "freebsd",
target_os = "openbsd",
- target_os = "bitrig",
target_os = "netbsd",
target_os = "dragonfly"))]
pub fn ino(&self) -> u64 {
target_os = "netbsd",
target_os = "openbsd",
target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig"))]
+ target_os = "dragonfly"))]
fn name_bytes(&self) -> &[u8] {
use crate::slice;
unsafe {
#[cfg(any(rustdoc, target_os = "linux"))] pub use crate::os::linux as platform;
#[cfg(all(not(rustdoc), target_os = "android"))] pub use crate::os::android as platform;
-#[cfg(all(not(rustdoc), target_os = "bitrig"))] pub use crate::os::bitrig as platform;
#[cfg(all(not(rustdoc), target_os = "dragonfly"))] pub use crate::os::dragonfly as platform;
#[cfg(all(not(rustdoc), target_os = "freebsd"))] pub use crate::os::freebsd as platform;
#[cfg(all(not(rustdoc), target_os = "haiku"))] pub use crate::os::haiku as platform;
target_os = "fuchsia",
target_os = "l4re"),
link_name = "__errno_location")]
- #[cfg_attr(any(target_os = "bitrig",
- target_os = "netbsd",
+ #[cfg_attr(any(target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
target_os = "hermit",
sysctl().or_else(|_| procfs())
}
-#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
+#[cfg(target_os = "openbsd")]
pub fn current_exe() -> io::Result<PathBuf> {
unsafe {
let mut mib = [libc::CTL_KERN,
#[cfg(all(unix,
not(target_os = "ios"),
- not(all(target_os = "macos", miri)),
not(target_os = "openbsd"),
not(target_os = "freebsd"),
not(target_os = "fuchsia")))]
// once per thread in `hashmap_random_keys`. Therefore `SecRandomCopyBytes` is
// only used on iOS where direct access to `/dev/urandom` is blocked by the
// sandbox.
-// HACK: However, we do use this when running in Miri on macOS; intercepting this is much
-// easier than intercepting accesses to /dev/urandom.
-#[cfg(any(target_os = "ios", all(target_os = "macos", miri)))]
+#[cfg(target_os = "ios")]
mod imp {
use crate::io;
use crate::ptr;
#[cfg(any(target_os = "linux",
target_os = "macos",
- target_os = "bitrig",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "solaris",
#[cfg(any(target_os = "linux",
target_os = "macos",
- target_os = "bitrig",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
#[cfg(not(any(target_os = "linux",
target_os = "macos",
- target_os = "bitrig",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "solaris",
#[cfg(any(target_os = "freebsd",
target_os = "dragonfly",
- target_os = "bitrig",
target_os = "openbsd"))]
pub fn set_name(name: &CStr) {
unsafe {
#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))),
not(target_os = "freebsd"),
not(target_os = "macos"),
- not(target_os = "bitrig"),
not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
not(target_os = "openbsd"),
not(target_os = "solaris")))]
#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
target_os = "freebsd",
target_os = "macos",
- target_os = "bitrig",
all(target_os = "netbsd", not(target_vendor = "rumprun")),
target_os = "openbsd",
target_os = "solaris"))]
Some(stackaddr as *mut libc::c_void)
}
- #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+ #[cfg(target_os = "openbsd")]
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
let mut current_stack: libc::stack_t = crate::mem::zeroed();
assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
&mut current_stack), 0);
- let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE;
let stackaddr = if libc::pthread_main_np() == 1 {
// main thread
- current_stack.ss_sp as usize - current_stack.ss_size + extra
+ current_stack.ss_sp as usize - current_stack.ss_size + PAGE_SIZE
} else {
// new thread
current_stack.ss_sp as usize - current_stack.ss_size
}
#[cfg(any(target_os = "macos",
- target_os = "bitrig",
target_os = "openbsd",
target_os = "solaris"))]
pub unsafe fn current() -> Option<Guard> {
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
+ #[inline]
+ fn last(mut self) -> Option<OsString> {
+ self.next_back()
+ }
}
impl ExactSizeIterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> { self.parsed_args_list.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.parsed_args_list.size_hint() }
+ #[inline]
+ fn last(mut self) -> Option<OsString> { self.next_back() }
}
impl DoubleEndedIterator for Args {
#[cfg(any(target_os = "linux", target_os = "android",
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
- target_os = "haiku", target_os = "bitrig"))]
+ target_os = "haiku"))]
use libc::MSG_NOSIGNAL;
#[cfg(not(any(target_os = "linux", target_os = "android",
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
- target_os = "haiku", target_os = "bitrig")))]
+ target_os = "haiku")))]
const MSG_NOSIGNAL: c_int = 0x0;
////////////////////////////////////////////////////////////////////////////////
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};
}
}
-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))
Raw(u16),
}
-/// A literal.
-pub type Lit = Spanned<LitKind>;
+/// 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<Symbol>,
+ /// 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 {
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};
/// Determine what `#[unwind]` attribute is present in `attrs`, if any.
pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
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);
}
}
/// 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)
'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
}
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
)+
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) ),+ ];
}
}
- 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");
}
}
}
- "rustc_const_unstable" => {
+ sym::rustc_const_unstable => {
if rustc_const_unstable.is_some() {
span_err!(diagnostic, item_sp, E0553,
"multiple rustc_const_unstable attributes");
continue
}
}
- "unstable" => {
+ sym::unstable => {
if stab.is_some() {
handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
break
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,
}
}
}
- "stable" => {
+ sym::stable => {
if stab.is_some() {
handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
break
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,
}
pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
- 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
// 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;
let diagnostic = &sess.span_diagnostic;
'outer: for attr in attrs_iter {
- if !attr.check_name("deprecated") {
+ if !attr.check_name(sym::deprecated) {
continue;
}
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,
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 {
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),
};
};
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)),
}
} 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,
acc
}
-fn int_type_of_word(s: &str) -> Option<IntType> {
+fn int_type_of_word(s: Symbol) -> Option<IntType> {
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
}
}
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;
}
/// Returns `true` if this list item is a MetaItem with a name of `name`.
- pub fn check_name<T>(&self, name: T) -> bool
- where
- Path: PartialEq<T>,
- {
+ pub fn check_name(&self, name: Symbol) -> bool {
self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
}
pub fn ident(&self) -> Option<Ident> {
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
/// attribute is marked as used.
///
/// To check the attribute name without marking it used, use the `path` field directly.
- pub fn check_name<T>(&self, name: T) -> bool
- where
- Path: PartialEq<T>,
- {
+ pub fn check_name(&self, name: Symbol) -> bool {
let matches = self.path == name;
if matches {
mark_used(self);
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<Symbol> {
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")]
}
}
- pub fn check_name<T>(&self, name: T) -> bool
- where
- Path: PartialEq<T>,
- {
+ pub fn check_name(&self, name: Symbol) -> bool {
self.path == name
}
/* Constructors */
pub fn mk_name_value_item_str(ident: Ident, value: Spanned<Symbol>) -> 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<NestedMetaItem>) -> MetaItem {
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,
}
}
-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<Item = &'a Attribute> {
attrs.iter().filter(move |attr| attr.check_name(name))
}
-pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<Symbol> {
+pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
attrs.iter()
.find(|at| at.check_name(name))
.and_then(|at| at.value_str())
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
};
where I: Iterator<Item = TokenTree>,
{
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));
}
}
}
}
-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::<char>::into).collect::<String>();
- Token::Literal(token::Lit::ByteStr(Symbol::intern(&string)), None)
- }
- LitKind::Byte(byte) => {
- let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
- Token::Literal(token::Lit::Byte(Symbol::intern(&string)), None)
- }
- LitKind::Char(ch) => {
- let string: String = ch.escape_default().map(Into::<char>::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<LitKind> {
- 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<F: FnOnce(&mut Vec<ast::Attribute>)>(&mut self, f: F);
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;
/// 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<ast::Attribute> {
- if !attr.check_name("cfg_attr") {
+ if !attr.check_name(sym::cfg_attr) {
return vec![attr];
}
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);
/// 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;
}
fn is_cfg(attr: &ast::Attribute) -> bool {
- attr.check_name("cfg")
+ attr.check_name(sym::cfg)
}
use crate::attr;
use crate::ast::{Item, ItemKind};
+use crate::symbol::sym;
pub enum EntryPointType {
None,
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
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};
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;
}
self.expr_struct(span, self.path_ident(span, id), fields)
}
- fn expr_lit(&self, sp: Span, lit: ast::LitKind) -> P<ast::Expr> {
- self.expr(sp, ast::ExprKind::Lit(respan(sp, lit)))
+ fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P<ast::Expr> {
+ 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<ast::Expr> {
self.expr_lit(span, ast::LitKind::Int(i as u128,
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,
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;
pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>) -> Vec<ast::Path> {
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() {
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;
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,
}
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();
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");
}
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,
}
}
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,
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",
// 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();
}
}
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),
-> Option<ast::Attribute> {
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)
.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");
}
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();
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());
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;
}
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;
/* __rust_unstable_column!(): expands to the current column number */
pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
-> Box<dyn base::MacResult+'static> {
- 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");
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
{
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;
let rhs_spans = rhs.iter().map(|t| t.span()).collect::<Vec<_>>();
// 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.
});
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()
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);
}
}
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,
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,
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),
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),
}
},
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),
}
},
ZeroOrMore,
/// Kleene plus (`+`) for one or more repetitions
OneOrMore,
+ /// Kleene optional (`?`) for zero or one reptitions
ZeroOrOne,
}
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};
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<quoted::Delimited>,
- idx: usize,
- span: DelimSpan,
- },
- Sequence {
- forest: Lrc<quoted::SequenceRepetition>,
- idx: usize,
- sep: Option<Token>,
- },
+ Delimited { forest: Lrc<quoted::Delimited>, idx: usize, span: DelimSpan },
+ Sequence { forest: Lrc<quoted::SequenceRepetition>, idx: usize, sep: Option<Token> },
}
impl Frame {
+ /// Construct a new frame around the delimited set of tokens.
fn new(tts: Vec<quoted::TokenTree>) -> Frame {
let forest = Lrc::new(quoted::Delimited { delim: token::NoDelim, tts: tts });
Frame::Delimited { forest: forest, idx: 0, span: DelimSpan::dummy() }
}
}
-/// 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<FxHashMap<Ident, Rc<NamedMatch>>>,
- src: Vec<quoted::TokenTree>)
- -> 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<Ident, Rc<NamedMatch>>,
+ src: Vec<quoted::TokenTree>,
+) -> 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<TreeAndJoint> = 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(),
}
}
}
- // 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 {
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);
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<Ident, Rc<NamedMatch>>,
- repeats: &[(usize, usize)])
- -> Option<Rc<NamedMatch>> {
+/// 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<Ident, Rc<NamedMatch>>,
+ repeats: &[(usize, usize)],
+) -> Option<Rc<NamedMatch>> {
interpolations.get(&ident).map(|matched| {
let mut matched = matched.clone();
for &(idx, _) in repeats {
})
}
+/// 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,
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)
}
},
}
}
-fn lockstep_iter_size(tree: "ed::TokenTree,
- interpolations: &FxHashMap<Ident, Rc<NamedMatch>>,
- 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<Ident, Rc<NamedMatch>>,
+ 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,
}
}
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;
/// Represents active features that are currently being implemented or
/// currently being considered for addition/removal.
const ACTIVE_FEATURES:
- &[(&str, &str, Option<u32>, Option<Edition>, fn(&mut Features, Span))] =
- &[$((stringify!($feature), $ver, $issue, $edition, set!($feature))),+];
+ &[(Symbol, &str, Option<u32>, Option<Edition>, fn(&mut Features, Span))] =
+ &[$((sym::$feature, $ver, $issue, $edition, set!($feature))),+];
/// A set of features to be used by later passes.
#[derive(Clone)]
($((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<u32>, Option<&str>)] = &[
- $((stringify!($feature), $ver, $issue, $reason)),+
+ const REMOVED_FEATURES: &[(Symbol, &str, Option<u32>, 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<u32>, Option<&str>)] = &[
- $((stringify!($feature), $ver, $issue, None)),+
+ const STABLE_REMOVED_FEATURES: &[(Symbol, &str, Option<u32>, 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<u32>, Option<&str>)] = &[
- $((stringify!($feature), $ver, $issue, None)),+
+ const ACCEPTED_FEATURES: &[(Symbol, &str, Option<u32>, Option<&str>)] = &[
+ $((sym::$feature, $ver, $issue, None)),+
];
}
}
// 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! (
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,
// 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",
)
),
(
- 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 \
)
),
- (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
// 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,
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))),
];
}
// 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)]
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 {
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)
};
}
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"
);
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.
}
}
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);
);
}
-fn find_lang_feature_issue(feature: &str) -> Option<u32> {
+fn find_lang_feature_issue(feature: Symbol) -> Option<u32> {
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
pub fn emit_feature_err(
sess: &ParseSess,
- feature: &str,
+ feature: Symbol,
span: Span,
issue: GateIssue,
explain: &str,
pub fn feature_err<'a>(
sess: &'a ParseSess,
- feature: &str,
+ feature: Symbol,
span: Span,
issue: GateIssue,
explain: &str,
fn leveled_feature_err<'a>(
sess: &'a ParseSess,
- feature: &str,
+ feature: Symbol,
span: Span,
issue: GateIssue,
explain: &str,
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)
}
}}
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) {
// 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"
);
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");
}
}
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 \
}
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");
}
}
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");
}
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
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);
}
}
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);
}
}
}
// 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
}
// 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);
}
}
}
}
for attr in krate_attrs {
- if !attr.check_name(symbols::feature) {
+ if !attr.check_name(sym::feature) {
continue
}
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 {
};
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",
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.
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| {
_ => 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,
- }
-}
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;
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<Comment>, Vec<Literal>)
+pub fn gather_comments(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) -> Vec<Comment>
{
let mut src = String::new();
srdr.read_to_string(&mut src).unwrap();
let mut rdr = lexer::StringReader::new_raw(sess, source_file, None);
let mut comments: Vec<Comment> = Vec::new();
- let mut literals: Vec<Literal> = Vec::new();
let mut code_to_the_left = false; // Only code
let mut anything_to_the_left = false; // Code or comments
}
}
- 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)]
// cache a direct reference to the source text, so that we don't have to
// retrieve it via `self.source_file.src.as_ref().unwrap()` all the time.
src: Lrc<String>,
- token: token::Token,
- span: Span,
- /// The raw source span which *does not* take `override_span` into account
- span_src_raw: Span,
- /// Stack of open delimiters and their spans. Used for error message.
- open_braces: Vec<(token::DelimToken, Span)>,
- crate unmatched_braces: Vec<UnmatchedBrace>,
- /// The type and spans for all braces
- ///
- /// Used only for error recovery when arriving to EOF with mismatched braces.
- matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
- crate override_span: Option<Span>,
- last_unclosed_found_span: Option<Span>,
+ override_span: Option<Span>,
}
impl<'a> StringReader<'a> {
sp: self.peek_span,
};
self.advance_token()?;
- self.span_src_raw = self.peek_span_src_raw;
-
Ok(ret_val)
}
}
}
- self.token = t.tok.clone();
- self.span = t.sp;
-
Ok(t)
}
peek_span_src_raw: syntax_pos::DUMMY_SP,
src,
fatal_errs: Vec::new(),
- token: token::Eof,
- span: syntax_pos::DUMMY_SP,
- span_src_raw: syntax_pos::DUMMY_SP,
- open_braces: Vec::new(),
- unmatched_braces: Vec::new(),
- matching_delim_spans: Vec::new(),
override_span,
- last_unclosed_found_span: None,
}
}
- pub fn new(sess: &'a ParseSess,
- source_file: Lrc<syntax_pos::SourceFile>,
- override_span: Option<Span>) -> 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<syntax_pos::SourceFile>,
override_span: Option<Span>) -> Result<Self, Vec<Diagnostic>> {
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<SourceMap>) -> ParseSess {
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()),
}
}
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]
+use syntax_pos::Span;
+
use crate::print::pprust::token_to_string;
use crate::parse::lexer::{StringReader, UnmatchedBrace};
use crate::parse::{token, PResult};
use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint};
impl<'a> StringReader<'a> {
+ crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
+ let mut tt_reader = TokenTreesReader {
+ string_reader: self,
+ token: token::Eof,
+ span: syntax_pos::DUMMY_SP,
+ open_braces: Vec::new(),
+ unmatched_braces: Vec::new(),
+ matching_delim_spans: Vec::new(),
+ last_unclosed_found_span: None,
+ };
+ let res = tt_reader.parse_all_token_trees();
+ (res, tt_reader.unmatched_braces)
+ }
+}
+
+struct TokenTreesReader<'a> {
+ string_reader: StringReader<'a>,
+ token: token::Token,
+ span: Span,
+ /// Stack of open delimiters and their spans. Used for error message.
+ open_braces: Vec<(token::DelimToken, Span)>,
+ unmatched_braces: Vec<UnmatchedBrace>,
+ /// The type and spans for all braces
+ ///
+ /// Used only for error recovery when arriving to EOF with mismatched braces.
+ matching_delim_spans: Vec<(token::DelimToken, Span, Span)>,
+ last_unclosed_found_span: Option<Span>,
+}
+
+impl<'a> TokenTreesReader<'a> {
// Parse a stream of tokens into a list of `TokenTree`s, up to an `Eof`.
- crate fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
+ fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> {
let mut tts = Vec::new();
+ self.real_token();
while self.token != token::Eof {
tts.push(self.parse_token_tree()?);
}
}
fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> {
- let sm = self.sess.source_map();
+ let sm = self.string_reader.sess.source_map();
match self.token {
token::Eof => {
let msg = "this file contains an un-closed delimiter";
- let mut err = self.sess.span_diagnostic.struct_span_err(self.span, msg);
+ let mut err = self.string_reader.sess.span_diagnostic
+ .struct_span_err(self.span, msg);
for &(_, sp) in &self.open_braces {
err.span_label(sp, "un-closed delimiter");
}
if let Some((delim, _)) = self.open_braces.last() {
if let Some((_, open_sp, close_sp)) = self.matching_delim_spans.iter()
.filter(|(d, open_sp, close_sp)| {
-
- if let Some(close_padding) = sm.span_to_margin(*close_sp) {
- if let Some(open_padding) = sm.span_to_margin(*open_sp) {
- return delim == d && close_padding != open_padding;
+ if let Some(close_padding) = sm.span_to_margin(*close_sp) {
+ if let Some(open_padding) = sm.span_to_margin(*open_sp) {
+ return delim == d && close_padding != open_padding;
+ }
}
- }
- false
+ false
}).next() // these are in reverse order as they get inserted on close, but
{ // we want the last open/first close
err.span_label(
// matching opening delimiter).
let token_str = token_to_string(&self.token);
let msg = format!("unexpected close delimiter: `{}`", token_str);
- let mut err = self.sess.span_diagnostic.struct_span_err(self.span, &msg);
+ let mut err = self.string_reader.sess.span_diagnostic
+ .struct_span_err(self.span, &msg);
err.span_label(self.span, "unexpected close delimiter");
Err(err)
},
// Note that testing for joint-ness here is done via the raw
// source span as the joint-ness is a property of the raw source
// rather than wanting to take `override_span` into account.
- let raw = self.span_src_raw;
+ // Additionally, we actually check if the *next* pair of tokens
+ // is joint, but this is equivalent to checking the current pair.
+ let raw = self.string_reader.peek_span_src_raw;
self.real_token();
- let is_joint = raw.hi() == self.span_src_raw.lo() && token::is_op(&self.token);
+ let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo()
+ && token::is_op(&self.token);
Ok((tt, if is_joint { Joint } else { NonJoint }))
}
}
}
+
+ fn real_token(&mut self) {
+ let t = self.string_reader.real_token();
+ self.token = t.tok;
+ self.span = t.sp;
+ }
}
--- /dev/null
+//! 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<Symbol>,
+ diag: Option<(Span, &Handler)>
+ ) -> Option<LitKind> {
+ 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<Symbol>) {
+ 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::<char>::into).collect::<String>();
+ (token::Lit::ByteStr(Symbol::intern(&string)), None)
+ }
+ LitKind::Byte(byte) => {
+ let string: String = ascii::escape_default(byte).map(Into::<char>::into).collect();
+ (token::Lit::Byte(Symbol::intern(&string)), None)
+ }
+ LitKind::Char(ch) => {
+ let string: String = ch.escape_default().map(Into::<char>::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<Lit> {
+ 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<ast::Name>) {
+ 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<Symbol>, diag: Option<(Span, &Handler)>)
+ -> Option<LitKind> {
+ 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<Symbol>, diag: Option<(Span, &Handler)>)
+ -> Option<LitKind> {
+ 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::<String>();
+ &s2
+ } else {
+ s
+ };
+
+ filtered_float_lit(Symbol::intern(s), suffix, diag)
+}
+
+fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
+ -> Option<LitKind> {
+ // 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::<String>();
+ &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<digits> and u<digits> 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)
+ }
+ })
+}
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::path::{Path, PathBuf};
use std::str;
#[macro_use]
pub mod parser;
-
+pub mod attr;
pub mod lexer;
pub mod token;
-pub mod attr;
-pub mod diagnostics;
-
-pub mod classify;
-
-pub(crate) mod unescape;
-use unescape::{unescape_str, unescape_char, unescape_byte_str, unescape_byte};
-pub(crate) mod unescape_error_reporting;
+crate mod classify;
+crate mod diagnostics;
+crate mod literal;
+crate mod unescape;
+crate mod unescape_error_reporting;
/// Info about a parsing session.
pub struct ParseSess {
included_mod_stack: Lock<Vec<PathBuf>>,
source_map: Lrc<SourceMap>,
pub buffered_lints: Lock<Vec<BufferedEarlyLint>>,
+ /// 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<FxHashMap<Span, Span>>,
}
impl ParseSess {
included_mod_stack: Lock::new(vec![]),
source_map,
buffered_lints: Lock::new(vec![]),
+ ambiguous_block_expr_parse: Lock::new(FxHashMap::default()),
}
}
});
});
}
+
+ /// 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<String>,
+ ) {
+ 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)]
}
/// Given a source file, produces a sequence of token trees. Returns any buffered errors from
-/// parsing the token tream.
+/// parsing the token stream.
pub fn maybe_file_to_stream(
sess: &ParseSess,
source_file: Lrc<SourceFile>,
override_span: Option<Span>,
) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> {
- let mut srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
- srdr.real_token();
+ let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
+ let (token_trees, unmatched_braces) = srdr.into_token_trees();
- match srdr.parse_all_token_trees() {
- Ok(stream) => Ok((stream, srdr.unmatched_braces)),
+ match token_trees {
+ Ok(stream) => Ok((stream, unmatched_braces)),
Err(err) => {
let mut buffer = Vec::with_capacity(1);
err.buffer(&mut buffer);
// Not using `emit_unclosed_delims` to use `db.buffer`
- for unmatched in srdr.unmatched_braces {
+ for unmatched in unmatched_braces {
let mut db = sess.span_diagnostic.struct_span_err(unmatched.found_span, &format!(
"incorrect close delimiter: `{}`",
token_to_string(&token::Token::CloseDelim(unmatched.found_delim)),
Parser::new(sess, stream, None, true, false)
}
-/// Parses a string representing a raw string literal into its final form. The
-/// only operation this does is convert embedded CRLF into a single LF.
-fn raw_str_lit(lit: &str) -> String {
- debug!("raw_str_lit: given {}", lit.escape_default());
- let mut res = String::with_capacity(lit.len());
-
- let mut chars = lit.chars().peekable();
- while let Some(c) = chars.next() {
- if c == '\r' {
- if *chars.peek().unwrap() != '\n' {
- panic!("lexer accepted bare CR");
- }
- chars.next();
- res.push('\n');
- } else {
- res.push(c);
- }
- }
-
- res.shrink_to_fit();
- res
-}
-
-// check if `s` looks like i32 or u1234 etc.
-fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
- s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit())
-}
-
-macro_rules! err {
- ($opt_diag:expr, |$span:ident, $diag:ident| $($body:tt)*) => {
- match $opt_diag {
- Some(($span, $diag)) => { $($body)* }
- None => return None,
- }
- }
-}
-
-crate fn lit_token(lit: token::Lit, suf: Option<Symbol>, diag: Option<(Span, &Handler)>)
- -> (bool /* suffix illegal? */, Option<ast::LitKind>) {
- use ast::LitKind;
-
- match lit {
- token::Byte(i) => {
- let lit_kind = match unescape_byte(&i.as_str()) {
- Ok(c) => LitKind::Byte(c),
- Err(_) => LitKind::Err(i),
- };
- (true, Some(lit_kind))
- },
- token::Char(i) => {
- let lit_kind = match unescape_char(&i.as_str()) {
- Ok(c) => LitKind::Char(c),
- Err(_) => LitKind::Err(i),
- };
- (true, Some(lit_kind))
- },
- token::Err(i) => (true, Some(LitKind::Err(i))),
-
- // There are some valid suffixes for integer and float literals,
- // so all the handling is done internally.
- token::Integer(s) => (false, integer_lit(&s.as_str(), suf, diag)),
- token::Float(s) => (false, float_lit(&s.as_str(), suf, diag)),
-
- token::Str_(mut sym) => {
- // If there are no characters requiring special treatment we can
- // reuse the symbol from the Token. Otherwise, we must generate a
- // new symbol because the string in the LitKind is different to the
- // string in the Token.
- let mut has_error = false;
- let s = &sym.as_str();
- if s.as_bytes().iter().any(|&c| c == b'\\' || c == b'\r') {
- let mut buf = String::with_capacity(s.len());
- unescape_str(s, &mut |_, unescaped_char| {
- match unescaped_char {
- Ok(c) => buf.push(c),
- Err(_) => has_error = true,
- }
- });
- if has_error {
- return (true, Some(LitKind::Err(sym)));
- }
- sym = Symbol::intern(&buf)
- }
-
- (true, Some(LitKind::Str(sym, ast::StrStyle::Cooked)))
- }
- token::StrRaw(mut sym, n) => {
- // Ditto.
- let s = &sym.as_str();
- if s.contains('\r') {
- sym = Symbol::intern(&raw_str_lit(s));
- }
- (true, Some(LitKind::Str(sym, ast::StrStyle::Raw(n))))
- }
- token::ByteStr(i) => {
- let s = &i.as_str();
- let mut buf = Vec::with_capacity(s.len());
- let mut has_error = false;
- unescape_byte_str(s, &mut |_, unescaped_byte| {
- match unescaped_byte {
- Ok(c) => buf.push(c),
- Err(_) => has_error = true,
- }
- });
- if has_error {
- return (true, Some(LitKind::Err(i)));
- }
- buf.shrink_to_fit();
- (true, Some(LitKind::ByteStr(Lrc::new(buf))))
- }
- token::ByteStrRaw(i, _) => {
- (true, Some(LitKind::ByteStr(Lrc::new(i.to_string().into_bytes()))))
- }
- }
-}
-
-fn filtered_float_lit(data: Symbol, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
- -> Option<ast::LitKind> {
- 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<Symbol>, diag: Option<(Span, &Handler)>)
- -> Option<ast::LitKind> {
- 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::<String>();
- &s2
- } else {
- s
- };
-
- filtered_float_lit(Symbol::intern(s), suffix, diag)
-}
-
-fn integer_lit(s: &str, suffix: Option<Symbol>, diag: Option<(Span, &Handler)>)
- -> Option<ast::LitKind> {
- // 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::<String>();
- &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<digits> and u<digits> 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.
#[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[..];
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::<Vec<_>>();
match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) {
(
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::<Vec<_>>();
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),
}
},
#[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::<Vec<_>>();
let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()];
assert_eq!(&docs[..], b);
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 */");
});
}
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};
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;
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;
Interpolated,
Eof,
Ident,
+ BitOr,
Other,
}
})
}
- 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 {
}
}
- fn unexpected_last<T>(&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<T>(&mut self) -> PResult<'a, T> {
match self.expect_one_of(&[], &[]) {
Err(e) => Err(e),
}
fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
- 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
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,
})
}
- fn look_ahead_span(&self, dist: usize) -> Span {
+ crate fn look_ahead_span(&self, dist: usize) -> Span {
if dist == 0 {
return self.span
}
crate fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
self.sess.span_diagnostic.struct_span_err(sp, m)
}
- fn struct_span_warn<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> DiagnosticBuilder<'a> {
- self.sess.span_diagnostic.struct_span_warn(sp, m)
- }
crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
self.sess.span_diagnostic.span_bug(sp, m)
}
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),
/// 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");
}
}
- /// 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<Expr>> {
maybe_whole_expr!(self);
})
}
- fn mk_expr(&mut self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
+ fn mk_expr(&self, span: Span, node: ExprKind, attrs: ThinVec<Attribute>) -> P<Expr> {
P(Expr { node, span, attrs, id: ast::DUMMY_NODE_ID })
}
- fn mk_unary(&mut self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind {
+ fn mk_unary(&self, unop: ast::UnOp, expr: P<Expr>) -> ast::ExprKind {
ExprKind::Unary(unop, expr)
}
- fn mk_binary(&mut self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
+ fn mk_binary(&self, binop: ast::BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
ExprKind::Binary(binop, lhs, rhs)
}
- fn mk_call(&mut self, f: P<Expr>, args: Vec<P<Expr>>) -> ast::ExprKind {
+ fn mk_call(&self, f: P<Expr>, args: Vec<P<Expr>>) -> ast::ExprKind {
ExprKind::Call(f, args)
}
- fn mk_index(&mut self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
+ fn mk_index(&self, expr: P<Expr>, idx: P<Expr>) -> ast::ExprKind {
ExprKind::Index(expr, idx)
}
- fn mk_range(&mut self,
+ fn mk_range(&self,
start: Option<P<Expr>>,
end: Option<P<Expr>>,
limits: RangeLimits)
}
}
- fn mk_assign_op(&mut self, binop: ast::BinOp,
+ fn mk_assign_op(&self, binop: ast::BinOp,
lhs: P<Expr>, rhs: P<Expr>) -> ast::ExprKind {
ExprKind::AssignOp(binop, lhs, rhs)
}
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);
self.expect(&token::OpenDelim(token::Paren))?;
let expr = self.parse_expr()?;
self.expect(&token::CloseDelim(token::Paren))?;
+ hi = self.prev_span;
ex = ExprKind::Await(ast::AwaitOrigin::MacroLike, expr);
} else if self.token.is_path_start() {
let path = self.parse_path(PathStyle::Expr)?;
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);
}
"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()),
}
};
- 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) {
} else {
self.restrictions
};
- if op.precedence() < min_prec {
+ let prec = op.precedence();
+ if prec < min_prec {
break;
}
// Check for deprecated `...` syntax
// 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
};
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.
}
};
- if op.fixity() == Fixity::None { break }
+ if let Fixity::None = fixity { break }
}
Ok(lhs)
}
/// 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);
}
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) {
);
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);
}
}
})
}
- fn is_async_block(&mut self) -> bool {
+ fn is_async_block(&self) -> bool {
self.token.is_keyword(keywords::Async) &&
(
( // `async move {`
)
}
- 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() &&
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)))
(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);
}
/// 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)
}
/// | ( < 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()?;
/// where T : Trait<U, V> + '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(),
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<Attribute>) -> P<Item> {
P(Item {
ident,
/// 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))
})
}
- 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 => {}
_ => {
}
}
- 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" {
}
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 {
}
pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
- 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
/// 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<IsAsync>, 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_mut().enumerate() {
let id = ast::DUMMY_NODE_ID;
// statement.
let (binding_mode, ident, is_simple_pattern) = match input.pat.node {
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),
})
};
- // Remove mutability from arguments. If this is not a simple pattern,
- // those arguments are replaced by `__argN`, so there is no need to do this.
- if let PatKind::Ident(BindingMode::ByValue(mutability @ Mutability::Mutable), ..) =
- &mut input.pat.node
- {
- assert!(is_simple_pattern);
- *mutability = Mutability::Immutable;
- }
-
let move_stmt = Stmt { id, node: StmtKind::Local(P(move_local)), span };
arguments.push(AsyncArgument { ident, arg, pat_stmt, move_stmt });
}
#[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),
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::<Lit>() == 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",
}
}
+ 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 {
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 {
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(..)"),
}
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> {
pub struct State<'a> {
pub s: pp::Printer<'a>,
cm: Option<&'a SourceMap>,
- comments: Option<Vec<comments::Comment> >,
- literals: Peekable<vec::IntoIter<comments::Literal>>,
+ comments: Option<Vec<comments::Comment>>,
cur_cmnt: usize,
boxes: Vec<pp::Breaks>,
ann: &'a (dyn PpAnn+'a),
s: pp::mk_printer(writer, DEFAULT_COLUMNS),
cm: None,
comments: None,
- literals: vec![].into_iter().peekable(),
cur_cmnt: 0,
boxes: Vec::new(),
ann,
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,
out: Box<dyn Write+'a>,
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<dyn Write+'a>,
ann: &'a dyn PpAnn,
comments: Option<Vec<comments::Comment>>,
- literals: Option<Vec<comments::Literal>>,
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,
}
}
}
}
}
+pub fn literal_to_string(lit: token::Lit, suffix: Option<ast::Name>) -> 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(),
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(),
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),
}
fn boxes(&mut self) -> &mut Vec<pp::Breaks>;
fn comments(&mut self) -> &mut Option<Vec<comments::Comment>>;
fn cur_cmnt(&mut self) -> &mut usize;
- fn cur_lit(&mut self) -> Option<&comments::Literal>;
- fn bump_lit(&mut self) -> Option<comments::Literal>;
fn word_space<S: Into<Cow<'static, str>>>(&mut self, w: S) -> io::Result<()> {
self.writer().word(w)?;
self.end()
}
- fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
- 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 {
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,
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<comments::Literal> {
- self.literals.next()
- }
}
impl<'a> State<'a> {
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<Lrc<[symbol::Symbol]>>,
+ ) -> 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 {
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;
}
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<Option<&'static str>> = Cell::new(None);
}
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"]
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 {
// 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
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(),
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,
}
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<ast::Path> {
- 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,
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;
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;
}
}
-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,
-> Box<dyn base::MacResult + 'cx> {
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);
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");
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<'_>,
-> Box<dyn base::MacResult + 'cx> {
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);
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<'_>,
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,
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};
}
};
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;
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() })))
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) {
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());
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};
//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);
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,
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<'_>,
-> Box<dyn base::MacResult + 'cx> {
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);
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,
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(|| {
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);
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);
};
// Creates a new module which looks like:
//
+// #[doc(hidden)]
// mod $gensym {
// extern crate proc_macro;
//
});
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,
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);
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;
}
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;
// 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() {
}
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 {
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;
) -> Vec<Annotatable> {
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);
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;
-> Box<dyn base::MacResult + 'static> {
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);
+use crate::symbol::{Symbol, sym};
use std::fmt;
use std::str::FromStr;
}
}
- 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,
}
}
/// 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
impl CompilerDesugaringKind {
pub fn name(self) -> Symbol {
Symbol::intern(match self {
+ CompilerDesugaringKind::IfTemporary => "if",
CompilerDesugaringKind::Async => "async",
CompilerDesugaringKind::Await => "await",
CompilerDesugaringKind::QuestionMark => "?",
pub use span_encoding::{Span, DUMMY_SP};
pub mod symbol;
-pub use symbol::symbols;
+pub use symbol::{Symbol, sym};
mod analyze_source_file;
/// 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,
}
// Keywords that are used in stable Rust.
As: "as",
- Box: "box",
Break: "break",
Const: "const",
Continue: "continue",
// Keywords that are used in unstable Rust or reserved for future use.
Abstract: "abstract",
Become: "become",
+ Box: "box",
Do: "do",
Final: "final",
Macro: "macro",
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,
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,
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,
}
}
}
}
-/// A symbol is an interned or gensymed string. The use of `newtype_index!` means
-/// that `Option<Symbol>` 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<Symbol>` 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.
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))
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))
}
}
}
-impl<T: std::ops::Deref<Target=str>> PartialEq<T> 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
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
}
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]
}
}
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()]
+ }
}
}
}
keywords!();
}
-pub mod symbols {
+// This module has a very short name because it's used a lot.
+pub mod sym {
use super::Symbol;
symbols!();
}
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,
}
}
-/// 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,
unsafe { f(&*str) }
}
+ fn with2<F: FnOnce(&str, &str) -> 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
}
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))
}
}
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))
}
}
}
}
-impl std::convert::From<InternedString> for String {
- fn from(val: InternedString) -> String {
- val.as_symbol().to_string()
- }
-}
-
impl fmt::Debug for InternedString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.with(|str| fmt::Debug::fmt(&str, f))
#[cfg(any(
target_os = "freebsd",
target_os = "dragonfly",
- target_os = "bitrig",
target_os = "netbsd"
))]
fn num_cpus() -> usize {
println!("cargo:rustc-link-lib=c++abi");
} else if target.contains("solaris") {
println!("cargo:rustc-link-lib=gcc_s");
- } else if target.contains("bitrig") {
- println!("cargo:rustc-link-lib=c++abi");
} else if target.contains("dragonfly") {
println!("cargo:rustc-link-lib=gcc_pic");
} else if target.contains("windows-gnu") {
-Subproject commit 84abffda0e03b03c62bdfc3cfeda1c2cf1f88c85
+Subproject commit eb38a1888d1d29b2d2c6b31428a5201cd8fba0ff
// This test is for *-windows-msvc only.
// ignore-android
-// ignore-bitrig
// ignore-cloudabi
// ignore-dragonfly
// ignore-emscripten
b: bool,
}
-// CHECK: target triple = "i686-apple-darwin"
+// CHECK: target triple = "i686-apple-macosx10.7.0"
#[no_mangle]
pub extern "C" fn structbool() -> Bool {
Bool { b: true }
// This test is for *-windows-msvc only.
// ignore-android
-// ignore-bitrig
// ignore-cloudabi
// ignore-dragonfly
// ignore-emscripten
b: bool,
}
-// CHECK: target triple = "x86_64-apple-darwin"
+// CHECK: target triple = "x86_64-apple-macosx10.7.0"
#[no_mangle]
pub extern "C" fn structbool() -> Bool {
Bool { b: true }
}
#[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;
}
#[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>) -> u32 {
let mut ret = 1;
--- /dev/null
+// revisions:rpass1 rpass2
+
+struct A;
+
+#[cfg(rpass2)]
+impl From<A> for () {
+ fn from(_: A) {}
+}
+
+fn main() {}
--- /dev/null
+fn main() {
+ let x: u32 = [0, 1, 2, 3][2];
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _2 = [const 0u32, const 1u32, const 2u32, const 3u32];
+// ...
+// _3 = const 2usize;
+// _4 = const 4usize;
+// _5 = Lt(_3, _4);
+// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
+// }
+// bb1: {
+// _1 = _2[_3];
+// ...
+// return;
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _5 = const true;
+// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
+// }
+// bb1: {
+// _1 = _2[_3];
+// ...
+// return;
+// }
+// END rustc.main.ConstProp.after.mir
--- /dev/null
+// compile-flags: -C overflow-checks=on
+
+fn main() {
+ let x: u32 = 1 + 1;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _2 = CheckedAdd(const 1u32, const 1u32);
+// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _2 = (const 2u32, const false);
+// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
+// }
+// END rustc.main.ConstProp.after.mir
--- /dev/null
+#[inline(never)]
+fn read(_: usize) { }
+
+fn main() {
+ const FOO: &i32 = &1;
+ let x = FOO as *const i32 as usize;
+ read(x);
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _3 = _4;
+// _2 = move _3 as *const i32 (Misc);
+// ...
+// _1 = move _2 as usize (Misc);
+// ...
+// _6 = _1;
+// _5 = const read(move _6) -> bb1;
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _3 = _4;
+// _2 = move _3 as *const i32 (Misc);
+// ...
+// _1 = move _2 as usize (Misc);
+// ...
+// _6 = _1;
+// _5 = const read(move _6) -> bb1;
+// }
+// END rustc.main.ConstProp.after.mir
--- /dev/null
+fn test() -> &'static [u32] {
+ &[1, 2]
+}
+
+fn main() {
+ let x = test()[0];
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb1: {
+// ...
+// _3 = const 0usize;
+// _4 = Len((*_2));
+// _5 = Lt(_3, _4);
+// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+// }
+// bb2: {
+// _1 = (*_2)[_3];
+// ...
+// return;
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _3 = const 0usize;
+// _4 = Len((*_2));
+// _5 = Lt(_3, _4);
+// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
+// }
+// bb2: {
+// _1 = (*_2)[_3];
+// ...
+// return;
+// }
+// END rustc.main.ConstProp.after.mir
// 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;
// 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
// 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;
}
// 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
--- /dev/null
+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
# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
# only way that `foo.c` will successfully compile.
-ifeq ($(UNAME),Bitrig)
- EXTRACFLAGS := -lc $(EXTRACFLAGS) $(EXTRACXXFLAGS)
-endif
-
all:
$(RUSTC) foo.rs --crate-type=rlib
$(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a
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)
$(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
-include ../tools.mk
+
+# ignore-musl
+# Objects are reproducible but their path is not.
+
all: \
smoke \
debug \
ifeq ($(UNAME),FreeBSD)
EXTRACFLAGS := -lm -lpthread -lgcc_s
else
-ifeq ($(UNAME),Bitrig)
- EXTRACFLAGS := -lm -lpthread
- EXTRACXXFLAGS := -lc++ -lc++abi
-else
ifeq ($(UNAME),SunOS)
EXTRACFLAGS := -lm -lpthread -lposix4 -lsocket -lresolv
else
endif
endif
endif
-endif
REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1))
REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1))
# ignore-freebsd
# ignore-openbsd
-# ignore-bitrig
# ignore-sunos
HOST := $(shell $(RUSTC) -vV | grep 'host:' | sed 's/host: //')
# 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
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};
};
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,
#[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! {
_ => 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");
}
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),*) => {
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]
all(target_os = "linux", target_arch = "arm"),
target_os = "freebsd",
target_os = "dragonfly",
- target_os = "bitrig",
target_os = "openbsd")) {
// skip these platforms as this support isn't implemented yet.
} else {
// run-pass
-#![feature(const_ptr_nonnull)]
-
use std::ptr::NonNull;
const DANGLING: NonNull<u32> = NonNull::dangling();
#[cfg(target_os = "dragonfly")]
mod hello;
-#[cfg(target_os = "bitrig")]
-mod hello;
-
#[cfg(target_os = "android")]
mod hello;
// Tests parallel codegen - this can fail if the symbol for the anonymous
// closure in `sum` pollutes the second codegen unit from the first.
-// ignore-bitrig
// compile-flags: -C codegen_units=2
#![feature(iter_arith)]
--- /dev/null
+warning: unreachable block in `if` expression
+ --> $DIR/if-ret.rs:4:24
+ |
+LL | fn foo() { if (return) { } }
+ | ^^^
+ |
+ = note: #[warn(unreachable_code)] on by default
+
#![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;
--- /dev/null
+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)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
// run-pass
#![allow(warnings)]
+#![feature(generators)]
use std::fmt::Debug;
fn iter_doesnt_capture_unnecessary_lifetime<'s>(&'s self) -> impl Iterator<Item = &'s u8> {
self.0.iter().flat_map(|inner_vec| inner_vec.iter())
}
+
+ fn generator_doesnt_capture_unnecessary_lifetime<'s: 's>() -> impl Sized {
+ || yield
+ }
}
+
fn main() {}
}
}
-#[cfg(target_os = "bitrig")]
-mod m {
- #[main]
- #[cfg(target_arch = "x86_64")]
- pub fn main() {
- unsafe {
- assert_eq!(::rusti::pref_align_of::<u64>(), 8);
- assert_eq!(::rusti::min_align_of::<u64>(), 8);
- }
- }
-}
-
#[cfg(target_os = "windows")]
mod m {
#[main]
// run-pass
-// ignore-bitrig
// compile-flags: -C codegen-units=3
// aux-build:sepcomp_cci_lib.rs
// run-pass
-// ignore-bitrig
// compile-flags: -C codegen-units=3
// aux-build:sepcomp-extern-lib.rs
// run-pass
#![allow(dead_code)]
-// ignore-bitrig
// compile-flags: -C codegen-units=3
// Test references to items that haven't been codegened yet.
// run-pass
-// ignore-bitrig
// compile-flags: -C codegen-units=3
// Test basic separate compilation functionality. The functions should be able
// run-pass
#![allow(dead_code)]
-// ignore-bitrig
// compile-flags: -C codegen-units=3
// Test references to static items across compilation units.
// run-pass
#![allow(dead_code)]
-// ignore-bitrig
// compile-flags: -C codegen-units=3
// ignore-emscripten no threads support
}
}
-#[cfg(target_os = "bitrig")]
-mod m {
- #[cfg(target_arch = "x86_64")]
- pub mod m {
- pub fn align() -> usize { 8 }
- pub fn size() -> usize { 16 }
- }
-}
-
#[cfg(target_os = "windows")]
mod m {
#[cfg(target_arch = "x86")]
// ignore-android needs extra network permissions
-// ignore-bitrig system ulimit (Too many open files)
// ignore-cloudabi no global network namespace access
// ignore-emscripten no threads or sockets support
// ignore-netbsd system ulimit (Too many open files)
}
#[cfg(any(target_os = "android",
- target_os = "bitrig",
target_os = "cloudabi",
target_os = "dragonfly",
target_os = "emscripten",
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);
}
use rustc_plugin::Registry;
use rustc::hir;
use syntax::attr;
+use syntax::symbol::Symbol;
declare_lint! {
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]");
}
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'");
}
}
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'");
}
}
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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() {}
--- /dev/null
+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) { }
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
--- /dev/null
+#![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<const NUM_BYTES: usize>(pub [u8; NUM_BYTES]);
+
+fn main() {
+ let _ = Foo::<3>([1, 2, 3]); //~ ERROR type annotations needed
+}
--- /dev/null
+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`.
--- /dev/null
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash
+
+struct S<const X: u32>;
+
+impl<const X: u32> S<{X}> {
+ fn x() -> u32 {
+ X
+ }
+}
+
+fn main() {
+ assert_eq!(S::<19>::x(), 19);
+}
--- /dev/null
+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)]
+ | ^^^^^^^^^^^^^^
+
--- /dev/null
+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
+}
--- /dev/null
+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`.
|
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"); }
| ^ ^
|
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 }) {}
| ^ ^
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
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
--- /dev/null
+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() {}
--- /dev/null
+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`.
--- /dev/null
+// Test that existential types are allowed to contain late-bound regions.
+
+// compile-pass
+// edition:2018
+
+#![feature(async_await, existential_type)]
+
+use std::future::Future;
+
+pub existential type Func: Sized;
+
+// Late bound region should be allowed to escape the function, since it's bound
+// in the type.
+fn null_function_ptr() -> Func {
+ None::<for<'a> fn(&'a ())>
+}
+
+async fn async_nop(_: &u8) {}
+
+pub existential type ServeFut: Future<Output=()>;
+
+// Late bound regions occur in the generator witness type here.
+fn serve() -> ServeFut {
+ async move {
+ let x = 5;
+ async_nop(&x).await
+ }
+}
+
+fn main() {}
--> $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
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 `()`
}
-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}`
--- /dev/null
+// 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]
+}
--- /dev/null
+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`.
return 3;
}
//~^^^ ERROR if may be missing an else clause
+ //~| ERROR mismatched types [E0308]
}
fn foo2(bar: usize) -> usize {
return 3;
};
//~^^^ ERROR if may be missing an else clause
+ //~| ERROR mismatched types [E0308]
x
}
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);
}
+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
|
= 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 {
| _________-__________^
= 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
= 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`.
#![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;
+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();
| ^^^^^^^^^^
#![feature(impl_trait_in_bindings)]
+//~^ WARN the feature `impl_trait_in_bindings` is incomplete and may cause the compiler to crash
fn a<T: Clone>(x: T) {
const foo: impl Clone = x;
+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
|x: &'static i32| x
}
+fn make_identity_static() -> impl Sized + 'static {
+ |x: &'static i32| x
+}
+
fn main() {}
A(f)
}
+fn wrapped_closure_with_bound() -> impl Sized + 'static {
+ let f = |x| x;
+ f(&0);
+ A(f)
+}
+
fn main() {
let x: Box<dyn Send> = Box::new(wrapped_closure());
+ let y: Box<dyn Send> = Box::new(wrapped_closure_with_bound());
}
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
enum Foo {
Drop = assert_eq!(1, 1)
//~^ ERROR if may be missing an else clause
+ //~| ERROR mismatched types [E0308]
}
}
+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
|
= 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`.
--- /dev/null
+pub mod test {
+ pub struct A;
+ pub struct B;
+ pub struct Foo<T>(T);
+
+ impl Foo<A> {
+ fn foo() {}
+ }
+
+ impl Foo<B> {
+ fn foo() {}
+ }
+}
+
+fn main() {
+ test::Foo::<test::B>::foo(); //~ ERROR method `foo` is private
+}
--- /dev/null
+error[E0624]: method `foo` is private
+ --> $DIR/issue-53498.rs:16:5
+ |
+LL | test::Foo::<test::B>::foo();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0624`.
--- /dev/null
+// compile-pass
+// compile-flags: -Z unpretty=hir
+
+#![feature(existential_type)]
+
+trait Animal {
+}
+
+fn main() {
+ pub existential type ServeFut: Animal;
+}
--- /dev/null
+// 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;
+ }
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
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 _;
);
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
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
// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass
-
-#![allow(warnings)]
+// skip-codegen
fn foo<'a, 'b>(x: &'a &'b u32) -> &'a u32 {
&**x
fn bug<'a>() -> impl Iterator<Item = &'a str> {
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
})
}
-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
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`.
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
--- /dev/null
+// 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<u32>, b: Option<u32>) -> 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() {}
--- /dev/null
+// 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<u32>, b: Option<u32>) -> 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() {}
--- /dev/null
+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`.
fn main() {
-
- match 0 {
+ let _ = match 0 {
0 => {
+ 0
} + 5 //~ 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
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
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
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
LL | | x: 3
LL | | } {
| |_____^
-help: surround the struct literal with parenthesis
+help: surround the struct literal with parentheses
|
LL | match (Foo {
LL | x: 3
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
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
-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
--- /dev/null
+//! 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 }
#![deny(unreachable_code)]
fn foo() {
- if {return} {
+ if {return} { //~ ERROR unreachable block in `if` expression
println!("Hello, world!");
}
}
-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
--- /dev/null
+#![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);
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+#![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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+// 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<UninhabitedEnum> {
+ None
+}
+
+fn uninhabited_variant() -> Option<UninhabitedVariants> {
+ None
+}
+
+fn partially_inhabited_variant() -> PartiallyInhabitedVariants {
+ PartiallyInhabitedVariants::Tuple(3)
+}
+
+fn uninhabited_struct() -> Option<UninhabitedStruct> {
+ None
+}
+
+fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
+ 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.
+ }
+}
--- /dev/null
+#![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<UninhabitedEnum> {
+ None
+}
+
+fn uninhabited_variant() -> Option<UninhabitedVariants> {
+ None
+}
+
+fn partially_inhabited_variant() -> PartiallyInhabitedVariants {
+ PartiallyInhabitedVariants::Tuple(3)
+}
+
+fn uninhabited_struct() -> Option<UninhabitedStruct> {
+ None
+}
+
+fn uninhabited_tuple_struct() -> Option<UninhabitedTupleStruct> {
+ 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
+ }
+}
--- /dev/null
+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
+
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
--- /dev/null
+// 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() {}
--- /dev/null
+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`.
|
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 }) {}
| ^ ^
|
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 }) {}
| ^ ^
|
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 }) {}
| ^ ^
|
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: "" }) {}
| ^ ^
--- /dev/null
+// Test that we properly detect the cycle amongst the traits
+// here and report an error.
+
+use std::panic::RefUnwindSafe;
+
+trait Database {
+ type Storage;
+}
+trait HasQueryGroup {}
+trait Query<DB> {
+ type Data;
+}
+trait SourceDatabase {
+ fn parse(&self) {
+ loop {}
+ }
+}
+
+struct ParseQuery;
+struct RootDatabase {
+ _runtime: Runtime<RootDatabase>,
+}
+struct Runtime<DB: Database> {
+ _storage: Box<DB::Storage>,
+}
+struct SalsaStorage {
+ _parse: <ParseQuery as Query<RootDatabase>>::Data, //~ ERROR overflow
+}
+
+impl Database for RootDatabase { //~ ERROR overflow
+ type Storage = SalsaStorage;
+}
+impl HasQueryGroup for RootDatabase {}
+impl<DB> Query<DB> for ParseQuery
+where
+ DB: SourceDatabase,
+ DB: Database,
+{
+ type Data = RootDatabase;
+}
+impl<T> SourceDatabase for T
+where
+ T: RefUnwindSafe,
+ T: HasQueryGroup,
+{
+}
+
+pub(crate) fn goto_implementation(db: &RootDatabase) -> u32 {
+ // This is not satisfied:
+ //
+ // - `RootDatabase: SourceDatabase`
+ // - requires `RootDatabase: RefUnwindSafe` + `RootDatabase: HasQueryGroup`
+ // - `RootDatabase: RefUnwindSafe`
+ // - requires `Runtime<RootDatabase>: RefUnwindSafe`
+ // - `Runtime<RootDatabase>: RefUnwindSafe`
+ // - requires `DB::Storage: RefUnwindSafe` (`SalsaStorage: RefUnwindSafe`)
+ // - `SalsaStorage: RefUnwindSafe`
+ // - requires `<ParseQuery as Query<RootDatabase>>::Data: RefUnwindSafe`,
+ // which means `ParseQuery: Query<RootDatabase>`
+ // - `ParseQuery: Query<RootDatabase>`
+ // - requires `RootDatabase: SourceDatabase`,
+ // - `RootDatabase: SourceDatabase` is already on the stack, so we have a
+ // cycle with non-coinductive participants
+ //
+ // we used to fail to report an error here because we got the
+ // caching wrong.
+ SourceDatabase::parse(db);
+ 22
+}
+
+fn main() {}
--- /dev/null
+error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
+ --> $DIR/cycle-cache-err-60010.rs:27:5
+ |
+LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
+
+error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
+ --> $DIR/cycle-cache-err-60010.rs:30:6
+ |
+LL | impl Database for RootDatabase {
+ | ^^^^^^^^
+ |
+ = note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
+ = note: required because it appears within the type `SalsaStorage`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
[dependencies]
toml = "0.4"
serde = { version = "1.0", features = ["derive"] }
-serde_derive = "1.0"
"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",
-Subproject commit 759b6161a328db1d4863139e90875308ecd25a75
+Subproject commit c4fcfb725b4be00c72eb9cf30c7d8b095577c280
-Subproject commit 341c96afd331195beeb001436535c1feb479ff9d
+Subproject commit 11194e3d050f45ff002a775f451ff6222fcd5b2c
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"
use std::path::Path;
use std::str::FromStr;
+use log::*;
+
#[derive(Clone, Debug, PartialEq)]
pub enum ErrorKind {
Help,
use std::io::BufReader;
use std::path::{Path, PathBuf};
+use log::*;
+
use crate::common::{self, CompareMode, Config, Mode};
use crate::util;
use crate::errors::{Error, ErrorKind};
use crate::runtest::ProcRes;
+use serde::Deserialize;
use serde_json;
use std::path::{Path, PathBuf};
use std::str::FromStr;
#![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;
use walkdir::WalkDir;
use env_logger;
use getopts;
+use log::*;
use self::header::{EarlyProps, Ignore};
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;
(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")
{
}
}
+ // 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
fn charset() -> &'static str {
// FreeBSD 10.1 defaults to GDB 6.1.1 which doesn't support "auto" charset
- if cfg!(target_os = "bitrig") {
- "auto"
- } else if cfg!(target_os = "freebsd") {
+ if cfg!(target_os = "freebsd") {
"ISO-8859-1"
} else {
"UTF-8"
create_dir_all(&tmpdir).unwrap();
let host = &self.config.host;
- let make = if host.contains("bitrig")
- || host.contains("dragonfly")
+ let make = if host.contains("dragonfly")
|| host.contains("freebsd")
|| host.contains("netbsd")
|| host.contains("openbsd")
// 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.
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"),
("androideabi", "android"),
- ("bitrig", "bitrig"),
("cloudabi", "cloudabi"),
("cuda", "cuda"),
("darwin", "macos"),
-Subproject commit 053aa694990a212ad8942dd72101ede23597c0e9
+Subproject commit bc0c76d861a178911f3f506196a7404eda1e690d
[dependencies]
regex = "1"
-serde = "1.0.8"
-serde_derive = "1.0.8"
+serde = { version = "1.0.8", features = ["derive"] }
serde_json = "1.0.2"
use std::path::Path;
use std::process::Command;
-use serde_derive::Deserialize;
+use serde::Deserialize;
use serde_json;
const LICENSES: &[&str] = &[