*.woff binary
src/vendor/** -text
Cargo.lock -merge linguist-generated=false
+
+# Older git versions try to fix line endings on images, this prevents it.
+*.png binary
+*.ico binary
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "arc-swap"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "arena"
version = "0.0.0"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "bytes"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "bytesize"
version = "1.0.0"
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "crossbeam-channel"
+version = "0.3.4"
+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)",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "crossbeam-deque"
version = "0.2.0"
"crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "crossbeam-deque"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "crossbeam-epoch"
version = "0.3.1"
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "crossbeam-epoch"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.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.2.2"
"xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "iovec"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "is-match"
version = "0.1.0"
"either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "itertools"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "itoa"
version = "0.4.3"
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "languageserver-types"
-version = "0.51.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.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)",
- "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "lazy_static"
version = "0.2.11"
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "lsp-codec"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lsp-types"
+version = "0.54.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-traits 0.2.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)",
+ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "lzma-sys"
version = "0.1.10"
"miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "mio"
+version = "0.6.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "kernel32-sys 0.2.2 (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.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio-named-pipes"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "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)",
+ "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "mio-uds"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "miow"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "miow"
version = "0.3.3"
"vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "net2"
+version = "0.2.33"
+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)",
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "new_debug_unreachable"
version = "1.0.1"
"parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "parking_lot"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "parking_lot_core"
version = "0.3.0"
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "parking_lot_core"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "percent-encoding"
version = "1.0.1"
"cargo 0.34.0",
"cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy_lints 0.0.212",
- "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-channel 0.3.4 (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.5.13 (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.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lsp-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lsp-types 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"racer 2.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"rls-analysis 0.16.10 (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)",
"tempfile 3.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "signal-hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "siphasher"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "slab"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "smallvec"
version = "0.6.7"
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "tokio"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.21 (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)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-codec"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-current-thread"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-executor"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-fs"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-io"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.11 (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)",
+]
+
+[[package]]
+name = "tokio-process"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-reactor"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
+ "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)",
+ "parking_lot 0.7.1 (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)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-signal"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-tcp"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-threadpool"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-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)",
+ "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)",
+ "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-timer"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
+]
+
+[[package]]
+name = "tokio-udp"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.11 (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)",
+ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tokio-uds"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
+ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.46 (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)",
+ "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "toml"
version = "0.4.10"
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "ws2_32-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "xattr"
version = "0.2.2"
"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e"
"checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+"checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98589b0e465a6c510d95fceebd365bb79bedece7f6e18a480897f2015f85ec51"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39"
"checksum bytecount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b92204551573580e078dc80017f36a213eb77a0450e4ddd8cfa0f3f2d1f0178f"
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
+"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
"checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010"
"checksum cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d8dfe3adeb30f7938e6c1dd5327f29235d8ada3e898aeb08c343005ec2915a2"
"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749"
"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.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827"
+"checksum crossbeam-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5b2a9ea8f77c7f9efd317a8a5645f515d903a2d86ee14d2337a5facd1bd52c12"
"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.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c90f1474584f38e270b5b613e898c8c328aa4f3dea85e0a27ac2e642f009416"
+"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.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
"checksum crossbeam-utils 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e07fc155212827475223f0bcfae57e945e694fc90950ddf3f6695bbfd5555c72"
"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec"
"checksum ignore 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36ecfc5ad80f0b1226df948c562e2cddd446096be3f644c95106400eae8a5e01"
"checksum im-rc 12.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4591152fd573cf453a890b5f9fdc5c328a751a0785539316739d5f85e5c468c"
+"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 itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450"
+"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
"checksum jemalloc-sys 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "bfc62c8e50e381768ce8ee0428ee53741929f7ebd73e4d83f669bcf7693e00ae"
"checksum jobserver 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "dd80e58f77e0cdea53ba96acc5e04479e5ffc5d869626a6beafe50fed867eace"
"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be"
"checksum jsonrpc-core 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4e9cbeda300803d381390fb65e8158437728c39e6987ed23bee82728b73511a7"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68de833188ada4e175d04a028f03f244f6370eedbcc75a05604d47d925933f69"
"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 lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd"
+"checksum lsp-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b29e3d1632fef13c1286b0b2f8545a7d894ae565a7fac013b90a17ee5bfbc91"
+"checksum lsp-types 0.54.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a252cc2be87d9329dd91c505a951996b3263582ba304870960faaae77b642183"
"checksum lzma-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d1eaa027402541975218bb0eec67d6b0412f6233af96e0d096d31dbdfd22e614"
"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
"checksum macro-utils 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c4deaccc2ead6a28c16c0ba82f07d52b6475397415ce40876e559b0b0ea510"
"checksum miniz-sys 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "0300eafb20369952951699b68243ab4334f4b10a88f411c221d444b36c40e649"
"checksum miniz_oxide 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5ad30a47319c16cde58d0314f5d98202a80c9083b5f61178457403dfb14e509c"
"checksum miniz_oxide_c_api 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "28edaef377517fd9fe3e085c37d892ce7acd1fbeab9239c5a36eec352d8a8b7e"
+"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
+"checksum mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3"
+"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125"
+"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
+"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4"
"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum num-derive 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8af1847c907c2f04d7bfd572fb25bbb4385c637fe5be163cf2f8c5d778fe1e7d"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
"checksum packed_simd 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25d36de864f7218ec5633572a800109bbe5a1cc8d9d95a967f3daf93ea7e6ddc"
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
+"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
"checksum parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06a2b6aae052309c2fd2161ef58f5067bc17bb758377a0de9d4b279d603fdd8a"
+"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
"checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc"
"checksum pest_derive 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3294f437119209b084c797604295f40227cffa35c57220b1e99a6ff3bf8ee4"
"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811"
"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
+"checksum signal-hook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f272d1b7586bec132ed427f532dd418d8beca1ca7f2caf7df35569b1415a4b4"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
+"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7"
"checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa"
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
+"checksum tokio 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4790d0be6f4ba6ae4f48190efa2ed7780c9e3567796abdb285003cf39840d9c5"
+"checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f"
+"checksum tokio-current-thread 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "331c8acc267855ec06eb0c94618dcbbfea45bed2d20b77252940095273fb58f6"
+"checksum tokio-executor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "30c6dbf2d1ad1de300b393910e8a3aa272b724a400b6531da03eed99e329fbf0"
+"checksum tokio-fs 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0e9cbbc8a3698b7ab652340f46633364f9eaa928ddaaee79d8b8f356dd79a09d"
+"checksum tokio-io 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b53aeb9d3f5ccf2ebb29e19788f96987fa1355f8fe45ea193928eaaaf3ae820f"
+"checksum tokio-process 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88e1281e412013f1ff5787def044a9577a0bed059f451e835f1643201f8b777d"
+"checksum tokio-reactor 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "afbcdb0f0d2a1e4c440af82d7bbf0bf91a8a8c0575bcd20c05d15be7e9d3a02f"
+"checksum tokio-signal 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dd6dc5276ea05ce379a16de90083ec80836440d5ef8a6a39545a3207373b8296"
+"checksum tokio-tcp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1d14b10654be682ac43efee27401d792507e30fd8d26389e1da3b185de2e4119"
+"checksum tokio-threadpool 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "17465013014410310f9f61fa10bf4724803c149ea1d51efece131c38efca93aa"
+"checksum tokio-timer 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f37f0111d76cc5da132fe9bc0590b9b9cfd079bc7e75ac3846278430a299ff8"
+"checksum tokio-udp 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66268575b80f4a4a710ef83d087fdfeeabdce9b74c797535fbac18a2cb906e92"
+"checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445"
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
"checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
"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"
"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c"
"checksum xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "df8bf41d3030c3577c9458fd6640a05afbf43b150d0b531b16bd77d3f794f27a"
"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
# server goes down presumably. See #43333 for more info
CARGO_HTTP_CHECK_REVOKE: false
- # Recommended by AppVeyor this moves our builds to GCE which incurs a 3-4
- # minute startup overhead, but that's paltry compared to our overall build
- # times so we're will to eat the cost. This is intended to give us better
- # performance I believe!
- appveyor_build_worker_cloud: gce
-
matrix:
# 32/64 bit MSVC tests
- MSYS_BITS: 64
# with clang-cl, so this is special in that it only compiles LLVM with clang-cl
#clang-cl = '/path/to/clang-cl.exe'
+# Pass extra compiler and linker flags to the LLVM CMake build.
+#cflags = "-fextra-flag"
+#cxxflags = "-fextra-flag"
+#ldflags = "-Wl,extra-flag"
+
# Use libc++ when building LLVM instead of libstdc++. This is the default on
# platforms already use libc++ as the default C++ library, but this option
# allows you to use libc++ even on platforms when it's not. You need to ensure
There is also useful content in the following READMEs, which are gradually being moved over to the guide:
- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query
- https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph
-- https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked
- https://github.com/rust-lang/rust/tree/master/src/librustc/infer/lexical_region_resolve
err = "unknown OS type: {}".format(ostype)
sys.exit(err)
+ if cputype == 'powerpc' and ostype == 'unknown-freebsd':
+ cputype = subprocess.check_output(
+ ['uname', '-p']).strip().decode(default_encoding)
cputype_mapper = {
'BePC': 'i686',
'aarch64': 'aarch64',
test::Debuginfo,
test::UiFullDeps,
test::RunPassFullDeps,
- test::RunFailFullDeps,
test::Rustdoc,
test::Pretty,
test::RunPassPretty,
test::RunFailPretty,
test::RunPassValgrindPretty,
- test::RunPassFullDepsPretty,
- test::RunFailFullDepsPretty,
test::Crate,
test::CrateLibrustc,
test::CrateRustdoc,
}
}
+ /// Get the paths to all of the compiler's codegen backends.
+ fn codegen_backends(&self, compiler: Compiler) -> impl Iterator<Item = PathBuf> {
+ fs::read_dir(self.sysroot_codegen_backends(compiler))
+ .into_iter()
+ .flatten()
+ .filter_map(Result::ok)
+ .map(|entry| entry.path())
+ }
+
pub fn rustdoc(&self, host: Interned<String>) -> PathBuf {
self.ensure(tool::Rustdoc { host })
}
match mode {
Mode::Std => {
self.clear_if_dirty(&my_out, &self.rustc(compiler));
+ for backend in self.codegen_backends(compiler) {
+ self.clear_if_dirty(&my_out, &backend);
+ }
},
Mode::Test => {
self.clear_if_dirty(&my_out, &libstd_stamp);
if self.config.incremental {
cargo.env("CARGO_INCREMENTAL", "1");
+ } else {
+ // Don't rely on any default setting for incr. comp. in Cargo
+ cargo.env("CARGO_INCREMENTAL", "0");
}
if let Some(ref on_fail) = self.config.on_fail {
pub lldb_enabled: bool,
pub llvm_tools_enabled: bool,
+ pub llvm_cflags: Option<String>,
+ pub llvm_cxxflags: Option<String>,
+ pub llvm_ldflags: Option<String>,
pub llvm_use_libcxx: bool,
// rust codegen options
link_shared: Option<bool>,
version_suffix: Option<String>,
clang_cl: Option<String>,
+ cflags: Option<String>,
+ cxxflags: Option<String>,
+ ldflags: Option<String>,
use_libcxx: Option<bool>,
}
config.llvm_link_jobs = llvm.link_jobs;
config.llvm_version_suffix = llvm.version_suffix.clone();
config.llvm_clang_cl = llvm.clang_cl.clone();
+
+ config.llvm_cflags = llvm.cflags.clone();
+ config.llvm_cxxflags = llvm.cxxflags.clone();
+ config.llvm_ldflags = llvm.ldflags.clone();
set(&mut config.llvm_use_libcxx, llvm.use_libcxx);
}
o("missing-tools", "dist.missing-tools", "allow failures when building tools")
o("use-libcxx", "llvm.use_libcxx", "build LLVM with libc++")
+o("cflags", "llvm.cflags", "build LLVM with these extra compiler flags")
+o("cxxflags", "llvm.cxxflags", "build LLVM with these extra compiler flags")
+o("ldflags", "llvm.ldflags", "build LLVM with these extra linker flags")
+
# Optimization and debugging options. These may be overridden by the release
# channel, etc.
o("optimize", "rust.optimize", "build optimized rust code")
// gdb debugger scripts
builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
0o755);
+ builder.install(&builder.src.join("src/etc/rust-gdbgui"), &sysroot.join("bin"),
+ 0o755);
cp_debugger_script("gdb_load_rust_pretty_printers.py");
cp_debugger_script("gdb_rust_pretty_printing.py");
src/test/run-fail/pretty \
src/test/run-pass-valgrind/pretty \
src/test/run-pass-fulldeps/pretty \
- src/test/run-fail-fulldeps/pretty \
$(AUX_ARGS) \
$(BOOTSTRAP_ARGS)
check-bootstrap:
}
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
- cfg.define("CMAKE_C_FLAGS", builder.cflags(target, GitRepo::Llvm).join(" "));
+ let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" ");
+ if let Some(ref s) = builder.config.llvm_cxxflags {
+ cflags.push_str(&format!(" {}", s));
+ }
+ cfg.define("CMAKE_C_FLAGS", cflags);
let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" ");
if builder.config.llvm_static_stdcpp &&
!target.contains("windows") &&
{
cxxflags.push_str(" -static-libstdc++");
}
+ if let Some(ref s) = builder.config.llvm_cxxflags {
+ cxxflags.push_str(&format!(" {}", s));
+ }
cfg.define("CMAKE_CXX_FLAGS", cxxflags);
if let Some(ar) = builder.ar(target) {
if ar.is_absolute() {
}
}
+ if let Some(ref s) = builder.config.llvm_ldflags {
+ cfg.define("CMAKE_SHARED_LINKER_FLAGS", s);
+ cfg.define("CMAKE_MODULE_LINKER_FLAGS", s);
+ cfg.define("CMAKE_EXE_LINKER_FLAGS", s);
+ }
+
if env::var_os("SCCACHE_ERROR_LOG").is_some() {
cfg.env("RUST_LOG", "sccache=warn");
}
suite: "run-pass-fulldeps"
});
-host_test!(RunFailFullDeps {
- path: "src/test/run-fail-fulldeps",
- mode: "run-fail",
- suite: "run-fail-fulldeps"
-});
-
host_test!(Rustdoc {
path: "src/test/rustdoc",
mode: "rustdoc",
default: false,
host: true
});
-test!(RunPassFullDepsPretty {
- path: "src/test/run-pass-fulldeps/pretty",
- mode: "pretty",
- suite: "run-pass-fulldeps",
- default: false,
- host: true
-});
-test!(RunFailFullDepsPretty {
- path: "src/test/run-fail-fulldeps/pretty",
- mode: "pretty",
- suite: "run-fail-fulldeps",
- default: false,
- host: true
-});
default_test!(RunMake {
path: "src/test/run-make",
apt-get update
apt-get install -y --no-install-recommends software-properties-common apt-transport-https
-apt-key adv --batch --yes --keyserver keyserver.ubuntu.com --recv-keys AA12E97F0881517F
+apt-key adv --batch --yes --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys AA12E97F0881517F
add-apt-repository -y 'deb https://static.redox-os.org/toolchain/apt /'
apt-get update
COPY dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
# We pass the commit id of the port of LLVM's libunwind to the build script.
# Any update to the commit id here, should cause the container image to be re-built from this point on.
-RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "bbe23902411be88d7388f381becefadd6e3ef819"
+RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh "13fad13f8ea83a8da58d04a5faa45943151b3398"
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
# The output from sdkmanager is so noisy that it will occupy all of the 4 MB
# log extremely quickly. Thus we must silence all output.
yes | sdkmanager --licenses > /dev/null
- sdkmanager platform-tools emulator \
+ yes | sdkmanager platform-tools emulator \
"platforms;android-$api" \
"system-images;android-$api;default;$abi" > /dev/null
}
#![feature(plugin_registrar, rustc_private)]
extern crate syntax;
+extern crate syntax_pos;
extern crate rustc;
extern crate rustc_plugin;
use syntax::tokenstream::TokenTree;
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
use syntax::ext::build::AstBuilder; // A trait for expr_usize.
-use syntax::ext::quote::rt::Span;
+use syntax_pos::Span;
use rustc_plugin::Registry;
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
--- /dev/null
+# `is_sorted`
+
+The tracking issue for this feature is: [#53485]
+
+[#53485]: https://github.com/rust-lang/rust/issues/53485
+
+------------------------
+
+Add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to `[T]`;
+add the methods `is_sorted`, `is_sorted_by` and `is_sorted_by_key` to
+`Iterator`.
# This fix went in 8.1, so check for that.
# See https://github.com/rust-lang/rust/issues/56730
gdb_81 = False
-_match = re.match('([0-9]+)\\.([0-9]+)', gdb.VERSION)
+_match = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION)
if _match:
if int(_match.group(1)) > 8 or (int(_match.group(1)) == 8 and int(_match.group(2)) >= 1):
gdb_81 = True
/// # Examples
///
/// ```
- /// #![feature(get_type_id)]
- ///
/// use std::any::{Any, TypeId};
///
/// fn is_string(s: &dyn Any) -> bool {
- /// TypeId::of::<String>() == s.get_type_id()
+ /// TypeId::of::<String>() == s.type_id()
/// }
///
/// fn main() {
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// }
/// ```
- #[unstable(feature = "get_type_id",
- reason = "this method will likely be replaced by an associated static",
- issue = "27745")]
- fn get_type_id(&self) -> TypeId;
+ #[stable(feature = "get_type_id", since = "1.34.0")]
+ fn type_id(&self) -> TypeId;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: 'static + ?Sized > Any for T {
- fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
+ fn type_id(&self) -> TypeId { TypeId::of::<T>() }
}
///////////////////////////////////////////////////////////////////////////////
let t = TypeId::of::<T>();
// Get TypeId of the type in the trait object
- let boxed = self.get_type_id();
+ let concrete = self.type_id();
// Compare both TypeIds on equality
- t == boxed
+ t == concrete
}
/// Returns some reference to the boxed value if it is of type `T`, or
--- /dev/null
+use std::io::{self, Write as IoWrite};
+use std::fmt::{self, Write as FmtWrite};
+use test::Bencher;
+
+#[bench]
+fn write_vec_value(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ for _ in 0..1000 {
+ mem.write_all("abc".as_bytes()).unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_ref(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ wr.write_all("abc".as_bytes()).unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_macro1(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ write!(wr, "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_macro2(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ write!(wr, "{}", "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_vec_macro_debug(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = Vec::new();
+ let wr = &mut mem as &mut dyn io::Write;
+ for _ in 0..1000 {
+ write!(wr, "{:?}", "☃").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_value(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ for _ in 0..1000 {
+ mem.write_str("abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_ref(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ wr.write_str("abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_macro1(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ for _ in 0..1000 {
+ write!(mem, "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_macro2(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ write!(wr, "{}", "abc").unwrap();
+ }
+ });
+}
+
+#[bench]
+fn write_str_macro_debug(bh: &mut Bencher) {
+ bh.iter(|| {
+ let mut mem = String::new();
+ let wr = &mut mem as &mut dyn fmt::Write;
+ for _ in 0..1000 {
+ write!(wr, "{:?}", "☃").unwrap();
+ }
+ });
+}
mod num;
mod ops;
mod slice;
+mod fmt;
// Infallible conversions are semantically equivalent to fallible conversions
// with an uninhabited error type.
#[unstable(feature = "try_from", issue = "33417")]
-impl<T, U> TryFrom<U> for T where T: From<U> {
+impl<T, U> TryFrom<U> for T where U: Into<T> {
type Error = !;
fn try_from(value: U) -> Result<Self, Self::Error> {
- Ok(T::from(value))
+ Ok(U::into(value))
}
}
}
}
-/// A struct to represent both where to emit formatting strings to and how they
-/// should be formatted. A mutable version of this is passed to all formatting
-/// traits.
+/// Configuration for formatting.
+///
+/// A `Formatter` represents various options related to formatting. Users do not
+/// construct `Formatter`s directly; a mutable reference to one is passed to
+/// the `fmt` method of all formatting traits, like [`Debug`] and [`Display`].
+///
+/// To interact with a `Formatter`, you'll call various methods to change the
+/// various options related to formatting. For examples, please see the
+/// documentation of the methods defined on `Formatter` below.
+///
+/// [`Debug`]: trait.Debug.html
+/// [`Display`]: trait.Display.html
#[allow(missing_debug_implementations)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Formatter<'a> {
curarg: args.args.iter(),
};
- let mut pieces = args.pieces.iter();
+ let mut idx = 0;
match args.fmt {
None => {
// We can use default formatting parameters for all arguments.
- for (arg, piece) in args.args.iter().zip(pieces.by_ref()) {
+ for (arg, piece) in args.args.iter().zip(args.pieces.iter()) {
formatter.buf.write_str(*piece)?;
(arg.formatter)(arg.value, &mut formatter)?;
+ idx += 1;
}
}
Some(fmt) => {
// Every spec has a corresponding argument that is preceded by
// a string piece.
- for (arg, piece) in fmt.iter().zip(pieces.by_ref()) {
+ for (arg, piece) in fmt.iter().zip(args.pieces.iter()) {
formatter.buf.write_str(*piece)?;
formatter.run(arg)?;
+ idx += 1;
}
}
}
// There can be only one trailing string piece left.
- if let Some(piece) = pieces.next() {
+ if let Some(piece) = args.pieces.get(idx) {
formatter.buf.write_str(*piece)?;
}
}
}
}
+
+ /// Checks if the elements of this iterator are sorted.
+ ///
+ /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
+ /// iterator yields exactly zero or one element, `true` is returned.
+ ///
+ /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition
+ /// implies that this function returns `false` if any two consecutive items are not
+ /// comparable.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_sorted)]
+ ///
+ /// assert!([1, 2, 2, 9].iter().is_sorted());
+ /// assert!(![1, 3, 2, 4].iter().is_sorted());
+ /// assert!([0].iter().is_sorted());
+ /// assert!(std::iter::empty::<i32>().is_sorted());
+ /// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted());
+ /// ```
+ #[inline]
+ #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+ fn is_sorted(self) -> bool
+ where
+ Self: Sized,
+ Self::Item: PartialOrd,
+ {
+ self.is_sorted_by(|a, b| a.partial_cmp(b))
+ }
+
+ /// Checks if the elements of this iterator are sorted using the given comparator function.
+ ///
+ /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare`
+ /// function to determine the ordering of two elements. Apart from that, it's equivalent to
+ /// [`is_sorted`]; see its documentation for more information.
+ ///
+ /// [`is_sorted`]: trait.Iterator.html#method.is_sorted
+ #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+ fn is_sorted_by<F>(mut self, mut compare: F) -> bool
+ where
+ Self: Sized,
+ F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>
+ {
+ let mut last = match self.next() {
+ Some(e) => e,
+ None => return true,
+ };
+
+ while let Some(curr) = self.next() {
+ if compare(&last, &curr)
+ .map(|o| o == Ordering::Greater)
+ .unwrap_or(true)
+ {
+ return false;
+ }
+ last = curr;
+ }
+
+ true
+ }
+
+ /// Checks if the elements of this iterator are sorted using the given key extraction
+ /// function.
+ ///
+ /// Instead of comparing the iterator's elements directly, this function compares the keys of
+ /// the elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see
+ /// its documentation for more information.
+ ///
+ /// [`is_sorted`]: trait.Iterator.html#method.is_sorted
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_sorted)]
+ ///
+ /// assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
+ /// assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
+ /// ```
+ #[inline]
+ #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+ fn is_sorted_by_key<F, K>(self, mut f: F) -> bool
+ where
+ Self: Sized,
+ F: FnMut(&Self::Item) -> K,
+ K: PartialOrd
+ {
+ self.is_sorted_by(|a, b| f(a).partial_cmp(&f(b)))
+ }
}
/// Select an element from an iterator based on the given "projection"
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(intrinsics)]
+#![feature(is_sorted)]
#![feature(iter_once_with)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
/// * '2.5E10', or equivalently, '2.5e10'
/// * '2.5E-10'
/// * '5.'
- /// * '.5', or, equivalently, '0.5'
+ /// * '.5', or, equivalently, '0.5'
/// * 'inf', '-inf', 'NaN'
///
/// Leading and trailing whitespace represent an error.
///
+ /// # Grammar
+ ///
+ /// All strings that adhere to the following [EBNF] grammar
+ /// will result in an [`Ok`] being returned:
+ ///
+ /// ```txt
+ /// Float ::= Sign? ( 'inf' | 'NaN' | Number )
+ /// Number ::= ( Digit+ |
+ /// Digit+ '.' Digit* |
+ /// Digit* '.' Digit+ ) Exp?
+ /// Exp ::= [eE] Sign? Digit+
+ /// Sign ::= [+-]
+ /// Digit ::= [0-9]
+ /// ```
+ ///
+ /// [EBNF]: https://www.w3.org/TR/REC-xml/#sec-notation
+ ///
+ /// # Known bugs
+ ///
+ /// In some situations, some strings that should create a valid float
+ /// instead return an error. See [issue #31407] for details.
+ ///
+ /// [issue #31407]: https://github.com/rust-lang/rust/issues/31407
+ ///
/// # Arguments
///
/// * src - A string
use str::FromStr;
macro_rules! impl_nonzero_fmt {
- ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
+ ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
$(
- #[stable(feature = "nonzero", since = "1.28.0")]
+ #[$stability]
impl fmt::$Trait for $Ty {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
macro_rules! nonzero_integers {
- ( $( $Ty: ident($Int: ty); )+ ) => {
+ ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => {
$(
doc_comment! {
concat!("An integer that is known not to equal zero.
```rust
use std::mem::size_of;
-assert_eq!(size_of::<Option<std::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
+assert_eq!(size_of::<Option<core::num::", stringify!($Ty), ">>(), size_of::<", stringify!($Int),
">());
```"),
- #[stable(feature = "nonzero", since = "1.28.0")]
+ #[$stability]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(1)]
/// # Safety
///
/// The value must not be zero.
- #[stable(feature = "nonzero", since = "1.28.0")]
+ #[$stability]
#[inline]
pub const unsafe fn new_unchecked(n: $Int) -> Self {
$Ty(n)
}
/// Create a non-zero if the given value is not zero.
- #[stable(feature = "nonzero", since = "1.28.0")]
+ #[$stability]
#[inline]
pub fn new(n: $Int) -> Option<Self> {
if n != 0 {
}
/// Returns the value as a primitive type.
- #[stable(feature = "nonzero", since = "1.28.0")]
+ #[$stability]
#[inline]
pub const fn get(self) -> $Int {
self.0
}
impl_nonzero_fmt! {
- (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
+ #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty
}
)+
}
}
nonzero_integers! {
- NonZeroU8(u8);
- NonZeroU16(u16);
- NonZeroU32(u32);
- NonZeroU64(u64);
- NonZeroU128(u128);
- NonZeroUsize(usize);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128);
+ #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128);
+ #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize);
}
/// Provides intentionally-wrapped arithmetic on `T`.
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64));
assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);",
$EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
let mut base = self;
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "use std::", stringify!($SelfT), ";
assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64);
assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);",
$EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81);
assert_eq!(3i8.wrapping_pow(5), -13);
assert_eq!(3i8.wrapping_pow(6), -39);",
$EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn wrapping_pow(self, mut exp: u32) -> Self {
let mut base = self;
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false));
assert_eq!(3i8.overflowing_pow(5), (-13, true));",
$EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
let mut base = self;
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32));
assert_eq!(", stringify!($SelfT), "::max_value().checked_pow(2), None);", $EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn checked_pow(self, mut exp: u32) -> Option<Self> {
let mut base = self;
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "use std::", stringify!($SelfT), ";
assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64);
assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);",
$EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn saturating_pow(self, exp: u32) -> Self {
match self.checked_pow(exp) {
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243);
assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn wrapping_pow(self, mut exp: u32) -> Self {
let mut base = self;
Basic usage:
```
-#![feature(no_panic_pow)]
", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false));
assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, "
```"),
- #[unstable(feature = "no_panic_pow", issue = "48320")]
+ #[stable(feature = "no_panic_pow", since = "1.34.0")]
#[inline]
pub fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
let mut base = self;
/// ```
#[lang = "index"]
#[rustc_on_unimplemented(
- on(
- _Self="&str",
- note="you can use `.chars().nth()` or `.bytes().nth()`
-see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
- ),
- on(
- _Self="str",
- note="you can use `.chars().nth()` or `.bytes().nth()`
-see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
- ),
- on(
- _Self="std::string::String",
- note="you can use `.chars().nth()` or `.bytes().nth()`
-see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
- ),
message="the type `{Self}` cannot be indexed by `{Idx}`",
label="`{Self}` cannot be indexed by `{Idx}`",
)]
/// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
/// a[1..5].rotate_left(1);
/// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
- /// ```
+ /// ```
#[stable(feature = "slice_rotate", since = "1.26.0")]
pub fn rotate_left(&mut self, mid: usize) {
assert!(mid <= self.len());
from_raw_parts_mut(mut_ptr.add(rest.len() - ts_len), ts_len))
}
}
+
+ /// Checks if the elements of this slice are sorted.
+ ///
+ /// That is, for each element `a` and its following element `b`, `a <= b` must hold. If the
+ /// slice yields exactly zero or one element, `true` is returned.
+ ///
+ /// Note that if `Self::Item` is only `PartialOrd`, but not `Ord`, the above definition
+ /// implies that this function returns `false` if any two consecutive items are not
+ /// comparable.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_sorted)]
+ /// let empty: [i32; 0] = [];
+ ///
+ /// assert!([1, 2, 2, 9].is_sorted());
+ /// assert!(![1, 3, 2, 4].is_sorted());
+ /// assert!([0].is_sorted());
+ /// assert!(empty.is_sorted());
+ /// assert!(![0.0, 1.0, std::f32::NAN].is_sorted());
+ /// ```
+ #[inline]
+ #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+ pub fn is_sorted(&self) -> bool
+ where
+ T: PartialOrd,
+ {
+ self.is_sorted_by(|a, b| a.partial_cmp(b))
+ }
+
+ /// Checks if the elements of this slice are sorted using the given comparator function.
+ ///
+ /// Instead of using `PartialOrd::partial_cmp`, this function uses the given `compare`
+ /// function to determine the ordering of two elements. Apart from that, it's equivalent to
+ /// [`is_sorted`]; see its documentation for more information.
+ ///
+ /// [`is_sorted`]: #method.is_sorted
+ #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+ pub fn is_sorted_by<F>(&self, mut compare: F) -> bool
+ where
+ F: FnMut(&T, &T) -> Option<Ordering>
+ {
+ self.iter().is_sorted_by(|a, b| compare(*a, *b))
+ }
+
+ /// Checks if the elements of this slice are sorted using the given key extraction function.
+ ///
+ /// Instead of comparing the slice's elements directly, this function compares the keys of the
+ /// elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see its
+ /// documentation for more information.
+ ///
+ /// [`is_sorted`]: #method.is_sorted
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(is_sorted)]
+ ///
+ /// assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+ /// assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+ /// ```
+ #[inline]
+ #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")]
+ pub fn is_sorted_by_key<F, K>(&self, mut f: F) -> bool
+ where
+ F: FnMut(&T) -> K,
+ K: PartialOrd
+ {
+ self.is_sorted_by(|a, b| f(a).partial_cmp(&f(b)))
+ }
}
#[lang = "slice_u8"]
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
impl<T, I> ops::Index<I> for [T]
where I: SliceIndex<[T]>
{
}
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
impl<T, I> ops::IndexMut<I> for [T]
where I: SliceIndex<[T]>
{
/// A helper trait used for indexing operations.
#[stable(feature = "slice_get_slice", since = "1.28.0")]
-#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
+#[rustc_on_unimplemented(
+ on(
+ T = "str",
+ label = "string indices are ranges of `usize`",
+ ),
+ on(
+ all(any(T = "str", T = "&str", T = "std::string::String"), _Self="{integer}"),
+ note="you can use `.chars().nth()` or `.bytes().nth()`
+see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
+ ),
+ message = "the type `{T}` cannot be indexed by `{Self}`",
+ label = "slice indices are of type `usize` or ranges of `usize`",
+)]
pub trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
/// The output type returned by methods.
#[stable(feature = "slice_get_slice", since = "1.28.0")]
// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
- (struct $name:ident -> $ptr:ty, $elem:ty, $raw_mut:tt, $( $mut_:tt )*) => {
+ (
+ struct $name:ident -> $ptr:ty,
+ $elem:ty,
+ $raw_mut:tt,
+ {$( $mut_:tt )*},
+ {$($extra:tt)*}
+ ) => {
impl<'a, T> $name<'a, T> {
// Helper function for creating a slice from the iterator.
#[inline(always)]
i
})
}
+
+ $($extra)*
}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-iterator!{struct Iter -> *const T, &'a T, const, /* no mut */}
+iterator!{struct Iter -> *const T, &'a T, const, {/* no mut */}, {
+ fn is_sorted_by<F>(self, mut compare: F) -> bool
+ where
+ Self: Sized,
+ F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
+ {
+ self.as_slice().windows(2).all(|w| {
+ compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
+ })
+ }
+}}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Iter<'_, T> {
}
}
-iterator!{struct IterMut -> *mut T, &'a mut T, mut, mut}
+iterator!{struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
/// An internal abstraction over the splitting iterators, so that
/// splitn, splitn_mut etc can be implemented once.
}
}
- /// Implements substring slicing with syntax `&self[begin .. end]`.
- ///
- /// Returns a slice of the given string from the byte range
- /// [`begin`..`end`).
- ///
- /// This operation is `O(1)`.
- ///
- /// # Panics
- ///
- /// Panics if `begin` or `end` does not point to the starting
- /// byte offset of a character (as defined by `is_char_boundary`).
- /// Requires that `begin <= end` and `end <= len` where `len` is the
- /// length of the string.
- ///
- /// # Examples
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- /// assert_eq!(&s[0 .. 1], "L");
- ///
- /// assert_eq!(&s[1 .. 9], "öwe 老");
- ///
- /// // these will panic:
- /// // byte 2 lies within `ö`:
- /// // &s[2 ..3];
- ///
- /// // byte 8 lies within `老`
- /// // &s[1 .. 8];
- ///
- /// // byte 100 is outside the string
- /// // &s[3 .. 100];
- /// ```
#[stable(feature = "rust1", since = "1.0.0")]
- impl ops::Index<ops::Range<usize>> for str {
- type Output = str;
- #[inline]
- fn index(&self, index: ops::Range<usize>) -> &str {
- index.index(self)
- }
- }
-
- /// Implements mutable substring slicing with syntax
- /// `&mut self[begin .. end]`.
- ///
- /// Returns a mutable slice of the given string from the byte range
- /// [`begin`..`end`).
- ///
- /// This operation is `O(1)`.
- ///
- /// # Panics
- ///
- /// Panics if `begin` or `end` does not point to the starting
- /// byte offset of a character (as defined by `is_char_boundary`).
- /// Requires that `begin <= end` and `end <= len` where `len` is the
- /// length of the string.
- #[stable(feature = "derefmut_for_string", since = "1.3.0")]
- impl ops::IndexMut<ops::Range<usize>> for str {
- #[inline]
- fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
- index.index_mut(self)
- }
- }
-
- /// Implements substring slicing with syntax `&self[.. end]`.
- ///
- /// Returns a slice of the string from the beginning to byte offset
- /// `end`.
- ///
- /// Equivalent to `&self[0 .. end]`.
- #[stable(feature = "rust1", since = "1.0.0")]
- impl ops::Index<ops::RangeTo<usize>> for str {
- type Output = str;
-
- #[inline]
- fn index(&self, index: ops::RangeTo<usize>) -> &str {
- index.index(self)
- }
- }
-
- /// Implements mutable substring slicing with syntax `&mut self[.. end]`.
- ///
- /// Returns a mutable slice of the string from the beginning to byte offset
- /// `end`.
- ///
- /// Equivalent to `&mut self[0 .. end]`.
- #[stable(feature = "derefmut_for_string", since = "1.3.0")]
- impl ops::IndexMut<ops::RangeTo<usize>> for str {
- #[inline]
- fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
- index.index_mut(self)
- }
- }
-
- /// Implements substring slicing with syntax `&self[begin ..]`.
- ///
- /// Returns a slice of the string from byte offset `begin`
- /// to the end of the string.
- ///
- /// Equivalent to `&self[begin .. len]`.
- #[stable(feature = "rust1", since = "1.0.0")]
- impl ops::Index<ops::RangeFrom<usize>> for str {
- type Output = str;
+ impl<I> ops::Index<I> for str
+ where
+ I: SliceIndex<str>,
+ {
+ type Output = I::Output;
#[inline]
- fn index(&self, index: ops::RangeFrom<usize>) -> &str {
+ fn index(&self, index: I) -> &I::Output {
index.index(self)
}
}
- /// Implements mutable substring slicing with syntax `&mut self[begin ..]`.
- ///
- /// Returns a mutable slice of the string from byte offset `begin`
- /// to the end of the string.
- ///
- /// Equivalent to `&mut self[begin .. len]`.
- #[stable(feature = "derefmut_for_string", since = "1.3.0")]
- impl ops::IndexMut<ops::RangeFrom<usize>> for str {
- #[inline]
- fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
- index.index_mut(self)
- }
- }
-
- /// Implements substring slicing with syntax `&self[..]`.
- ///
- /// Returns a slice of the whole string. This operation can
- /// never panic.
- ///
- /// Equivalent to `&self[0 .. len]`.
#[stable(feature = "rust1", since = "1.0.0")]
- impl ops::Index<ops::RangeFull> for str {
- type Output = str;
-
- #[inline]
- fn index(&self, _index: ops::RangeFull) -> &str {
- self
- }
- }
-
- /// Implements mutable substring slicing with syntax `&mut self[..]`.
- ///
- /// Returns a mutable slice of the whole string. This operation can
- /// never panic.
- ///
- /// Equivalent to `&mut self[0 .. len]`.
- #[stable(feature = "derefmut_for_string", since = "1.3.0")]
- impl ops::IndexMut<ops::RangeFull> for str {
- #[inline]
- fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
- self
- }
- }
-
- #[stable(feature = "inclusive_range", since = "1.26.0")]
- impl ops::Index<ops::RangeInclusive<usize>> for str {
- type Output = str;
-
- #[inline]
- fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
- index.index(self)
- }
- }
-
- #[stable(feature = "inclusive_range", since = "1.26.0")]
- impl ops::Index<ops::RangeToInclusive<usize>> for str {
- type Output = str;
-
- #[inline]
- fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
- index.index(self)
- }
- }
-
- #[stable(feature = "inclusive_range", since = "1.26.0")]
- impl ops::IndexMut<ops::RangeInclusive<usize>> for str {
- #[inline]
- fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
- index.index_mut(self)
- }
- }
- #[stable(feature = "inclusive_range", since = "1.26.0")]
- impl ops::IndexMut<ops::RangeToInclusive<usize>> for str {
+ impl<I> ops::IndexMut<I> for str
+ where
+ I: SliceIndex<str>,
+ {
#[inline]
- fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
+ fn index_mut(&mut self, index: I) -> &mut I::Output {
index.index_mut(self)
}
}
panic!("attempted to index str up to maximum usize");
}
+ /// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`.
+ ///
+ /// Returns a slice of the whole string, i.e., returns `&self` or `&mut
+ /// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike
+ /// other indexing operations, this can never panic.
+ ///
+ /// This operation is `O(1)`.
+ ///
+ /// Prior to 1.20.0, these indexing operations were still supported by
+ /// direct implementation of `Index` and `IndexMut`.
+ ///
+ /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeFull {
type Output = str;
}
}
+ /// Implements substring slicing with syntax `&self[begin .. end]` or `&mut
+ /// self[begin .. end]`.
+ ///
+ /// Returns a slice of the given string from the byte range
+ /// [`begin`, `end`).
+ ///
+ /// This operation is `O(1)`.
+ ///
+ /// Prior to 1.20.0, these indexing operations were still supported by
+ /// direct implementation of `Index` and `IndexMut`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `begin` or `end` does not point to the starting byte offset of
+ /// a character (as defined by `is_char_boundary`), if `begin > end`, or if
+ /// `end > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// assert_eq!(&s[0 .. 1], "L");
+ ///
+ /// assert_eq!(&s[1 .. 9], "öwe 老");
+ ///
+ /// // these will panic:
+ /// // byte 2 lies within `ö`:
+ /// // &s[2 ..3];
+ ///
+ /// // byte 8 lies within `老`
+ /// // &s[1 .. 8];
+ ///
+ /// // byte 100 is outside the string
+ /// // &s[3 .. 100];
+ /// ```
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::Range<usize> {
type Output = str;
}
}
+ /// Implements substring slicing with syntax `&self[.. end]` or `&mut
+ /// self[.. end]`.
+ ///
+ /// Returns a slice of the given string from the byte range [`0`, `end`).
+ /// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`.
+ ///
+ /// This operation is `O(1)`.
+ ///
+ /// Prior to 1.20.0, these indexing operations were still supported by
+ /// direct implementation of `Index` and `IndexMut`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `end` does not point to the starting byte offset of a
+ /// character (as defined by `is_char_boundary`), or if `end > len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeTo<usize> {
type Output = str;
}
}
+ /// Implements substring slicing with syntax `&self[begin ..]` or `&mut
+ /// self[begin ..]`.
+ ///
+ /// Returns a slice of the given string from the byte range [`begin`,
+ /// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin ..
+ /// len]`.
+ ///
+ /// This operation is `O(1)`.
+ ///
+ /// Prior to 1.20.0, these indexing operations were still supported by
+ /// direct implementation of `Index` and `IndexMut`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `begin` does not point to the starting byte offset of
+ /// a character (as defined by `is_char_boundary`), or if `begin >= len`.
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeFrom<usize> {
type Output = str;
}
}
+ /// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut
+ /// self[begin ..= end]`.
+ ///
+ /// Returns a slice of the given string from the byte range
+ /// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut
+ /// self[begin .. end + 1]`, except if `end` has the maximum value for
+ /// `usize`.
+ ///
+ /// This operation is `O(1)`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `begin` does not point to the starting byte offset of
+ /// a character (as defined by `is_char_boundary`), if `end` does not point
+ /// to the ending byte offset of a character (`end + 1` is either a starting
+ /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl SliceIndex<str> for ops::RangeInclusive<usize> {
type Output = str;
}
}
-
-
+ /// Implements substring slicing with syntax `&self[..= end]` or `&mut
+ /// self[..= end]`.
+ ///
+ /// Returns a slice of the given string from the byte range [0, `end`].
+ /// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum
+ /// value for `usize`.
+ ///
+ /// This operation is `O(1)`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `end` does not point to the ending byte offset of a character
+ /// (`end + 1` is either a starting byte offset as defined by
+ /// `is_char_boundary`, or equal to `len`), or if `end >= len`.
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl SliceIndex<str> for ops::RangeToInclusive<usize> {
type Output = str;
assert_eq!((0..10).flat_map(f).flat_map(g).sum::<usize>(),
(0..10).flat_map(|x| f(x).flat_map(g)).sum::<usize>());
}
+
+#[test]
+fn test_is_sorted() {
+ assert!([1, 2, 2, 9].iter().is_sorted());
+ assert!(![1, 3, 2].iter().is_sorted());
+ assert!([0].iter().is_sorted());
+ assert!(std::iter::empty::<i32>().is_sorted());
+ assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted());
+ assert!([-2, -1, 0, 3].iter().is_sorted());
+ assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
+ assert!(!["c", "bb", "aaa"].iter().is_sorted());
+ assert!(["c", "bb", "aaa"].iter().is_sorted_by_key(|s| s.len()));
+}
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
+#![feature(is_sorted)]
#![feature(iter_copied)]
#![feature(iter_nth_back)]
#![feature(iter_once_with)]
-use core::num::NonZeroU32;
+use core::num::{NonZeroU32, NonZeroI32};
use core::option::Option;
use core::option::Option::{Some, None};
use std::mem::size_of;
#[test]
fn test_size_nonzero_in_option() {
assert_eq!(size_of::<NonZeroU32>(), size_of::<Option<NonZeroU32>>());
+ assert_eq!(size_of::<NonZeroI32>(), size_of::<Option<NonZeroI32>>());
}
#[test]
let num: u32 = nz.into();
assert_eq!(num, 1u32);
}
+
+#[test]
+fn test_from_signed_nonzero() {
+ let nz = NonZeroI32::new(1).unwrap();
+ let num: i32 = nz.into();
+ assert_eq!(num, 1i32);
+}
// 2 is greater than 1, so this range is invalid.
bytes.copy_within(2..1, 0);
}
+
+#[test]
+fn test_is_sorted() {
+ let empty: [i32; 0] = [];
+
+ assert!([1, 2, 2, 9].is_sorted());
+ assert!(![1, 3, 2].is_sorted());
+ assert!([0].is_sorted());
+ assert!(empty.is_sorted());
+ assert!(![0.0, 1.0, std::f32::NAN].is_sorted());
+ assert!([-2, -1, 0, 3].is_sorted());
+ assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+ assert!(!["c", "bb", "aaa"].is_sorted());
+ assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+}
ArgumentNamed(&'a str),
}
+impl Position<'_> {
+ pub fn index(&self) -> Option<usize> {
+ match self {
+ ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i),
+ _ => None,
+ }
+ }
+}
+
/// Enum of alignments which are supported.
#[derive(Copy, Clone, PartialEq)]
pub enum Alignment {
}
fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex {
- let hir_id = self.tcx.hir().node_to_hir_id(stmt.node.id());
- match stmt.node {
- hir::StmtKind::Decl(ref decl, _) => {
- let exit = self.decl(&decl, pred);
- self.add_ast_node(hir_id.local_id, &[exit])
- }
-
- hir::StmtKind::Expr(ref expr, _) |
- hir::StmtKind::Semi(ref expr, _) => {
- let exit = self.expr(&expr, pred);
- self.add_ast_node(hir_id.local_id, &[exit])
- }
- }
- }
-
- fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex {
- match decl.node {
- hir::DeclKind::Local(ref local) => {
+ let hir_id = self.tcx.hir().node_to_hir_id(stmt.id);
+ let exit = match stmt.node {
+ hir::StmtKind::Local(ref local) => {
let init_exit = self.opt_expr(&local.init, pred);
self.pat(&local.pat, init_exit)
}
-
- hir::DeclKind::Item(_) => pred,
- }
+ hir::StmtKind::Item(_) => {
+ pred
+ }
+ hir::StmtKind::Expr(ref expr) |
+ hir::StmtKind::Semi(ref expr) => {
+ self.expr(&expr, pred)
+ }
+ };
+ self.add_ast_node(hir_id.local_id, &[exit])
}
fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
-use errors::DiagnosticBuilder;
+use errors::{Diagnostic, DiagnosticBuilder};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use std::collections::hash_map::Entry;
use ty::{self, TyCtxt};
use util::common::{ProfileQueriesMsg, profq_msg};
+use parking_lot::{Mutex, Condvar};
use ich::{StableHashingContext, StableHashingContextProvider, Fingerprint};
colors: DepNodeColorMap,
+ /// A set of loaded diagnostics which has been emitted.
+ emitted_diagnostics: Mutex<FxHashSet<DepNodeIndex>>,
+
+ /// Used to wait for diagnostics to be emitted.
+ emitted_diagnostics_cond_var: Condvar,
+
/// When we load, there may be `.o` files, cached mir, or other such
/// things available to us. If we find that they are not dirty, we
/// load the path to the file storing those work-products here into
previous_work_products: prev_work_products,
dep_node_debug: Default::default(),
current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)),
+ emitted_diagnostics: Default::default(),
+ emitted_diagnostics_cond_var: Condvar::new(),
previous: prev_graph,
colors: DepNodeColorMap::new(prev_graph_node_count),
loaded_from_cache: Default::default(),
};
// ... emitting any stored diagnostic ...
- if did_allocation {
- // Only the thread which did the allocation emits the error messages
-
- // FIXME: Ensure that these are printed before returning for all threads.
- // Currently threads where did_allocation = false can continue on
- // and emit other diagnostics before these diagnostics are emitted.
- // Such diagnostics should be emitted after these.
- // See https://github.com/rust-lang/rust/issues/48685
- let diagnostics = tcx.queries.on_disk_cache
- .load_diagnostics(tcx, prev_dep_node_index);
- if diagnostics.len() > 0 {
- let handle = tcx.sess.diagnostic();
+ let diagnostics = tcx.queries.on_disk_cache
+ .load_diagnostics(tcx, prev_dep_node_index);
- // Promote the previous diagnostics to the current session.
- tcx.queries.on_disk_cache
- .store_diagnostics(dep_node_index, diagnostics.clone().into());
-
- for diagnostic in diagnostics {
- DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit();
- }
- }
+ if unlikely!(diagnostics.len() > 0) {
+ self.emit_diagnostics(
+ tcx,
+ data,
+ dep_node_index,
+ did_allocation,
+ diagnostics
+ );
}
// ... and finally storing a "Green" entry in the color map.
Some(dep_node_index)
}
+ /// Atomically emits some loaded diagnotics assuming that this only gets called with
+ /// did_allocation set to true on one thread
+ #[cold]
+ #[inline(never)]
+ fn emit_diagnostics<'tcx>(
+ &self,
+ tcx: TyCtxt<'_, 'tcx, 'tcx>,
+ data: &DepGraphData,
+ dep_node_index: DepNodeIndex,
+ did_allocation: bool,
+ diagnostics: Vec<Diagnostic>,
+ ) {
+ if did_allocation || !cfg!(parallel_queries) {
+ // Only the thread which did the allocation emits the error messages
+ let handle = tcx.sess.diagnostic();
+
+ // Promote the previous diagnostics to the current session.
+ tcx.queries.on_disk_cache
+ .store_diagnostics(dep_node_index, diagnostics.clone().into());
+
+ for diagnostic in diagnostics {
+ DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit();
+ }
+
+ #[cfg(parallel_queries)]
+ {
+ // Mark the diagnostics and emitted and wake up waiters
+ data.emitted_diagnostics.lock().insert(dep_node_index);
+ data.emitted_diagnostics_cond_var.notify_all();
+ }
+ } else {
+ // The other threads will wait for the diagnostics to be emitted
+
+ let mut emitted_diagnostics = data.emitted_diagnostics.lock();
+ loop {
+ if emitted_diagnostics.contains(&dep_node_index) {
+ break;
+ }
+ data.emitted_diagnostics_cond_var.wait(&mut emitted_diagnostics);
+ }
+ }
+ }
+
// Returns true if the given node has been marked as green during the
// current compilation session. Used in various assertions
pub fn is_green(&self, dep_node: &DepNode) -> bool {
fn check_stmt_attributes(&self, stmt: &hir::Stmt) {
// When checking statements ignore expressions, they will be checked later
- if let hir::StmtKind::Decl(_, _) = stmt.node {
- for attr in stmt.node.attrs() {
+ if let hir::StmtKind::Local(ref l) = stmt.node {
+ for attr in l.attrs.iter() {
if attr.check_name("inline") {
self.check_inline(attr, &stmt.span, Target::Statement);
}
fn visit_pat(&mut self, p: &'v Pat) {
walk_pat(self, p)
}
- fn visit_decl(&mut self, d: &'v Decl) {
- walk_decl(self, d)
- }
fn visit_anon_const(&mut self, c: &'v AnonConst) {
walk_anon_const(self, c)
}
}
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
+ visitor.visit_id(statement.id);
match statement.node {
- StmtKind::Decl(ref declaration, id) => {
- visitor.visit_id(id);
- visitor.visit_decl(declaration)
- }
- StmtKind::Expr(ref expression, id) |
- StmtKind::Semi(ref expression, id) => {
- visitor.visit_id(id);
+ StmtKind::Local(ref local) => visitor.visit_local(local),
+ StmtKind::Item(ref item) => visitor.visit_nested_item(**item),
+ StmtKind::Expr(ref expression) |
+ StmtKind::Semi(ref expression) => {
visitor.visit_expr(expression)
}
}
}
-pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
- match declaration.node {
- DeclKind::Local(ref local) => visitor.visit_local(local),
- DeclKind::Item(item) => visitor.visit_nested_item(item),
- }
-}
-
pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
visitor.visit_id(constant.id);
visitor.visit_nested_body(constant.body);
//! in the HIR, especially for multiple identifiers.
use dep_graph::DepGraph;
+use errors::Applicability;
use hir::{self, ParamName};
use hir::HirVec;
use hir::map::{DefKey, DefPathData, Definitions};
explicit_owner: Option<NodeId>,
) -> hir::PathSegment {
let (mut generic_args, infer_types) = if let Some(ref generic_args) = segment.args {
- let msg = "parenthesized parameters may only be used with a trait";
+ let msg = "parenthesized type parameters may only be used with a `Fn` trait";
match **generic_args {
GenericArgs::AngleBracketed(ref data) => {
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
(hir::GenericArgs::none(), true)
}
ParenthesizedGenericArgs::Err => {
- struct_span_err!(self.sess, data.span, E0214, "{}", msg)
- .span_label(data.span, "only traits may use parentheses")
- .emit();
- (hir::GenericArgs::none(), true)
+ let mut err = struct_span_err!(self.sess, data.span, E0214, "{}", msg);
+ err.span_label(data.span, "only `Fn` traits may use parentheses");
+ if let Ok(snippet) = self.sess.source_map().span_to_snippet(data.span) {
+ // Do not suggest going from `Trait()` to `Trait<>`
+ if data.inputs.len() > 0 {
+ err.span_suggestion_with_applicability(
+ data.span,
+ "use angle brackets instead",
+ format!("<{}>", &snippet[1..snippet.len() - 1]),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ };
+ err.emit();
+ (self.lower_angle_bracketed_parameter_data(
+ &data.as_angle_bracketed_args(),
+ param_mode,
+ itctx).0,
+ false)
}
},
}
fn lower_parenthesized_parameter_data(
&mut self,
- data: &ParenthesisedArgs,
+ data: &ParenthesizedArgs,
) -> (hir::GenericArgs, bool) {
// Switch to `PassThrough` mode for anonymous lifetimes: this
// means that we permit things like `&Ref<T>`, where `Ref` has
self.with_anonymous_lifetime_mode(
AnonymousLifetimeMode::PassThrough,
|this| {
- let &ParenthesisedArgs { ref inputs, ref output, span } = data;
+ let &ParenthesizedArgs { ref inputs, ref output, span } = data;
let inputs = inputs
.iter()
.map(|ty| this.lower_ty_direct(ty, ImplTraitContext::disallowed()))
)
}
- fn lower_local(&mut self, l: &Local) -> (P<hir::Local>, SmallVec<[hir::ItemId; 1]>) {
+ fn lower_local(&mut self, l: &Local) -> (hir::Local, SmallVec<[hir::ItemId; 1]>) {
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(l.id);
let mut ids = SmallVec::<[hir::ItemId; 1]>::new();
if self.sess.features_untracked().impl_trait_in_bindings {
}
}
let parent_def_id = DefId::local(self.current_hir_id_owner.last().unwrap().0);
- (P(hir::Local {
+ (hir::Local {
id: node_id,
hir_id,
ty: l.ty
span: l.span,
attrs: l.attrs.clone(),
source: hir::LocalSource::Normal,
- }), ids)
+ }, ids)
}
fn lower_mutability(&mut self, m: Mutability) -> hir::Mutability {
ThinVec::new(),
))
};
- let match_stmt = respan(
- head_sp,
- hir::StmtKind::Expr(match_expr, self.next_id().node_id)
- );
+ let match_stmt = hir::Stmt {
+ id: self.next_id().node_id,
+ node: hir::StmtKind::Expr(match_expr),
+ span: head_sp,
+ };
let next_expr = P(self.expr_ident(head_sp, next_ident, next_pat.id));
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 = respan(
- body.span,
- hir::StmtKind::Expr(body_expr, self.next_id().node_id)
- );
+ let body_stmt = hir::Stmt {
+ id: self.next_id().node_id,
+ node: hir::StmtKind::Expr(body_expr),
+ span: body.span,
+ };
let loop_block = P(self.block_all(
e.span,
let (l, item_ids) = self.lower_local(l);
let mut ids: SmallVec<[hir::Stmt; 1]> = item_ids
.into_iter()
- .map(|item_id| Spanned {
- node: hir::StmtKind::Decl(
- P(Spanned {
- node: hir::DeclKind::Item(item_id),
- span: s.span,
- }),
- self.next_id().node_id,
- ),
+ .map(|item_id| hir::Stmt {
+ id: self.next_id().node_id,
+ node: hir::StmtKind::Item(P(item_id)),
span: s.span,
})
.collect();
- ids.push(Spanned {
- node: hir::StmtKind::Decl(
- P(Spanned {
- node: hir::DeclKind::Local(l),
- span: s.span,
- }),
- self.lower_node_id(s.id).node_id,
- ),
+ ids.push(hir::Stmt {
+ id: self.lower_node_id(s.id).node_id,
+ node: hir::StmtKind::Local(P(l)),
span: s.span,
});
return ids;
let mut id = Some(s.id);
return self.lower_item_id(it)
.into_iter()
- .map(|item_id| Spanned {
- node: hir::StmtKind::Decl(
- P(Spanned {
- node: hir::DeclKind::Item(item_id),
- span: s.span,
- }),
- id.take()
+ .map(|item_id| hir::Stmt {
+ id: id.take()
.map(|id| self.lower_node_id(id).node_id)
.unwrap_or_else(|| self.next_id().node_id),
- ),
+ node: hir::StmtKind::Item(P(item_id)),
span: s.span,
})
.collect();
}
- StmtKind::Expr(ref e) => Spanned {
- node: hir::StmtKind::Expr(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id),
+ StmtKind::Expr(ref e) => hir::Stmt {
+ id: self.lower_node_id(s.id).node_id,
+ node: hir::StmtKind::Expr(P(self.lower_expr(e))),
span: s.span,
},
- StmtKind::Semi(ref e) => Spanned {
- node: hir::StmtKind::Semi(P(self.lower_expr(e)), self.lower_node_id(s.id).node_id),
+ StmtKind::Semi(ref e) => hir::Stmt {
+ id: self.lower_node_id(s.id).node_id,
+ node: hir::StmtKind::Semi(P(self.lower_expr(e))),
span: s.span,
},
StmtKind::Mac(..) => panic!("Shouldn't exist here"),
) -> hir::Stmt {
let LoweredNodeId { node_id, hir_id } = self.next_id();
- let local = P(hir::Local {
+ let local = hir::Local {
pat,
ty: None,
init: ex,
span: sp,
attrs: ThinVec::new(),
source,
- });
- let decl = respan(sp, hir::DeclKind::Local(local));
- respan(sp, hir::StmtKind::Decl(P(decl), self.next_id().node_id))
+ };
+ hir::Stmt {
+ id: self.next_id().node_id,
+ node: hir::StmtKind::Local(P(local)),
+ span: sp
+ }
}
fn stmt_let(
}
fn visit_stmt(&mut self, stmt: &'hir Stmt) {
- let id = stmt.node.id();
+ let id = stmt.id;
self.insert(stmt.span, id, Node::Stmt(stmt));
self.with_parent(id, |this| {
let def_data = match i.node {
ItemKind::Impl(..) => DefPathData::Impl,
ItemKind::Trait(..) => DefPathData::Trait(i.ident.as_interned_str()),
+ ItemKind::TraitAlias(..) => DefPathData::TraitAlias(i.ident.as_interned_str()),
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) |
- ItemKind::TraitAlias(..) | ItemKind::Existential(..) |
- ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) | ItemKind::Ty(..) =>
- DefPathData::TypeNs(i.ident.as_interned_str()),
+ ItemKind::Existential(..) | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) |
+ ItemKind::Ty(..) => DefPathData::TypeNs(i.ident.as_interned_str()),
ItemKind::Mod(..) if i.ident == keywords::Invalid.ident() => {
return visit::walk_item(self, i);
}
/// GlobalMetaData identifies a piece of crate metadata that is global to
/// a whole crate (as opposed to just one item). GlobalMetaData components
/// are only supposed to show up right below the crate root.
- GlobalMetaData(InternedString)
+ GlobalMetaData(InternedString),
+ /// A trait alias.
+ TraitAlias(InternedString),
}
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug,
match *self {
TypeNs(name) |
Trait(name) |
+ TraitAlias(name) |
AssocTypeInTrait(name) |
AssocTypeInImpl(name) |
AssocExistentialInImpl(name) |
let s = match *self {
TypeNs(name) |
Trait(name) |
+ TraitAlias(name) |
AssocTypeInTrait(name) |
AssocTypeInImpl(name) |
AssocExistentialInImpl(name) |
Node::AnonConst(_) => {
BodyOwnerKind::Const
}
+ Node::Variant(&Spanned { node: VariantKind { data: VariantData::Tuple(..), .. }, .. }) |
+ Node::StructCtor(..) |
+ Node::Item(&Item { node: ItemKind::Fn(..), .. }) |
+ Node::TraitItem(&TraitItem { node: TraitItemKind::Method(..), .. }) |
+ Node::ImplItem(&ImplItem { node: ImplItemKind::Method(..), .. }) => {
+ BodyOwnerKind::Fn
+ }
Node::Item(&Item { node: ItemKind::Static(_, m, _), .. }) => {
BodyOwnerKind::Static(m)
}
- // Default to function if it's not a constant or static.
- _ => BodyOwnerKind::Fn
+ Node::Expr(&Expr { node: ExprKind::Closure(..), .. }) => {
+ BodyOwnerKind::Closure
+ }
+ node => bug!("{:#?} is not a body node", node),
}
}
pub use self::UnOp::*;
pub use self::UnsafeSource::*;
+use errors::FatalError;
use hir::def::Def;
use hir::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX};
use util::nodemap::{NodeMap, FxHashSet};
use mir::mono::Linkage;
use syntax_pos::{Span, DUMMY_SP, symbol::InternedString};
-use syntax::source_map::{self, Spanned};
+use syntax::source_map::Spanned;
use rustc_target::spec::abi::Abi;
use syntax::ast::{self, CrateSugar, Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Label, Lit, StrStyle, FloatTy, IntTy, UintTy};
}
/// A statement
-pub type Stmt = Spanned<StmtKind>;
+#[derive(Clone, RustcEncodable, RustcDecodable)]
+pub struct Stmt {
+ pub id: NodeId,
+ pub node: StmtKind,
+ pub span: Span,
+}
-impl fmt::Debug for StmtKind {
+impl fmt::Debug for Stmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // Sadness.
- let spanned = source_map::dummy_spanned(self.clone());
- write!(f,
- "stmt({}: {})",
- spanned.node.id(),
- print::to_string(print::NO_ANN, |s| s.print_stmt(&spanned)))
+ write!(f, "stmt({}: {})", self.id,
+ print::to_string(print::NO_ANN, |s| s.print_stmt(self)))
}
}
#[derive(Clone, RustcEncodable, RustcDecodable)]
pub enum StmtKind {
- /// Could be an item or a local (let) binding:
- Decl(P<Decl>, NodeId),
+ /// A local (let) binding:
+ Local(P<Local>),
+ /// An item binding:
+ Item(P<ItemId>),
/// Expr without trailing semi-colon (must have unit type):
- Expr(P<Expr>, NodeId),
+ Expr(P<Expr>),
/// Expr with trailing semi-colon (may have any type):
- Semi(P<Expr>, NodeId),
+ Semi(P<Expr>),
}
impl StmtKind {
pub fn attrs(&self) -> &[Attribute] {
match *self {
- StmtKind::Decl(ref d, _) => d.node.attrs(),
- StmtKind::Expr(ref e, _) |
- StmtKind::Semi(ref e, _) => &e.attrs,
- }
- }
-
- pub fn id(&self) -> NodeId {
- match *self {
- StmtKind::Decl(_, id) |
- StmtKind::Expr(_, id) |
- StmtKind::Semi(_, id) => id,
+ StmtKind::Local(ref l) => &l.attrs,
+ StmtKind::Item(_) => &[],
+ StmtKind::Expr(ref e) |
+ StmtKind::Semi(ref e) => &e.attrs,
}
}
}
pub source: LocalSource,
}
-pub type Decl = Spanned<DeclKind>;
-
-#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub enum DeclKind {
- /// A local (let) binding:
- Local(P<Local>),
- /// An item binding:
- Item(ItemId),
-}
-
-impl DeclKind {
- pub fn attrs(&self) -> &[Attribute] {
- match *self {
- DeclKind::Local(ref l) => &l.attrs,
- DeclKind::Item(_) => &[]
- }
- }
-
- pub fn is_local(&self) -> bool {
- match *self {
- DeclKind::Local(_) => true,
- _ => false,
- }
- }
-}
-
/// represents one arm of a 'match'
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Arm {
/// Functions and methods.
Fn,
+ /// Closures
+ Closure,
+
/// Constants and associated constants.
Const,
Static(Mutability),
}
+impl BodyOwnerKind {
+ pub fn is_fn_or_closure(self) -> bool {
+ match self {
+ BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
+ BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false,
+ }
+ }
+}
+
/// 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)
pub hir_ref_id: HirId,
}
+impl TraitRef {
+ /// Get the `DefId` of the referenced trait. It _must_ actually be a trait or trait alias.
+ pub fn trait_def_id(&self) -> DefId {
+ match self.path.def {
+ Def::Trait(did) => did,
+ Def::TraitAlias(did) => did,
+ Def::Err => {
+ FatalError.raise();
+ }
+ _ => unreachable!(),
+ }
+ }
+}
+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct PolyTraitRef {
/// The `'a` in `<'a> Foo<&'a T>`
pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
self.maybe_print_comment(st.span.lo())?;
match st.node {
- hir::StmtKind::Decl(ref decl, _) => {
- self.print_decl(&decl)?;
+ hir::StmtKind::Local(ref loc) => {
+ self.space_if_not_bol()?;
+ self.ibox(indent_unit)?;
+ self.word_nbsp("let")?;
+
+ self.ibox(indent_unit)?;
+ self.print_local_decl(&loc)?;
+ self.end()?;
+ if let Some(ref init) = loc.init {
+ self.nbsp()?;
+ self.word_space("=")?;
+ self.print_expr(&init)?;
+ }
+ self.end()?
+ }
+ hir::StmtKind::Item(ref item) => {
+ self.ann.nested(self, Nested::Item(**item))?
}
- hir::StmtKind::Expr(ref expr, _) => {
+ hir::StmtKind::Expr(ref expr) => {
self.space_if_not_bol()?;
self.print_expr(&expr)?;
}
- hir::StmtKind::Semi(ref expr, _) => {
+ hir::StmtKind::Semi(ref expr) => {
self.space_if_not_bol()?;
self.print_expr(&expr)?;
self.s.word(";")?;
Ok(())
}
- pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> {
- self.maybe_print_comment(decl.span.lo())?;
- match decl.node {
- hir::DeclKind::Local(ref loc) => {
- self.space_if_not_bol()?;
- self.ibox(indent_unit)?;
- self.word_nbsp("let")?;
-
- self.ibox(indent_unit)?;
- self.print_local_decl(&loc)?;
- self.end()?;
- if let Some(ref init) = loc.init {
- self.nbsp()?;
- self.word_space("=")?;
- self.print_expr(&init)?;
- }
- self.end()
- }
- hir::DeclKind::Item(item) => {
- self.ann.nested(self, Nested::Item(item))
- }
- }
- }
-
pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
self.s.word(i.to_string())
}
/// seen the semicolon, and thus don't need another.
fn stmt_ends_with_semi(stmt: &hir::StmtKind) -> bool {
match *stmt {
- hir::StmtKind::Decl(ref d, _) => {
- match d.node {
- hir::DeclKind::Local(_) => true,
- hir::DeclKind::Item(_) => false,
- }
- }
- hir::StmtKind::Expr(ref e, _) => {
- expr_requires_semi_to_be_stmt(&e)
- }
- hir::StmtKind::Semi(..) => {
- false
- }
+ hir::StmtKind::Local(_) => true,
+ hir::StmtKind::Item(_) => false,
+ hir::StmtKind::Expr(ref e) => expr_requires_semi_to_be_stmt(&e),
+ hir::StmtKind::Semi(..) => false,
}
}
UnNeg
});
-impl_stable_hash_for_spanned!(hir::StmtKind);
+impl_stable_hash_for!(struct hir::Stmt {
+ id,
+ node,
+ span,
+});
+
impl_stable_hash_for!(struct hir::Local {
pat,
source
});
-impl_stable_hash_for_spanned!(hir::DeclKind);
-impl_stable_hash_for!(enum hir::DeclKind {
- Local(local),
- Item(item_id)
-});
-
impl_stable_hash_for!(struct hir::Arm {
attrs,
pats,
});
impl_stable_hash_for!(enum hir::StmtKind {
- Decl(decl, id),
- Expr(expr, id),
- Semi(expr, id)
+ Local(local),
+ Item(item_id),
+ Expr(expr),
+ Semi(expr)
});
impl_stable_hash_for!(struct hir::Arg {
impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
impl_stable_hash_for!(enum ::syntax::ast::LitKind {
Str(value, style),
+ Err(value),
ByteStr(value),
Byte(value),
Char(value),
tokenstream::TokenTree::Delimited(span, delim, ref tts) => {
span.hash_stable(hcx, hasher);
std_hash::Hash::hash(&delim, hasher);
- for sub_tt in tts.stream().trees() {
+ for sub_tt in tts.trees() {
sub_tt.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) |
}
}
- fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) {
+ fn note_error_origin(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ cause: &ObligationCause<'tcx>,
+ exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
+ ) {
match cause.code {
ObligationCauseCode::MatchExpressionArmPattern { span, ty } => {
if ty.is_suggestable() { // don't show type `_`
err.span_label(span, format!("this match expression has type `{}`", ty));
}
+ if let Some(ty::error::ExpectedFound { found, .. }) = exp_found {
+ if ty.is_box() && ty.boxed_ty() == found {
+ if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
+ err.span_suggestion_with_applicability(
+ span,
+ "consider dereferencing the boxed value",
+ format!("*{}", snippet),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
}
ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
hir::MatchSource::IfLetDesugar { .. } => {
// It reads better to have the error origin as the final
// thing.
- self.note_error_origin(diag, &cause);
+ self.note_error_origin(diag, &cause, exp_found);
}
/// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate,
-# Skolemization and functions
+To learn more about how Higher-ranked trait bounds work in the _old_ trait
+solver, see [this chapter][oldhrtb] of the rustc-guide.
-One of the trickiest and most subtle aspects of regions is dealing
-with higher-ranked things which include bound region variables, such
-as function types. I strongly suggest that if you want to understand
-the situation, you read this paper (which is, admittedly, very long,
-but you don't have to read the whole thing):
+To learn more about how they work in the _new_ trait solver, see [this
+chapter][newhrtb].
-http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/
-
-Although my explanation will never compete with SPJ's (for one thing,
-his is approximately 100 pages), I will attempt to explain the basic
-problem and also how we solve it. Note that the paper only discusses
-subtyping, not the computation of LUB/GLB.
-
-The problem we are addressing is that there is a kind of subtyping
-between functions with bound region parameters. Consider, for
-example, whether the following relation holds:
-
- for<'a> fn(&'a isize) <: for<'b> fn(&'b isize)? (Yes, a => b)
-
-The answer is that of course it does. These two types are basically
-the same, except that in one we used the name `a` and one we used
-the name `b`.
-
-In the examples that follow, it becomes very important to know whether
-a lifetime is bound in a function type (that is, is a lifetime
-parameter) or appears free (is defined in some outer scope).
-Therefore, from now on I will always write the bindings explicitly,
-using the Rust syntax `for<'a> fn(&'a isize)` to indicate that `a` is a
-lifetime parameter.
-
-Now let's consider two more function types. Here, we assume that the
-`'b` lifetime is defined somewhere outside and hence is not a lifetime
-parameter bound by the function type (it "appears free"):
-
- for<'a> fn(&'a isize) <: fn(&'b isize)? (Yes, a => b)
-
-This subtyping relation does in fact hold. To see why, you have to
-consider what subtyping means. One way to look at `T1 <: T2` is to
-say that it means that it is always ok to treat an instance of `T1` as
-if it had the type `T2`. So, with our functions, it is always ok to
-treat a function that can take pointers with any lifetime as if it
-were a function that can only take a pointer with the specific
-lifetime `'b`. After all, `'b` is a lifetime, after all, and
-the function can take values of any lifetime.
-
-You can also look at subtyping as the *is a* relationship. This amounts
-to the same thing: a function that accepts pointers with any lifetime
-*is a* function that accepts pointers with some specific lifetime.
-
-So, what if we reverse the order of the two function types, like this:
-
- fn(&'b isize) <: for<'a> fn(&'a isize)? (No)
-
-Does the subtyping relationship still hold? The answer of course is
-no. In this case, the function accepts *only the lifetime `'b`*,
-so it is not reasonable to treat it as if it were a function that
-accepted any lifetime.
-
-What about these two examples:
-
- for<'a,'b> fn(&'a isize, &'b isize) <: for<'a> fn(&'a isize, &'a isize)? (Yes)
- for<'a> fn(&'a isize, &'a isize) <: for<'a,'b> fn(&'a isize, &'b isize)? (No)
-
-Here, it is true that functions which take two pointers with any two
-lifetimes can be treated as if they only accepted two pointers with
-the same lifetime, but not the reverse.
-
-## The algorithm
-
-Here is the algorithm we use to perform the subtyping check:
-
-1. Replace all bound regions in the subtype with new variables
-2. Replace all bound regions in the supertype with placeholder
- equivalents. A "placeholder" region is just a new fresh region
- name.
-3. Check that the parameter and return types match as normal
-4. Ensure that no placeholder regions 'leak' into region variables
- visible from "the outside"
-
-Let's walk through some examples and see how this algorithm plays out.
-
-#### First example
-
-We'll start with the first example, which was:
-
- 1. for<'a> fn(&'a T) <: for<'b> fn(&'b T)? Yes: a -> b
-
-After steps 1 and 2 of the algorithm we will have replaced the types
-like so:
-
- 1. fn(&'A T) <: fn(&'x T)?
-
-Here the upper case `&A` indicates a *region variable*, that is, a
-region whose value is being inferred by the system. I also replaced
-`&b` with `&x`---I'll use letters late in the alphabet (`x`, `y`, `z`)
-to indicate placeholder region names. We can assume they don't appear
-elsewhere. Note that neither the sub- nor the supertype bind any
-region names anymore (as indicated by the absence of `<` and `>`).
-
-The next step is to check that the parameter types match. Because
-parameters are contravariant, this means that we check whether:
-
- &'x T <: &'A T
-
-Region pointers are contravariant so this implies that
-
- &A <= &x
-
-must hold, where `<=` is the subregion relationship. Processing
-*this* constrain simply adds a constraint into our graph that `&A <=
-&x` and is considered successful (it can, for example, be satisfied by
-choosing the value `&x` for `&A`).
-
-So far we have encountered no error, so the subtype check succeeds.
-
-#### The third example
-
-Now let's look first at the third example, which was:
-
- 3. fn(&'a T) <: for<'b> fn(&'b T)? No!
-
-After steps 1 and 2 of the algorithm we will have replaced the types
-like so:
-
- 3. fn(&'a T) <: fn(&'x T)?
-
-This looks pretty much the same as before, except that on the LHS
-`'a` was not bound, and hence was left as-is and not replaced with
-a variable. The next step is again to check that the parameter types
-match. This will ultimately require (as before) that `'a` <= `&x`
-must hold: but this does not hold. `self` and `x` are both distinct
-free regions. So the subtype check fails.
-
-#### Checking for placeholder leaks
-
-You may be wondering about that mysterious last step in the algorithm.
-So far it has not been relevant. The purpose of that last step is to
-catch something like *this*:
-
- for<'a> fn() -> fn(&'a T) <: fn() -> for<'b> fn(&'b T)? No.
-
-Here the function types are the same but for where the binding occurs.
-The subtype returns a function that expects a value in precisely one
-region. The supertype returns a function that expects a value in any
-region. If we allow an instance of the subtype to be used where the
-supertype is expected, then, someone could call the fn and think that
-the return value has type `fn<b>(&'b T)` when it really has type
-`fn(&'a T)` (this is case #3, above). Bad.
-
-So let's step through what happens when we perform this subtype check.
-We first replace the bound regions in the subtype (the supertype has
-no bound regions). This gives us:
-
- fn() -> fn(&'A T) <: fn() -> for<'b> fn(&'b T)?
-
-Now we compare the return types, which are covariant, and hence we have:
-
- fn(&'A T) <: for<'b> fn(&'b T)?
-
-Here we replace the bound region in the supertype with a placeholder to yield:
-
- fn(&'A T) <: fn(&'x T)?
-
-And then proceed to compare the argument types:
-
- &'x T <: &'A T
- 'A <= 'x
-
-Finally, this is where it gets interesting! This is where an error
-*should* be reported. But in fact this will not happen. The reason why
-is that `A` is a variable: we will infer that its value is the fresh
-region `x` and think that everything is happy. In fact, this behavior
-is *necessary*, it was key to the first example we walked through.
-
-The difference between this example and the first one is that the variable
-`A` already existed at the point where the placeholders were added. In
-the first example, you had two functions:
-
- for<'a> fn(&'a T) <: for<'b> fn(&'b T)
-
-and hence `&A` and `&x` were created "together". In general, the
-intention of the placeholder names is that they are supposed to be
-fresh names that could never be equal to anything from the outside.
-But when inference comes into play, we might not be respecting this
-rule.
-
-So the way we solve this is to add a fourth step that examines the
-constraints that refer to placeholder names. Basically, consider a
-non-directed version of the constraint graph. Let `Tainted(x)` be the
-set of all things reachable from a placeholder variable `x`.
-`Tainted(x)` should not contain any regions that existed before the
-step at which the placeholders were created. So this case here
-would fail because `&x` was created alone, but is relatable to `&A`.
-
-## Computing the LUB and GLB
-
-The paper I pointed you at is written for Haskell. It does not
-therefore considering subtyping and in particular does not consider
-LUB or GLB computation. We have to consider this. Here is the
-algorithm I implemented.
-
-First though, let's discuss what we are trying to compute in more
-detail. The LUB is basically the "common supertype" and the GLB is
-"common subtype"; one catch is that the LUB should be the
-*most-specific* common supertype and the GLB should be *most general*
-common subtype (as opposed to any common supertype or any common
-subtype).
-
-Anyway, to help clarify, here is a table containing some function
-pairs and their LUB/GLB (for conciseness, in this table, I'm just
-including the lifetimes here, not the rest of the types, and I'm
-writing `fn<>` instead of `for<> fn`):
-
-```
-Type 1 Type 2 LUB GLB
-fn<'a>('a) fn('X) fn('X) fn<'a>('a)
-fn('a) fn('X) -- fn<'a>('a)
-fn<'a,'b>('a, 'b) fn<'x>('x, 'x) fn<'a>('a, 'a) fn<'a,'b>('a, 'b)
-fn<'a,'b>('a, 'b, 'a) fn<'x,'y>('x, 'y, 'y) fn<'a>('a, 'a, 'a) fn<'a,'b,'c>('a,'b,'c)
-```
-
-### Conventions
-
-I use lower-case letters (e.g., `&a`) for bound regions and upper-case
-letters for free regions (`&A`). Region variables written with a
-dollar-sign (e.g., `$a`). I will try to remember to enumerate the
-bound-regions on the fn type as well (e.g., `for<'a> fn(&a)`).
-
-### High-level summary
-
-Both the LUB and the GLB algorithms work in a similar fashion. They
-begin by replacing all bound regions (on both sides) with fresh region
-inference variables. Therefore, both functions are converted to types
-that contain only free regions. We can then compute the LUB/GLB in a
-straightforward way, as described in `combine.rs`. This results in an
-interim type T. The algorithms then examine the regions that appear
-in T and try to, in some cases, replace them with bound regions to
-yield the final result.
-
-To decide whether to replace a region `R` that appears in `T` with
-a bound region, the algorithms make use of two bits of
-information. First is a set `V` that contains all region
-variables created as part of the LUB/GLB computation (roughly; see
-`region_vars_confined_to_snapshot()` for full details). `V` will
-contain the region variables created to replace the bound regions
-in the input types, but it also contains 'intermediate' variables
-created to represent the LUB/GLB of individual regions.
-Basically, when asked to compute the LUB/GLB of a region variable
-with another region, the inferencer cannot oblige immediately
-since the values of that variables are not known. Therefore, it
-creates a new variable that is related to the two regions. For
-example, the LUB of two variables `$x` and `$y` is a fresh
-variable `$z` that is constrained such that `$x <= $z` and `$y <=
-$z`. So `V` will contain these intermediate variables as well.
-
-The other important factor in deciding how to replace a region in T is
-the function `Tainted($r)` which, for a region variable, identifies
-all regions that the region variable is related to in some way
-(`Tainted()` made an appearance in the subtype computation as well).
-
-### LUB
-
-The LUB algorithm proceeds in three steps:
-
-1. Replace all bound regions (on both sides) with fresh region
- inference variables.
-2. Compute the LUB "as normal", meaning compute the GLB of each
- pair of argument types and the LUB of the return types and
- so forth. Combine those to a new function type `F`.
-3. Replace each region `R` that appears in `F` as follows:
- - Let `V` be the set of variables created during the LUB
- computational steps 1 and 2, as described in the previous section.
- - If `R` is not in `V`, replace `R` with itself.
- - If `Tainted(R)` contains a region that is not in `V`,
- replace `R` with itself.
- - Otherwise, select the earliest variable in `Tainted(R)` that originates
- from the left-hand side and replace `R` with the bound region that
- this variable was a replacement for.
-
-So, let's work through the simplest example: `fn(&A)` and `for<'a> fn(&a)`.
-In this case, `&a` will be replaced with `$a` and the interim LUB type
-`fn($b)` will be computed, where `$b=GLB(&A,$a)`. Therefore, `V =
-{$a, $b}` and `Tainted($b) = { $b, $a, &A }`. When we go to replace
-`$b`, we find that since `&A \in Tainted($b)` is not a member of `V`,
-we leave `$b` as is. When region inference happens, `$b` will be
-resolved to `&A`, as we wanted.
-
-Let's look at a more complex one: `fn(&a, &b)` and `fn(&x, &x)`. In
-this case, we'll end up with a (pre-replacement) LUB type of `fn(&g,
-&h)` and a graph that looks like:
-
-```
- $a $b *--$x
- \ \ / /
- \ $h-* /
- $g-----------*
-```
-
-Here `$g` and `$h` are fresh variables that are created to represent
-the LUB/GLB of things requiring inference. This means that `V` and
-`Tainted` will look like:
-
-```
-V = {$a, $b, $g, $h, $x}
-Tainted($g) = Tainted($h) = { $a, $b, $h, $g, $x }
-```
-
-Therefore we replace both `$g` and `$h` with `$a`, and end up
-with the type `fn(&a, &a)`.
-
-### GLB
-
-The procedure for computing the GLB is similar. The difference lies
-in computing the replacements for the various variables. For each
-region `R` that appears in the type `F`, we again compute `Tainted(R)`
-and examine the results:
-
-1. If `R` is not in `V`, it is not replaced.
-2. Else, if `Tainted(R)` contains only variables in `V`, and it
- contains exactly one variable from the LHS and one variable from
- the RHS, then `R` can be mapped to the bound version of the
- variable from the LHS.
-3. Else, if `Tainted(R)` contains no variable from the LHS and no
- variable from the RHS, then `R` can be mapped to itself.
-4. Else, `R` is mapped to a fresh bound variable.
-
-These rules are pretty complex. Let's look at some examples to see
-how they play out.
-
-Out first example was `fn(&a)` and `fn(&X)`. In this case, `&a` will
-be replaced with `$a` and we will ultimately compute a
-(pre-replacement) GLB type of `fn($g)` where `$g=LUB($a,&X)`.
-Therefore, `V={$a,$g}` and `Tainted($g)={$g,$a,&X}. To find the
-replacement for `$g` we consult the rules above:
-- Rule (1) does not apply because `$g \in V`
-- Rule (2) does not apply because `&X \in Tainted($g)`
-- Rule (3) does not apply because `$a \in Tainted($g)`
-- Hence, by rule (4), we replace `$g` with a fresh bound variable `&z`.
-So our final result is `fn(&z)`, which is correct.
-
-The next example is `fn(&A)` and `fn(&Z)`. In this case, we will again
-have a (pre-replacement) GLB of `fn(&g)`, where `$g = LUB(&A,&Z)`.
-Therefore, `V={$g}` and `Tainted($g) = {$g, &A, &Z}`. In this case,
-by rule (3), `$g` is mapped to itself, and hence the result is
-`fn($g)`. This result is correct (in this case, at least), but it is
-indicative of a case that *can* lead us into concluding that there is
-no GLB when in fact a GLB does exist. See the section "Questionable
-Results" below for more details.
-
-The next example is `fn(&a, &b)` and `fn(&c, &c)`. In this case, as
-before, we'll end up with `F=fn($g, $h)` where `Tainted($g) =
-Tainted($h) = {$g, $h, $a, $b, $c}`. Only rule (4) applies and hence
-we'll select fresh bound variables `y` and `z` and wind up with
-`fn(&y, &z)`.
-
-For the last example, let's consider what may seem trivial, but is
-not: `fn(&a, &a)` and `fn(&b, &b)`. In this case, we'll get `F=fn($g,
-$h)` where `Tainted($g) = {$g, $a, $x}` and `Tainted($h) = {$h, $a,
-$x}`. Both of these sets contain exactly one bound variable from each
-side, so we'll map them both to `&a`, resulting in `fn(&a, &a)`, which
-is the desired result.
-
-### Shortcomings and correctness
-
-You may be wondering whether this algorithm is correct. The answer is
-"sort of". There are definitely cases where they fail to compute a
-result even though a correct result exists. I believe, though, that
-if they succeed, then the result is valid, and I will attempt to
-convince you. The basic argument is that the "pre-replacement" step
-computes a set of constraints. The replacements, then, attempt to
-satisfy those constraints, using bound identifiers where needed.
-
-For now I will briefly go over the cases for LUB/GLB and identify
-their intent:
-
-- LUB:
- - The region variables that are substituted in place of bound regions
- are intended to collect constraints on those bound regions.
- - If Tainted(R) contains only values in V, then this region is unconstrained
- and can therefore be generalized, otherwise it cannot.
-- GLB:
- - The region variables that are substituted in place of bound regions
- are intended to collect constraints on those bound regions.
- - If Tainted(R) contains exactly one variable from each side, and
- only variables in V, that indicates that those two bound regions
- must be equated.
- - Otherwise, if Tainted(R) references any variables from left or right
- side, then it is trying to combine a bound region with a free one or
- multiple bound regions, so we need to select fresh bound regions.
-
-Sorry this is more of a shorthand to myself. I will try to write up something
-more convincing in the future.
-
-#### Where are the algorithms wrong?
-
-- The pre-replacement computation can fail even though using a
- bound-region would have succeeded.
-- We will compute GLB(fn(fn($a)), fn(fn($b))) as fn($c) where $c is the
- GLB of $a and $b. But if inference finds that $a and $b must be mapped
- to regions without a GLB, then this is effectively a failure to compute
- the GLB. However, the result `fn<$c>(fn($c))` is a valid GLB.
+[oldhrtb]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html
+[newhrtb]: https://rust-lang.github.io/rustc-guide/borrow_check/region_inference.html#placeholders-and-universes
> WARNING: This README is obsolete and will be removed soon! For
> more info on how the current borrowck works, see the [rustc guide].
+>
+> As of edition 2018, region inference is done using Non-lexical lifetimes,
+> which is described in the guide and [this RFC].
[rustc guide]: https://rust-lang.github.io/rustc-guide/mir/borrowck.html
+[this RFC]: https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md
## Terminology
}
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
- self.iterate_until_fixed_point("Expansion", |constraint, origin| {
- debug!("expansion: constraint={:?} origin={:?}", constraint, origin);
- match *constraint {
+ self.iterate_until_fixed_point("Expansion", |constraint| {
+ debug!("expansion: constraint={:?}", constraint);
+ let (a_region, b_vid, b_data, retain) = match *constraint {
Constraint::RegSubVar(a_region, b_vid) => {
let b_data = var_values.value_mut(b_vid);
- (self.expand_node(a_region, b_vid, b_data), false)
+ (a_region, b_vid, b_data, false)
}
Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
- VarValue::ErrorValue => (false, false),
+ VarValue::ErrorValue => return (false, false),
VarValue::Value(a_region) => {
- let b_node = var_values.value_mut(b_vid);
- let changed = self.expand_node(a_region, b_vid, b_node);
- let retain = match *b_node {
+ let b_data = var_values.value_mut(b_vid);
+ let retain = match *b_data {
VarValue::Value(ReStatic) | VarValue::ErrorValue => false,
_ => true
};
- (changed, retain)
+ (a_region, b_vid, b_data, retain)
}
},
Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
// These constraints are checked after expansion
// is done, in `collect_errors`.
- (false, false)
+ return (false, false)
}
- }
+ };
+
+ let changed = self.expand_node(a_region, b_vid, b_data);
+ (changed, retain)
})
}
+ // This function is very hot in some workloads. There's a single callsite
+ // so always inlining is ok even though it's large.
+ #[inline(always)]
fn expand_node(
&self,
a_region: Region<'tcx>,
match *b_data {
VarValue::Value(cur_region) => {
+ // Identical scopes can show up quite often, if the fixed point
+ // iteration converges slowly, skip them
+ if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) {
+ if a_scope == cur_scope {
+ return false;
+ }
+ }
+
let mut lub = self.lub_concrete_regions(a_region, cur_region);
if lub == cur_region {
return false;
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
let tcx = self.tcx();
- // Equal scopes can show up quite often, if the fixed point
- // iteration converges slowly, skip them
- if a == b {
- return a;
- }
-
match (a, b) {
(&ty::ReClosureBound(..), _)
| (_, &ty::ReClosureBound(..))
}
fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
- where
- F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> (bool, bool),
+ where F: FnMut(&Constraint<'tcx>) -> (bool, bool),
{
- let mut constraints: SmallVec<[_; 16]> = self.data.constraints.iter().collect();
+ let mut constraints: SmallVec<[_; 16]> = self.data.constraints.keys().collect();
let mut iteration = 0;
let mut changed = true;
while changed {
changed = false;
iteration += 1;
debug!("---- {} Iteration {}{}", "#", tag, iteration);
- constraints.retain(|(constraint, origin)| {
- let (edge_changed, retain) = body(constraint, origin);
+ constraints.retain(|constraint| {
+ let (edge_changed, retain) = body(constraint);
if edge_changed {
debug!("Updated due to constraint {:?}", constraint);
changed = true;
-# Region constraint collection
-
-> WARNING: This README is obsolete and will be removed soon! For
-> more info on how the current borrowck works, see the [rustc guide].
+For info on how the current borrowck works, see the [rustc guide].
[rustc guide]: https://rust-lang.github.io/rustc-guide/mir/borrowck.html
-
-## Terminology
-
-Note that we use the terms region and lifetime interchangeably.
-
-## Introduction
-
-As described in the rustc guide [chapter on type inference][ti], and unlike
-normal type inference, which is similar in spirit to H-M and thus
-works progressively, the region type inference works by accumulating
-constraints over the course of a function. Finally, at the end of
-processing a function, we process and solve the constraints all at
-once.
-
-[ti]: https://rust-lang.github.io/rustc-guide/type-inference.html
-
-The constraints are always of one of three possible forms:
-
-- `ConstrainVarSubVar(Ri, Rj)` states that region variable Ri must be
- a subregion of Rj
-- `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which
- must not be a variable) must be a subregion of the variable Ri
-- `ConstrainVarSubReg(Ri, R)` states the variable Ri should be less
- than the concrete region R. This is kind of deprecated and ought to
- be replaced with a verify (they essentially play the same role).
-
-In addition to constraints, we also gather up a set of "verifys"
-(what, you don't think Verify is a noun? Get used to it my
-friend!). These represent relations that must hold but which don't
-influence inference proper. These take the form of:
-
-- `VerifyRegSubReg(Ri, Rj)` indicates that Ri <= Rj must hold,
- where Rj is not an inference variable (and Ri may or may not contain
- one). This doesn't influence inference because we will already have
- inferred Ri to be as small as possible, so then we just test whether
- that result was less than Rj or not.
-- `VerifyGenericBound(R, Vb)` is a more complex expression which tests
- that the region R must satisfy the bound `Vb`. The bounds themselves
- may have structure like "must outlive one of the following regions"
- or "must outlive ALL of the following regions. These bounds arise
- from constraints like `T: 'a` -- if we know that `T: 'b` and `T: 'c`
- (say, from where clauses), then we can conclude that `T: 'a` if `'b:
- 'a` *or* `'c: 'a`.
-
-## Building up the constraints
-
-Variables and constraints are created using the following methods:
-
-- `new_region_var()` creates a new, unconstrained region variable;
-- `make_subregion(Ri, Rj)` states that Ri is a subregion of Rj
-- `lub_regions(Ri, Rj) -> Rk` returns a region Rk which is
- the smallest region that is greater than both Ri and Rj
-- `glb_regions(Ri, Rj) -> Rk` returns a region Rk which is
- the greatest region that is smaller than both Ri and Rj
-
-The actual region resolution algorithm is not entirely
-obvious, though it is also not overly complex.
-
-## Snapshotting
-
-It is also permitted to try (and rollback) changes to the graph. This
-is done by invoking `start_snapshot()`, which returns a value. Then
-later you can call `rollback_to()` which undoes the work.
-Alternatively, you can call `commit()` which ends all snapshots.
-Snapshots can be recursive---so you can start a snapshot when another
-is in progress, but only the root snapshot can "commit".
-
-## Skolemization
-
-For a discussion on skolemization and higher-ranked subtyping, please
-see the module `middle::infer::higher_ranked::doc`.
#![feature(nll)]
#![feature(non_exhaustive)]
#![feature(proc_macro_internals)]
-#![feature(quote)]
#![feature(optin_builtin_traits)]
#![feature(refcell_replace_swap)]
#![feature(rustc_diagnostic_macros)]
hir_visit::walk_arm(self, a);
}
- fn visit_decl(&mut self, d: &'tcx hir::Decl) {
- run_lints!(self, check_decl, d);
- hir_visit::walk_decl(self, d);
- }
-
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) {
run_lints!(self, check_generic_param, p);
hir_visit::walk_generic_param(self, p);
fn check_stmt(a: &$hir hir::Stmt);
fn check_arm(a: &$hir hir::Arm);
fn check_pat(a: &$hir hir::Pat);
- fn check_decl(a: &$hir hir::Decl);
fn check_expr(a: &$hir hir::Expr);
fn check_expr_post(a: &$hir hir::Expr);
fn check_ty(a: &$hir hir::Ty);
fn walk_stmt(&mut self, stmt: &hir::Stmt) {
match stmt.node {
- hir::StmtKind::Decl(ref decl, _) => {
- match decl.node {
- hir::DeclKind::Local(ref local) => {
- self.walk_local(&local);
- }
+ hir::StmtKind::Local(ref local) => {
+ self.walk_local(&local);
+ }
- hir::DeclKind::Item(_) => {
- // we don't visit nested items in this visitor,
- // only the fn body we were given.
- }
- }
+ hir::StmtKind::Item(_) => {
+ // we don't visit nested items in this visitor,
+ // only the fn body we were given.
}
- hir::StmtKind::Expr(ref expr, _) |
- hir::StmtKind::Semi(ref expr, _) => {
+ hir::StmtKind::Expr(ref expr) |
+ hir::StmtKind::Semi(ref expr) => {
self.consume_expr(&expr);
}
}
fn propagate_through_stmt(&mut self, stmt: &hir::Stmt, succ: LiveNode)
-> LiveNode {
match stmt.node {
- hir::StmtKind::Decl(ref decl, _) => {
- self.propagate_through_decl(&decl, succ)
- }
+ hir::StmtKind::Local(ref local) => {
+ // Note: we mark the variable as defined regardless of whether
+ // there is an initializer. Initially I had thought to only mark
+ // the live variable as defined if it was initialized, and then we
+ // could check for uninit variables just by scanning what is live
+ // at the start of the function. But that doesn't work so well for
+ // immutable variables defined in a loop:
+ // loop { let x; x = 5; }
+ // because the "assignment" loops back around and generates an error.
+ //
+ // So now we just check that variables defined w/o an
+ // initializer are not live at the point of their
+ // initialization, which is mildly more complex than checking
+ // once at the func header but otherwise equivalent.
- hir::StmtKind::Expr(ref expr, _) | hir::StmtKind::Semi(ref expr, _) => {
- self.propagate_through_expr(&expr, succ)
+ let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
+ self.define_bindings_in_pat(&local.pat, succ)
}
- }
- }
-
- fn propagate_through_decl(&mut self, decl: &hir::Decl, succ: LiveNode)
- -> LiveNode {
- match decl.node {
- hir::DeclKind::Local(ref local) => {
- self.propagate_through_local(&local, succ)
+ hir::StmtKind::Item(..) => succ,
+ hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => {
+ self.propagate_through_expr(&expr, succ)
}
- hir::DeclKind::Item(_) => succ,
}
}
- fn propagate_through_local(&mut self, local: &hir::Local, succ: LiveNode)
- -> LiveNode {
- // Note: we mark the variable as defined regardless of whether
- // there is an initializer. Initially I had thought to only mark
- // the live variable as defined if it was initialized, and then we
- // could check for uninit variables just by scanning what is live
- // at the start of the function. But that doesn't work so well for
- // immutable variables defined in a loop:
- // loop { let x; x = 5; }
- // because the "assignment" loops back around and generates an error.
- //
- // So now we just check that variables defined w/o an
- // initializer are not live at the point of their
- // initialization, which is mildly more complex than checking
- // once at the func header but otherwise equivalent.
-
- let succ = self.propagate_through_opt_expr(local.init.as_ref().map(|e| &**e), succ);
- self.define_bindings_in_pat(&local.pat, succ)
- }
-
fn propagate_through_exprs(&mut self, exprs: &[Expr], succ: LiveNode)
-> LiveNode {
exprs.iter().rev().fold(succ, |succ, expr| {
// index information.)
for (i, statement) in blk.stmts.iter().enumerate() {
- if let hir::StmtKind::Decl(..) = statement.node {
- // Each StmtKind::Decl introduces a subscope for bindings
- // introduced by the declaration; this subscope covers
- // a suffix of the block . Each subscope in a block
- // has the previous subscope in the block as a parent,
- // except for the first such subscope, which has the
- // block itself as a parent.
- visitor.enter_scope(
- Scope {
- id: blk.hir_id.local_id,
- data: ScopeData::Remainder(FirstStatementIndex::new(i))
- }
- );
- visitor.cx.var_parent = visitor.cx.parent;
+ match statement.node {
+ hir::StmtKind::Local(..) |
+ hir::StmtKind::Item(..) => {
+ // Each declaration introduces a subscope for bindings
+ // introduced by the declaration; this subscope covers a
+ // suffix of the block. Each subscope in a block has the
+ // previous subscope in the block as a parent, except for
+ // the first such subscope, which has the block itself as a
+ // parent.
+ visitor.enter_scope(
+ Scope {
+ id: blk.hir_id.local_id,
+ data: ScopeData::Remainder(FirstStatementIndex::new(i))
+ }
+ );
+ visitor.cx.var_parent = visitor.cx.parent;
+ }
+ hir::StmtKind::Expr(..) |
+ hir::StmtKind::Semi(..) => {}
}
visitor.visit_stmt(statement)
}
}
fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
- let stmt_id = visitor.tcx.hir().node_to_hir_id(stmt.node.id()).local_id;
+ let stmt_id = visitor.tcx.hir().node_to_hir_id(stmt.id).local_id;
debug!("resolve_stmt(stmt.id={:?})", stmt_id);
// Every statement will clean up the temporaries created during
// The body of the every fn is a root scope.
self.cx.parent = self.cx.var_parent;
- if let hir::BodyOwnerKind::Fn = self.tcx.hir().body_owner_kind(owner_id) {
- self.visit_expr(&body.value);
+ if self.tcx.hir().body_owner_kind(owner_id).is_fn_or_closure() {
+ self.visit_expr(&body.value)
} else {
// Only functions have an outer terminating (drop) scope, while
// temporaries in constant initializers may be 'static, but only
unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
"Present the input source, unstable (and less-pretty) variants;
valid types are any of the types for `--pretty`, as well as:
+ `expanded`, `expanded,identified`,
+ `expanded,hygiene` (with internal representations),
`flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
+ `flowgraph,unlabelled=<nodeid>` (unlabelled graphviz formatted flowgraph for node),
`everybody_loops` (all function bodies replaced with `loop {}`),
- `hir` (the HIR), `hir,identified`, or
- `hir,typed` (HIR with types for each node)."),
+ `hir` (the HIR), `hir,identified`,
+ `hir,typed` (HIR with types for each node),
+ `hir-tree` (dump the raw HIR),
+ `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"),
run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
"run `dsymutil` and delete intermediate object files"),
ui_testing: bool = (false, parse_bool, [UNTRACKED],
}
fn report_similar_impl_candidates(&self,
- mut impl_candidates: Vec<ty::TraitRef<'tcx>>,
+ impl_candidates: Vec<ty::TraitRef<'tcx>>,
err: &mut DiagnosticBuilder<'_>)
{
if impl_candidates.is_empty() {
});
// Sort impl candidates so that ordering is consistent for UI tests.
- let normalized_impl_candidates = &mut impl_candidates[0..end]
+ let mut normalized_impl_candidates = impl_candidates
.iter()
.map(normalize)
.collect::<Vec<String>>();
+
+ // Sort before taking the `..end` range,
+ // because the ordering of `impl_candidates` may not be deterministic:
+ // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
normalized_impl_candidates.sort();
err.help(&format!("the following implementations were found:{}{}",
- normalized_impl_candidates.join(""),
+ normalized_impl_candidates[..end].join(""),
if len > 5 {
format!("\nand {} others", len - 4)
} else {
let def_id = obligation.predicate.def_id();
- if ty::is_trait_alias(self.tcx(), def_id) {
+ if self.tcx().is_trait_alias(def_id) {
candidates.vec.push(TraitAliasCandidate(def_id.clone()));
}
let visible_parent = visible_parent_map.get(&cur_def).cloned();
let actual_parent = self.parent(cur_def);
- debug!(
- "try_push_visible_item_path: visible_parent={:?} actual_parent={:?}",
- visible_parent, actual_parent,
- );
let data = cur_def_key.disambiguated_data.data;
+ debug!(
+ "try_push_visible_item_path: data={:?} visible_parent={:?} actual_parent={:?}",
+ data, visible_parent, actual_parent,
+ );
let symbol = match data {
// In order to output a path that could actually be imported (valid and visible),
// we need to handle re-exports correctly.
// the children of the visible parent (as was done when computing
// `visible_parent_map`), looking for the specific child we currently have and then
// have access to the re-exported name.
- DefPathData::Module(module_name) if visible_parent != actual_parent => {
- let mut name: Option<ast::Ident> = None;
- if let Some(visible_parent) = visible_parent {
- for child in self.item_children(visible_parent).iter() {
- if child.def.def_id() == cur_def {
- name = Some(child.ident);
- }
- }
- }
- name.map(|n| n.as_str()).unwrap_or(module_name.as_str())
+ DefPathData::Module(actual_name) |
+ DefPathData::TypeNs(actual_name) if visible_parent != actual_parent => {
+ visible_parent
+ .and_then(|parent| {
+ self.item_children(parent)
+ .iter()
+ .find(|child| child.def.def_id() == cur_def)
+ .map(|child| child.ident.as_str())
+ })
+ .unwrap_or_else(|| actual_name.as_str())
},
_ => {
data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| {
data @ DefPathData::Misc |
data @ DefPathData::TypeNs(..) |
data @ DefPathData::Trait(..) |
+ data @ DefPathData::TraitAlias(..) |
data @ DefPathData::AssocTypeInTrait(..) |
data @ DefPathData::AssocTypeInImpl(..) |
data @ DefPathData::AssocExistentialInImpl(..) |
None
}
-/// Returns `true` if `def_id` is a trait alias.
-pub fn is_trait_alias(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> bool {
- if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
- if let Node::Item(item) = tcx.hir().get(node_id) {
- if let hir::ItemKind::TraitAlias(..) = item.node {
- return true;
- }
- }
- }
- false
-}
-
/// See `ParamEnv` struct definition for details.
fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-# The Rust Compiler Query System
-
-The Compiler Query System is the key to our new demand-driven
-organization. The idea is pretty simple. You have various queries
-that compute things about the input -- for example, there is a query
-called `type_of(def_id)` that, given the def-id of some item, will
-compute the type of that item and return it to you.
-
-Query execution is **memoized** -- so the first time you invoke a
-query, it will go do the computation, but the next time, the result is
-returned from a hashtable. Moreover, query execution fits nicely into
-**incremental computation**; the idea is roughly that, when you do a
-query, the result **may** be returned to you by loading stored data
-from disk (but that's a separate topic we won't discuss further here).
-
-The overall vision is that, eventually, the entire compiler
-control-flow will be query driven. There will effectively be one
-top-level query ("compile") that will run compilation on a crate; this
-will in turn demand information about that crate, starting from the
-*end*. For example:
-
-- This "compile" query might demand to get a list of codegen-units
- (i.e., modules that need to be compiled by LLVM).
-- But computing the list of codegen-units would invoke some subquery
- that returns the list of all modules defined in the Rust source.
-- That query in turn would invoke something asking for the HIR.
-- This keeps going further and further back until we wind up doing the
- actual parsing.
-
-However, that vision is not fully realized. Still, big chunks of the
-compiler (for example, generating MIR) work exactly like this.
-
-### Invoking queries
-
-To invoke a query is simple. The tcx ("type context") offers a method
-for each defined query. So, for example, to invoke the `type_of`
-query, you would just do this:
-
-```rust
-let ty = tcx.type_of(some_def_id);
-```
-
-### Cycles between queries
-
-Currently, cycles during query execution should always result in a
-compilation error. Typically, they arise because of illegal programs
-that contain cyclic references they shouldn't (though sometimes they
-arise because of compiler bugs, in which case we need to factor our
-queries in a more fine-grained fashion to avoid them).
-
-However, it is nonetheless often useful to *recover* from a cycle
-(after reporting an error, say) and try to soldier on, so as to give a
-better user experience. In order to recover from a cycle, you don't
-get to use the nice method-call-style syntax. Instead, you invoke
-using the `try_get` method, which looks roughly like this:
-
-```rust
-use ty::query::queries;
-...
-match queries::type_of::try_get(tcx, DUMMY_SP, self.did) {
- Ok(result) => {
- // no cycle occurred! You can use `result`
- }
- Err(err) => {
- // A cycle occurred! The error value `err` is a `DiagnosticBuilder`,
- // meaning essentially an "in-progress", not-yet-reported error message.
- // See below for more details on what to do here.
- }
-}
-```
-
-So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that
-you must ensure that a compiler error message is reported. You can do that in two ways:
-
-The simplest is to invoke `err.emit()`. This will emit the cycle error to the user.
-
-However, often cycles happen because of an illegal program, and you
-know at that point that an error either already has been reported or
-will be reported due to this cycle by some other bit of code. In that
-case, you can invoke `err.cancel()` to not emit any error. It is
-traditional to then invoke:
-
-```
-tcx.sess.delay_span_bug(some_span, "some message")
-```
-
-`delay_span_bug()` is a helper that says: we expect a compilation
-error to have happened or to happen in the future; so, if compilation
-ultimately succeeds, make an ICE with the message `"some
-message"`. This is basically just a precaution in case you are wrong.
-
-### How the compiler executes a query
-
-So you may be wondering what happens when you invoke a query
-method. The answer is that, for each query, the compiler maintains a
-cache -- if your query has already been executed, then, the answer is
-simple: we clone the return value out of the cache and return it
-(therefore, you should try to ensure that the return types of queries
-are cheaply cloneable; insert a `Rc` if necessary).
-
-#### Providers
-
-If, however, the query is *not* in the cache, then the compiler will
-try to find a suitable **provider**. A provider is a function that has
-been defined and linked into the compiler somewhere that contains the
-code to compute the result of the query.
-
-**Providers are defined per-crate.** The compiler maintains,
-internally, a table of providers for every crate, at least
-conceptually. Right now, there are really two sets: the providers for
-queries about the **local crate** (that is, the one being compiled)
-and providers for queries about **external crates** (that is,
-dependencies of the local crate). Note that what determines the crate
-that a query is targeting is not the *kind* of query, but the *key*.
-For example, when you invoke `tcx.type_of(def_id)`, that could be a
-local query or an external query, depending on what crate the `def_id`
-is referring to (see the `self::keys::Key` trait for more information
-on how that works).
-
-Providers always have the same signature:
-
-```rust
-fn provider<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx, 'tcx>,
- key: QUERY_KEY)
- -> QUERY_RESULT
-{
- ...
-}
-```
-
-Providers take two arguments: the `tcx` and the query key. Note also
-that they take the *global* tcx (i.e., they use the `'tcx` lifetime
-twice), rather than taking a tcx with some active inference context.
-They return the result of the query.
-
-#### How providers are setup
-
-When the tcx is created, it is given the providers by its creator using
-the `Providers` struct. This struct is generate by the macros here, but it
-is basically a big list of function pointers:
-
-```rust
-struct Providers {
- type_of: for<'cx, 'tcx> fn(TyCtxt<'cx, 'tcx, 'tcx>, DefId) -> Ty<'tcx>,
- ...
-}
-```
-
-At present, we have one copy of the struct for local crates, and one
-for external crates, though the plan is that we may eventually have
-one per crate.
-
-These `Provider` structs are ultimately created and populated by
-`librustc_driver`, but it does this by distributing the work
-throughout the other `rustc_*` crates. This is done by invoking
-various `provide` functions. These functions tend to look something
-like this:
-
-```rust
-pub fn provide(providers: &mut Providers) {
- *providers = Providers {
- type_of,
- ..*providers
- };
-}
-```
-
-That is, they take an `&mut Providers` and mutate it in place. Usually
-we use the formulation above just because it looks nice, but you could
-as well do `providers.type_of = type_of`, which would be equivalent.
-(Here, `type_of` would be a top-level function, defined as we saw
-before.) So, if we want to add a provider for some other query,
-let's call it `fubar`, into the crate above, we might modify the `provide()`
-function like so:
-
-```rust
-pub fn provide(providers: &mut Providers) {
- *providers = Providers {
- type_of,
- fubar,
- ..*providers
- };
-}
-
-fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. }
-```
-
-NB. Most of the `rustc_*` crates only provide **local
-providers**. Almost all **extern providers** wind up going through the
-`rustc_metadata` crate, which loads the information from the crate
-metadata. But in some cases there are crates that provide queries for
-*both* local and external crates, in which case they define both a
-`provide` and a `provide_extern` function that `rustc_driver` can
-invoke.
-
-### Adding a new kind of query
-
-So suppose you want to add a new kind of query, how do you do so?
-Well, defining a query takes place in two steps:
-
-1. first, you have to specify the query name and arguments; and then,
-2. you have to supply query providers where needed.
-
-To specify the query name and arguments, you simply add an entry
-to the big macro invocation in `mod.rs`. This will probably have changed
-by the time you read this README, but at present it looks something
-like:
-
-```
-define_queries! { <'tcx>
- /// Records the type of every item.
- [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>,
-
- ...
-}
-```
-
-Each line of the macro defines one query. The name is broken up like this:
-
-```
-[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>,
-^^ ^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^
-| | | | |
-| | | | result type of query
-| | | query key type
-| | dep-node constructor
-| name of query
-query flags
-```
-
-Let's go over them one by one:
-
-- **Query flags:** these are largely unused right now, but the intention
- is that we'll be able to customize various aspects of how the query is
- processed.
-- **Name of query:** the name of the query method
- (`tcx.type_of(..)`). Also used as the name of a struct
- (`ty::query::queries::type_of`) that will be generated to represent
- this query.
-- **Dep-node constructor:** indicates the constructor function that
- connects this query to incremental compilation. Typically, this is a
- `DepNode` variant, which can be added by modifying the
- `define_dep_nodes!` macro invocation in
- `librustc/dep_graph/dep_node.rs`.
- - However, sometimes we use a custom function, in which case the
- name will be in snake case and the function will be defined at the
- bottom of the file. This is typically used when the query key is
- not a def-id, or just not the type that the dep-node expects.
-- **Query key type:** the type of the argument to this query.
- This type must implement the `ty::query::keys::Key` trait, which
- defines (for example) how to map it to a crate, and so forth.
-- **Result type of query:** the type produced by this query. This type
- should (a) not use `RefCell` or other interior mutability and (b) be
- cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for
- non-trivial data types.
- - The one exception to those rules is the `ty::steal::Steal` type,
- which is used to cheaply modify MIR in place. See the definition
- of `Steal` for more details. New uses of `Steal` should **not** be
- added without alerting `@rust-lang/compiler`.
-
-So, to add a query:
-
-- Add an entry to `define_queries!` using the format above.
-- Possibly add a corresponding entry to the dep-node macro.
-- Link the provider by modifying the appropriate `provide` method;
- or add a new one if needed and ensure that `rustc_driver` is invoking it.
-
-#### Query structs and descriptions
-
-For each kind, the `define_queries` macro will generate a "query struct"
-named after the query. This struct is a kind of a place-holder
-describing the query. Each such struct implements the
-`self::config::QueryConfig` trait, which has associated types for the
-key/value of that particular query. Basically the code generated looks something
-like this:
-
-```rust
-// Dummy struct representing a particular kind of query:
-pub struct type_of<'tcx> { phantom: PhantomData<&'tcx ()> }
-
-impl<'tcx> QueryConfig for type_of<'tcx> {
- type Key = DefId;
- type Value = Ty<'tcx>;
-}
-```
-
-There is an additional trait that you may wish to implement called
-`self::config::QueryDescription`. This trait is used during cycle
-errors to give a "human readable" name for the query, so that we can
-summarize what was happening when the cycle occurred. Implementing
-this trait is optional if the query key is `DefId`, but if you *don't*
-implement it, you get a pretty generic error ("processing `foo`...").
-You can put new impls into the `config` module. They look something like this:
-
-```rust
-impl<'tcx> QueryDescription for queries::type_of<'tcx> {
- fn describe(tcx: TyCtxt<'_, '_, '_>, key: DefId) -> String {
- format!("computing the type of `{}`", tcx.item_path_str(key))
- }
-}
-```
+For more information about how the query system works, see the [rustc guide].
+[rustc guide]: https://rust-lang.github.io/rustc-guide/query.html
}
}
+ /// True if `def_id` refers to a trait alias (i.e., `trait Foo = ...;`).
+ pub fn is_trait_alias(self, def_id: DefId) -> bool {
+ if let DefPathData::TraitAlias(_) = self.def_key(def_id).disambiguated_data.data {
+ true
+ } else {
+ false
+ }
+ }
+
/// True if this def-id refers to the implicit constructor for
/// a tuple struct like `struct Foo(u32)`.
pub fn is_struct_constructor(self, def_id: DefId) -> bool {
DefPathData::AssocTypeInImpl(_) |
DefPathData::AssocExistentialInImpl(_) |
DefPathData::Trait(_) |
+ DefPathData::TraitAlias(_) |
DefPathData::Impl |
DefPathData::TypeNs(_) => {
break;
#![allow(non_camel_case_types)]
#![feature(nll)]
-#![feature(quote)]
#![recursion_limit="256"]
// On MSVC we have to use the fallback mode, because LLVM doesn't
// lower variant parts to PDB.
return cx.sess().target.target.options.is_like_msvc
- || llvm_util::get_major_version() < 7;
+ // LLVM version 7 did not release with an important bug fix;
+ // but the required patch is in the LLVM 8. Rust LLVM reports
+ // 8 as well.
+ || llvm_util::get_major_version() < 8;
}
// Describes the members of an enum value: An enum is described as a union of
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
}
+ if name == "simd_bitmask" {
+ // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
+ // vector mask and returns an unsigned integer containing the most
+ // significant bit (MSB) of each lane.
+ use rustc_target::abi::HasDataLayout;
+
+ // If the vector has less than 8 lanes, an u8 is returned with zeroed
+ // trailing bits.
+ let expected_int_bits = in_len.max(8);
+ match ret_ty.sty {
+ ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (),
+ _ => return_error!(
+ "bitmask `{}`, expected `u{}`",
+ ret_ty, expected_int_bits
+ ),
+ }
+
+ // Integer vector <i{in_bitwidth} x in_len>:
+ let (i_xn, in_elem_bitwidth) = match in_elem.sty {
+ ty::Int(i) => (
+ args[0].immediate(),
+ i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits() as _)
+ ),
+ ty::Uint(i) => (
+ args[0].immediate(),
+ i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits() as _)
+ ),
+ _ => return_error!(
+ "vector argument `{}`'s element type `{}`, expected integer element type",
+ in_ty, in_elem
+ ),
+ };
+
+ // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
+ let shift_indices = vec![
+ bx.cx.const_int(bx.type_ix(in_elem_bitwidth as _), (in_elem_bitwidth - 1) as _); in_len
+ ];
+ let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice()));
+ // Truncate vector to an <i1 x N>
+ let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len as _));
+ // Bitcast <i1 x N> to iN:
+ let i_ = bx.bitcast(i1xn, bx.type_ix(in_len as _));
+ // Zero-extend iN to the bitmask type:
+ return Ok(bx.zext(i_, bx.type_ix(expected_int_bits as _)));
+ }
+
fn simd_simple_float_intrinsic(
name: &str,
in_elem: &::rustc::ty::TyS,
#![allow(unused_attributes)]
#![feature(libc)]
#![feature(nll)]
-#![feature(quote)]
#![feature(range_contains)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
ty::Str => {
let mut name = String::with_capacity(32);
let printer = DefPathBasedNames::new(cx.tcx, true, true);
- printer.push_type_name(layout.ty, &mut name);
+ printer.push_type_name(layout.ty, &mut name, false);
if let (&ty::Adt(def, _), &layout::Variants::Single { index })
= (&layout.ty.sty, &layout.variants)
{
// For now we just never have an entry symbol
cmd.arg("--no-entry");
- // Make the default table accessible
- cmd.arg("--export-table");
-
// Rust code should never have warnings, and warnings are often
// indicative of bugs, let's prevent them.
cmd.arg("--fatal-warnings");
#![feature(nll)]
#![allow(unused_attributes)]
#![allow(dead_code)]
-#![feature(quote)]
#![recursion_limit="256"]
let field = const_field(
bx.tcx(),
ty::ParamEnv::reveal_all(),
- self.instance,
None,
mir::Field::new(field as usize),
c,
pub trait MonoItemExt<'a, 'tcx: 'a>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> {
fn define<Bx: BuilderMethods<'a, 'tcx>>(&self, cx: &'a Bx::CodegenCx) {
debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
- self.to_string(cx.tcx()),
+ self.to_string(cx.tcx(), true),
self.to_raw_string(),
cx.codegen_unit().name());
}
debug!("END IMPLEMENTING '{} ({})' in cgu {}",
- self.to_string(cx.tcx()),
+ self.to_string(cx.tcx(), true),
self.to_raw_string(),
cx.codegen_unit().name());
}
visibility: Visibility
) {
debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
- self.to_string(cx.tcx()),
+ self.to_string(cx.tcx(), true),
self.to_raw_string(),
cx.codegen_unit().name());
}
debug!("END PREDEFINING '{} ({})' in cgu {}",
- self.to_string(cx.tcx()),
+ self.to_string(cx.tcx(), true),
self.to_raw_string(),
cx.codegen_unit().name());
}
#![feature(custom_attribute)]
#![feature(nll)]
#![allow(unused_attributes)]
-#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
+++ /dev/null
-The `ObligationForest` is a utility data structure used in trait
-matching to track the set of outstanding obligations (those not yet
-resolved to success or error). It also tracks the "backtrace" of each
-pending obligation (why we are trying to figure this out in the first
-place).
-
-### External view
-
-`ObligationForest` supports two main public operations (there are a
-few others not discussed here):
-
-1. Add a new root obligations (`push_tree`).
-2. Process the pending obligations (`process_obligations`).
-
-When a new obligation `N` is added, it becomes the root of an
-obligation tree. This tree can also carry some per-tree state `T`,
-which is given at the same time. This tree is a singleton to start, so
-`N` is both the root and the only leaf. Each time the
-`process_obligations` method is called, it will invoke its callback
-with every pending obligation (so that will include `N`, the first
-time). The callback also receives a (mutable) reference to the
-per-tree state `T`. The callback should process the obligation `O`
-that it is given and return one of three results:
-
-- `Ok(None)` -> ambiguous result. Obligation was neither a success
- nor a failure. It is assumed that further attempts to process the
- obligation will yield the same result unless something in the
- surrounding environment changes.
-- `Ok(Some(C))` - the obligation was *shallowly successful*. The
- vector `C` is a list of subobligations. The meaning of this is that
- `O` was successful on the assumption that all the obligations in `C`
- are also successful. Therefore, `O` is only considered a "true"
- success if `C` is empty. Otherwise, `O` is put into a suspended
- state and the obligations in `C` become the new pending
- obligations. They will be processed the next time you call
- `process_obligations`.
-- `Err(E)` -> obligation failed with error `E`. We will collect this
- error and return it from `process_obligations`, along with the
- "backtrace" of obligations (that is, the list of obligations up to
- and including the root of the failed obligation). No further
- obligations from that same tree will be processed, since the tree is
- now considered to be in error.
-
-When the call to `process_obligations` completes, you get back an `Outcome`,
-which includes three bits of information:
-
-- `completed`: a list of obligations where processing was fully
- completed without error (meaning that all transitive subobligations
- have also been completed). So, for example, if the callback from
- `process_obligations` returns `Ok(Some(C))` for some obligation `O`,
- then `O` will be considered completed right away if `C` is the
- empty vector. Otherwise it will only be considered completed once
- all the obligations in `C` have been found completed.
-- `errors`: a list of errors that occurred and associated backtraces
- at the time of error, which can be used to give context to the user.
-- `stalled`: if true, then none of the existing obligations were
- *shallowly successful* (that is, no callback returned `Ok(Some(_))`).
- This implies that all obligations were either errors or returned an
- ambiguous result, which means that any further calls to
- `process_obligations` would simply yield back further ambiguous
- results. This is used by the `FulfillmentContext` to decide when it
- has reached a steady state.
-
-#### Snapshots
-
-The `ObligationForest` supports a limited form of snapshots; see
-`start_snapshot`; `commit_snapshot`; and `rollback_snapshot`. In
-particular, you can use a snapshot to roll back new root
-obligations. However, it is an error to attempt to
-`process_obligations` during a snapshot.
-
-### Implementation details
-
-For the most part, comments specific to the implementation are in the
-code. This file only contains a very high-level overview. Basically,
-the forest is stored in a vector. Each element of the vector is a node
-in some tree. Each node in the vector has the index of an (optional)
-parent and (for convenience) its root (which may be itself). It also
-has a current state, described by `NodeState`. After each
-processing step, we compress the vector to remove completed and error
-nodes, which aren't needed anymore.
//! The `ObligationForest` is a utility data structure used in trait
-//! matching to track the set of outstanding obligations (those not
-//! yet resolved to success or error). It also tracks the "backtrace"
-//! of each pending obligation (why we are trying to figure this out
-//! in the first place). See README.md for a general overview of how
-//! to use this class.
+//! matching to track the set of outstanding obligations (those not yet
+//! resolved to success or error). It also tracks the "backtrace" of each
+//! pending obligation (why we are trying to figure this out in the first
+//! place).
+//!
+//! ### External view
+//!
+//! `ObligationForest` supports two main public operations (there are a
+//! few others not discussed here):
+//!
+//! 1. Add a new root obligations (`push_tree`).
+//! 2. Process the pending obligations (`process_obligations`).
+//!
+//! When a new obligation `N` is added, it becomes the root of an
+//! obligation tree. This tree can also carry some per-tree state `T`,
+//! which is given at the same time. This tree is a singleton to start, so
+//! `N` is both the root and the only leaf. Each time the
+//! `process_obligations` method is called, it will invoke its callback
+//! with every pending obligation (so that will include `N`, the first
+//! time). The callback also receives a (mutable) reference to the
+//! per-tree state `T`. The callback should process the obligation `O`
+//! that it is given and return one of three results:
+//!
+//! - `Ok(None)` -> ambiguous result. Obligation was neither a success
+//! nor a failure. It is assumed that further attempts to process the
+//! obligation will yield the same result unless something in the
+//! surrounding environment changes.
+//! - `Ok(Some(C))` - the obligation was *shallowly successful*. The
+//! vector `C` is a list of subobligations. The meaning of this is that
+//! `O` was successful on the assumption that all the obligations in `C`
+//! are also successful. Therefore, `O` is only considered a "true"
+//! success if `C` is empty. Otherwise, `O` is put into a suspended
+//! state and the obligations in `C` become the new pending
+//! obligations. They will be processed the next time you call
+//! `process_obligations`.
+//! - `Err(E)` -> obligation failed with error `E`. We will collect this
+//! error and return it from `process_obligations`, along with the
+//! "backtrace" of obligations (that is, the list of obligations up to
+//! and including the root of the failed obligation). No further
+//! obligations from that same tree will be processed, since the tree is
+//! now considered to be in error.
+//!
+//! When the call to `process_obligations` completes, you get back an `Outcome`,
+//! which includes three bits of information:
+//!
+//! - `completed`: a list of obligations where processing was fully
+//! completed without error (meaning that all transitive subobligations
+//! have also been completed). So, for example, if the callback from
+//! `process_obligations` returns `Ok(Some(C))` for some obligation `O`,
+//! then `O` will be considered completed right away if `C` is the
+//! empty vector. Otherwise it will only be considered completed once
+//! all the obligations in `C` have been found completed.
+//! - `errors`: a list of errors that occurred and associated backtraces
+//! at the time of error, which can be used to give context to the user.
+//! - `stalled`: if true, then none of the existing obligations were
+//! *shallowly successful* (that is, no callback returned `Ok(Some(_))`).
+//! This implies that all obligations were either errors or returned an
+//! ambiguous result, which means that any further calls to
+//! `process_obligations` would simply yield back further ambiguous
+//! results. This is used by the `FulfillmentContext` to decide when it
+//! has reached a steady state.
+//!
+//! #### Snapshots
+//!
+//! The `ObligationForest` supports a limited form of snapshots; see
+//! `start_snapshot`; `commit_snapshot`; and `rollback_snapshot`. In
+//! particular, you can use a snapshot to roll back new root
+//! obligations. However, it is an error to attempt to
+//! `process_obligations` during a snapshot.
+//!
+//! ### Implementation details
+//!
+//! For the most part, comments specific to the implementation are in the
+//! code. This file only contains a very high-level overview. Basically,
+//! the forest is stored in a vector. Each element of the vector is a node
+//! in some tree. Each node in the vector has the index of an (optional)
+//! parent and (for convenience) its root (which may be itself). It also
+//! has a current state, described by `NodeState`. After each
+//! processing step, we compress the vector to remove completed and error
+//! nodes, which aren't needed anymore.
use fx::{FxHashMap, FxHashSet};
crate_loader,
&resolver_arenas,
);
- syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote);
+ syntax_ext::register_builtins(&mut resolver, syntax_exts);
// Expand all macros
sess.profiler(|p| p.start_activity(ProfileCategory::Expansion));
#![feature(box_syntax)]
#![cfg_attr(unix, feature(libc))]
#![feature(nll)]
-#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(set_stdio)]
sess.fatal(&format!("argument to `unpretty` must be one of `normal`, \
`expanded`, `flowgraph[,unlabelled]=<nodeid>`, \
`identified`, `expanded,identified`, `everybody_loops`, \
- `hir`, `hir,identified`, `hir,typed`, or `mir`; got {}",
+ `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
+ `mir` or `mir-cfg`; got {}",
name));
} else {
sess.fatal(&format!("argument to `pretty` must be one of `normal`, `expanded`, \
/// it easy to declare such methods on the builder.
macro_rules! forward {
// Forward pattern for &self -> &Self
- (pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self) => {
+ (
+ $(#[$attrs:meta])*
+ pub fn $n:ident(&self, $($name:ident: $ty:ty),* $(,)*) -> &Self
+ ) => {
+ $(#[$attrs])*
pub fn $n(&self, $($name: $ty),*) -> &Self {
#[allow(deprecated)]
self.diagnostic.$n($($name),*);
};
// Forward pattern for &mut self -> &mut Self
- (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self) => {
+ (
+ $(#[$attrs:meta])*
+ pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)*) -> &mut Self
+ ) => {
+ $(#[$attrs])*
pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
#[allow(deprecated)]
self.diagnostic.$n($($name),*);
// Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan>
// type parameter. No obvious way to make this more generic.
- (pub fn $n:ident<S: Into<MultiSpan>>(
- &mut self,
- $($name:ident: $ty:ty),*
- $(,)*) -> &mut Self) => {
+ (
+ $(#[$attrs:meta])*
+ pub fn $n:ident<S: Into<MultiSpan>>(
+ &mut self,
+ $($name:ident: $ty:ty),*
+ $(,)*
+ ) -> &mut Self
+ ) => {
+ $(#[$attrs])*
pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self {
#[allow(deprecated)]
self.diagnostic.$n($($name),*);
msg: &str,
) -> &mut Self);
- #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
- forward!(pub fn span_suggestion_short(
- &mut self,
- sp: Span,
- msg: &str,
- suggestion: String,
- ) -> &mut Self);
-
- #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
- forward!(pub fn multipart_suggestion(
- &mut self,
- msg: &str,
- suggestion: Vec<(Span, String)>,
- ) -> &mut Self);
-
- #[deprecated(note = "Use `span_suggestion_with_applicability`")]
- forward!(pub fn span_suggestion(&mut self,
- sp: Span,
- msg: &str,
- suggestion: String,
- ) -> &mut Self);
-
- #[deprecated(note = "Use `span_suggestions_with_applicability`")]
- forward!(pub fn span_suggestions(&mut self,
- sp: Span,
- msg: &str,
- suggestions: Vec<String>,
- ) -> &mut Self);
+ forward!(
+ #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
+ pub fn span_suggestion_short(
+ &mut self,
+ sp: Span,
+ msg: &str,
+ suggestion: String,
+ ) -> &mut Self
+ );
+
+ forward!(
+ #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
+ pub fn multipart_suggestion(
+ &mut self,
+ msg: &str,
+ suggestion: Vec<(Span, String)>,
+ ) -> &mut Self
+ );
+
+ forward!(
+ #[deprecated(note = "Use `span_suggestion_with_applicability`")]
+ pub fn span_suggestion(
+ &mut self,
+ sp: Span,
+ msg: &str,
+ suggestion: String,
+ ) -> &mut Self
+ );
+
+ forward!(
+ #[deprecated(note = "Use `span_suggestions_with_applicability`")]
+ pub fn span_suggestions(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestions: Vec<String>,
+ ) -> &mut Self
+ );
pub fn multipart_suggestion_with_applicability(&mut self,
msg: &str,
Style::MainHeaderMsg
};
- if msp.primary_spans().is_empty() && msp.span_labels().is_empty() && is_secondary
+ if !msp.has_primary_spans() && !msp.has_span_labels() && is_secondary
&& !self.short_message {
// This is a secondary message with no span info
for _ in 0..max_line_num_len {
_ => {},
}
TokenTree::Delimited(_, _, tts) => {
- self.check_tokens(cx, tts.stream())
+ self.check_tokens(cx, tts)
},
}
}
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(nll)]
-#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
let expr = match s.node {
- hir::StmtKind::Semi(ref expr, _) => &**expr,
+ hir::StmtKind::Semi(ref expr) => &**expr,
_ => return,
};
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for PathStatements {
fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
- if let hir::StmtKind::Semi(ref expr, _) = s.node {
+ if let hir::StmtKind::Semi(ref expr) = s.node {
if let hir::ExprKind::Path(_) = expr.node {
cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
}
EntryKind::Mod(_) => Def::Mod(did),
EntryKind::Variant(_) => Def::Variant(did),
EntryKind::Trait(_) => Def::Trait(did),
+ EntryKind::TraitAlias(_) => Def::TraitAlias(did),
EntryKind::Enum(..) => Def::Enum(did),
EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang),
EntryKind::ForeignType => Def::ForeignTy(did),
}
pub fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
- let data = match self.entry(item_id).kind {
- EntryKind::Trait(data) => data.decode((self, sess)),
- _ => bug!(),
- };
-
- ty::TraitDef::new(self.local_def_id(item_id),
- data.unsafety,
- data.paren_sugar,
- data.has_auto_impl,
- data.is_marker,
- self.def_path_table.def_path_hash(item_id))
+ match self.entry(item_id).kind {
+ EntryKind::Trait(data) => {
+ let data = data.decode((self, sess));
+ ty::TraitDef::new(self.local_def_id(item_id),
+ data.unsafety,
+ data.paren_sugar,
+ data.has_auto_impl,
+ data.is_marker,
+ self.def_path_table.def_path_hash(item_id))
+ },
+ EntryKind::TraitAlias(_) => {
+ ty::TraitDef::new(self.local_def_id(item_id),
+ hir::Unsafety::Normal,
+ false,
+ false,
+ false,
+ self.def_path_table.def_path_hash(item_id))
+ },
+ _ => bug!("def-index does not refer to trait or trait alias"),
+ }
}
fn get_variant(&self,
item_id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> ty::GenericPredicates<'tcx> {
- match self.entry(item_id).kind {
- EntryKind::Trait(data) => data.decode(self).super_predicates.decode((self, tcx)),
- _ => bug!(),
- }
+ let super_predicates = match self.entry(item_id).kind {
+ EntryKind::Trait(data) => data.decode(self).super_predicates,
+ EntryKind::TraitAlias(data) => data.decode(self).super_predicates,
+ _ => bug!("def-index does not refer to trait or trait alias"),
+ };
+
+ super_predicates.decode((self, tcx))
}
pub fn get_generics(&self,
EntryKind::AssociatedType(container) => {
(ty::AssociatedKind::Type, container, false)
}
+ EntryKind::AssociatedExistential(container) => {
+ (ty::AssociatedKind::Existential, container, false)
+ }
_ => bug!("cannot get associated-item of `{:?}`", def_key)
};
}
def_key.parent.and_then(|parent_index| {
match self.entry(parent_index).kind {
- EntryKind::Trait(_) => Some(self.local_def_id(parent_index)),
+ EntryKind::Trait(_) |
+ EntryKind::TraitAlias(_) => Some(self.local_def_id(parent_index)),
_ => None,
}
})
EntryKind::Impl(self.lazy(&data))
}
- hir::ItemKind::Trait(..) |
- hir::ItemKind::TraitAlias(..) => {
+ hir::ItemKind::Trait(..) => {
let trait_def = tcx.trait_def(def_id);
let data = TraitData {
unsafety: trait_def.unsafety,
EntryKind::Trait(self.lazy(&data))
}
+ hir::ItemKind::TraitAlias(..) => {
+ let data = TraitAliasData {
+ super_predicates: self.lazy(&tcx.super_predicates_of(def_id)),
+ };
+
+ EntryKind::TraitAlias(self.lazy(&data))
+ }
hir::ItemKind::ExternCrate(_) |
hir::ItemKind::Use(..) => bug!("cannot encode info for item {:?}", item),
};
hir::ItemKind::Impl(..) |
hir::ItemKind::Existential(..) |
hir::ItemKind::Trait(..) => Some(self.encode_generics(def_id)),
+ hir::ItemKind::TraitAlias(..) => Some(self.encode_generics(def_id)),
_ => None,
},
predicates: match item.node {
hir::ItemKind::Union(..) |
hir::ItemKind::Impl(..) |
hir::ItemKind::Existential(..) |
- hir::ItemKind::Trait(..) => Some(self.encode_predicates(def_id)),
+ hir::ItemKind::Trait(..) |
+ hir::ItemKind::TraitAlias(..) => Some(self.encode_predicates(def_id)),
_ => None,
},
// hack. (No reason not to expand it in the future if
// necessary.)
predicates_defined_on: match item.node {
- hir::ItemKind::Trait(..) => Some(self.encode_predicates_defined_on(def_id)),
+ hir::ItemKind::Trait(..) |
+ hir::ItemKind::TraitAlias(..) => Some(self.encode_predicates_defined_on(def_id)),
_ => None, // not *wrong* for other kinds of items, but not needed
},
#![feature(nll)]
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
-#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(crate_visibility_modifier)]
AssociatedType(AssociatedContainer),
AssociatedExistential(AssociatedContainer),
AssociatedConst(AssociatedContainer, ConstQualif, Lazy<RenderedConst>),
+ TraitAlias(Lazy<TraitAliasData<'tcx>>),
}
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> {
EntryKind::Trait(ref trait_data) => {
trait_data.hash_stable(hcx, hasher);
}
+ EntryKind::TraitAlias(ref trait_alias_data) => {
+ trait_alias_data.hash_stable(hcx, hasher);
+ }
EntryKind::Impl(ref impl_data) => {
impl_data.hash_stable(hcx, hasher);
}
super_predicates
});
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct TraitAliasData<'tcx> {
+ pub super_predicates: Lazy<ty::GenericPredicates<'tcx>>,
+}
+
+impl_stable_hash_for!(struct TraitAliasData<'tcx> {
+ super_predicates
+});
+
#[derive(RustcEncodable, RustcDecodable)]
pub struct ImplData<'tcx> {
pub polarity: hir::ImplPolarity,
let place = &self.move_data.move_paths[mpi].place;
let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
- let note_msg = match self.describe_place_with_options(
- place,
- IncludingDowncast(true),
- ) {
- Some(name) => format!("`{}`", name),
+ let opt_name = self.describe_place_with_options(place, IncludingDowncast(true));
+ let note_msg = match opt_name {
+ Some(ref name) => format!("`{}`", name),
None => "value".to_owned(),
};
-
- err.note(&format!(
- "move occurs because {} has type `{}`, \
- which does not implement the `Copy` trait",
- note_msg, ty
- ));
+ if let ty::TyKind::Param(param_ty) = ty.sty {
+ let tcx = self.infcx.tcx;
+ let generics = tcx.generics_of(self.mir_def_id);
+ let def_id = generics.type_param(¶m_ty, tcx).def_id;
+ if let Some(sp) = tcx.hir().span_if_local(def_id) {
+ err.span_label(
+ sp,
+ "consider adding a `Copy` constraint to this type argument",
+ );
+ }
+ }
+ if let Place::Local(local) = place {
+ let decl = &self.mir.local_decls[*local];
+ err.span_label(
+ decl.source_info.span,
+ format!(
+ "move occurs because {} has type `{}`, \
+ which does not implement the `Copy` trait",
+ note_msg, ty,
+ ));
+ } else {
+ err.note(&format!(
+ "move occurs because {} has type `{}`, \
+ which does not implement the `Copy` trait",
+ note_msg, ty
+ ));
+ }
}
if let Some((_, mut old_err)) = self.move_error_reported
|bd, i| DebugFormatted::new(&bd.move_data().move_paths[i]),
));
- let locals_are_invalidated_at_exit = match tcx.hir().body_owner_kind(id) {
- hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
- hir::BodyOwnerKind::Fn => true,
- };
+ let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(id).is_fn_or_closure();
let borrow_set = Rc::new(BorrowSet::build(
tcx, mir, locals_are_invalidated_at_exit, &mdpe.move_data));
let closure_base_def_id = tcx.closure_base_def_id(self.mir_def_id);
match tcx.hir().body_owner_kind(self.mir_node_id) {
+ BodyOwnerKind::Closure |
BodyOwnerKind::Fn => {
let defining_ty = if self.mir_def_id == closure_base_def_id {
tcx.type_of(closure_base_def_id)
let cx = Cx::new(&infcx, id);
let mut mir = if cx.tables().tainted_by_errors {
build::construct_error(cx, body_id)
- } else if let hir::BodyOwnerKind::Fn = cx.body_owner_kind {
+ } else if cx.body_owner_kind.is_fn_or_closure() {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
let fn_hir_id = tcx.hir().node_to_hir_id(id);
hir::BodyOwnerKind::Static(_) =>
// No need to free storage in this context.
None,
+ hir::BodyOwnerKind::Closure |
hir::BodyOwnerKind::Fn =>
Some(self.topmost_scope()),
}
use rustc::hir::def::Def;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
use rustc::mir;
-use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
+use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
use rustc::ty::subst::Subst;
use rustc::traits::Reveal;
-use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashMap;
use rustc::util::common::ErrorReported;
/// Should be a power of two for performance reasons.
const DETECTOR_SNAPSHOT_PERIOD: isize = 256;
-/// Warning: do not use this function if you expect to start interpreting the given `Mir`.
-/// The `EvalContext` is only meant to be used to query values from constants and statics.
-///
-/// This function is used during const propagation. We cannot use `mk_eval_cx`, because copy
-/// propagation happens *during* the computation of the MIR of the current function. So if we
-/// tried to call the `optimized_mir` query, we'd get a cycle error because we are (transitively)
-/// inside the `optimized_mir` query of the `Instance` given.
-///
-/// Since we are looking at the MIR of the function in an abstract manner, we don't have a
-/// `ParamEnv` available to us. This function creates a `ParamEnv` for the given instance.
-pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- instance: Instance<'tcx>,
- mir: &'mir mir::Mir<'tcx>,
- span: Span,
-) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
- debug!("mk_borrowck_eval_cx: {:?}", instance);
- let param_env = tcx.param_env(instance.def_id());
- mk_eval_cx_inner(tcx, instance, mir, span, param_env)
-}
-
-/// This is just a helper function to reduce code duplication between `mk_borrowck_eval_cx` and
-/// `mk_eval_cx`. Do not call this function directly.
-fn mk_eval_cx_inner<'a, 'mir, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- instance: Instance<'tcx>,
- mir: &'mir mir::Mir<'tcx>,
- span: Span,
- param_env: ty::ParamEnv<'tcx>,
-) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'mir, 'tcx>> {
- let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new());
- // Insert a stack frame so any queries have the correct substs.
- // We also avoid all the extra work performed by push_stack_frame,
- // like initializing local variables
- ecx.stack.push(interpret::Frame {
- block: mir::START_BLOCK,
- locals: IndexVec::new(),
- instance,
- span,
- mir,
- return_place: None,
- return_to_block: StackPopCleanup::Goto(None), // never pop
- stmt: 0,
- extra: (),
- });
- Ok(ecx)
-}
-
-/// Warning: do not use this function if you expect to start interpreting the given `Mir`.
/// The `EvalContext` is only meant to be used to do field and index projections into constants for
/// `simd_shuffle` and const patterns in match arms.
///
/// that inform us about the generic bounds of the constant. E.g. using an associated constant
/// of a function's generic parameter will require knowledge about the bounds on the generic
/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
-fn mk_eval_cx<'a, 'tcx>(
+pub(crate) fn mk_eval_cx<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- instance: Instance<'tcx>,
+ span: Span,
param_env: ty::ParamEnv<'tcx>,
-) -> EvalResult<'tcx, CompileTimeEvalContext<'a, 'tcx, 'tcx>> {
- debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
- let span = tcx.def_span(instance.def_id());
- let mir = tcx.optimized_mir(instance.def.def_id());
- mk_eval_cx_inner(tcx, instance, mir, span, param_env)
+) -> CompileTimeEvalContext<'a, 'mir, 'tcx> {
+ debug!("mk_eval_cx: {:?}", param_env);
+ EvalContext::new(tcx.at(span), param_env, CompileTimeInterpreter::new())
}
pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
mir: &'mir mir::Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
- let mut ecx = mk_borrowck_eval_cx(tcx, cid.instance, mir, DUMMY_SP).unwrap();
+ let span = tcx.def_span(cid.instance.def_id());
+ let mut ecx = mk_eval_cx(tcx, span, param_env);
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
}
pub fn const_field<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- instance: ty::Instance<'tcx>,
variant: Option<VariantIdx>,
field: mir::Field,
value: ty::Const<'tcx>,
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
- trace!("const_field: {:?}, {:?}, {:?}", instance, field, value);
- let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+ trace!("const_field: {:?}, {:?}", field, value);
+ let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let result = (|| {
// get the operand again
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?;
pub fn const_variant_index<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
- instance: ty::Instance<'tcx>,
val: ty::Const<'tcx>,
) -> EvalResult<'tcx, VariantIdx> {
- trace!("const_variant_index: {:?}, {:?}", instance, val);
- let ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+ trace!("const_variant_index: {:?}", val);
+ let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?;
Ok(ecx.read_discriminant(op)?.1)
}
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
let cid = key.value;
- let ecx = mk_eval_cx(tcx, cid.instance, key.param_env).unwrap();
+ let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env);
let val = (|| {
let op = ecx.raw_const_to_mplace(constant)?.into();
// FIXME: Once the visitor infrastructure landed, change validation to
let id = tcx.allocate_bytes(s.as_bytes());
ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx)
},
+ LitKind::Err(ref s) => {
+ let s = s.as_str();
+ let id = tcx.allocate_bytes(s.as_bytes());
+ return Ok(ty::Const {
+ val: ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx),
+ ty: tcx.types.err,
+ });
+ },
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::Ptr(id.into()))
-> Vec<StmtRef<'tcx>> {
let mut result = vec![];
for (index, stmt) in stmts.iter().enumerate() {
- let hir_id = cx.tcx.hir().node_to_hir_id(stmt.node.id());
+ let hir_id = cx.tcx.hir().node_to_hir_id(stmt.id);
let opt_dxn_ext = cx.region_scope_tree.opt_destruction_scope(hir_id.local_id);
- let stmt_span = StatementSpan(cx.tcx.hir().span(stmt.node.id()));
+ let stmt_span = StatementSpan(cx.tcx.hir().span(stmt.id));
match stmt.node {
- hir::StmtKind::Expr(ref expr, _) |
- hir::StmtKind::Semi(ref expr, _) => {
+ hir::StmtKind::Expr(ref expr) |
+ hir::StmtKind::Semi(ref expr) => {
result.push(StmtRef::Mirror(Box::new(Stmt {
kind: StmtKind::Expr {
scope: region::Scope {
span: stmt_span,
})))
}
- hir::StmtKind::Decl(ref decl, _) => {
- match decl.node {
- hir::DeclKind::Item(..) => {
- // ignore for purposes of the MIR
- }
- hir::DeclKind::Local(ref local) => {
- let remainder_scope = region::Scope {
- id: block_id,
- data: region::ScopeData::Remainder(
- region::FirstStatementIndex::new(index)),
- };
-
- let mut pattern = cx.pattern_from_hir(&local.pat);
+ hir::StmtKind::Item(..) => {
+ // ignore for purposes of the MIR
+ }
+ hir::StmtKind::Local(ref local) => {
+ let remainder_scope = region::Scope {
+ id: block_id,
+ data: region::ScopeData::Remainder(
+ region::FirstStatementIndex::new(index)),
+ };
- if let Some(ty) = &local.ty {
- if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
- debug!("mirror_stmts: user_ty={:?}", user_ty);
- pattern = Pattern {
- ty: pattern.ty,
- span: pattern.span,
- kind: Box::new(PatternKind::AscribeUserType {
- user_ty: PatternTypeProjection::from_user_type(user_ty),
- user_ty_span: ty.span,
- subpattern: pattern,
- variance: ty::Variance::Covariant,
- })
- };
- }
- }
+ let mut pattern = cx.pattern_from_hir(&local.pat);
- result.push(StmtRef::Mirror(Box::new(Stmt {
- kind: StmtKind::Let {
- remainder_scope: remainder_scope,
- init_scope: region::Scope {
- id: hir_id.local_id,
- data: region::ScopeData::Node
- },
- pattern,
- initializer: local.init.to_ref(),
- lint_level: cx.lint_level_of(local.id),
- },
- opt_destruction_scope: opt_dxn_ext,
- span: stmt_span,
- })));
+ if let Some(ty) = &local.ty {
+ if let Some(&user_ty) = cx.tables.user_provided_types().get(ty.hir_id) {
+ debug!("mirror_stmts: user_ty={:?}", user_ty);
+ pattern = Pattern {
+ ty: pattern.ty,
+ span: pattern.span,
+ kind: Box::new(PatternKind::AscribeUserType {
+ user_ty: PatternTypeProjection::from_user_type(user_ty),
+ user_ty_span: ty.span,
+ subpattern: pattern,
+ variance: ty::Variance::Covariant,
+ })
+ };
}
}
+
+ result.push(StmtRef::Mirror(Box::new(Stmt {
+ kind: StmtKind::Let {
+ remainder_scope: remainder_scope,
+ init_scope: region::Scope {
+ id: hir_id.local_id,
+ data: region::ScopeData::Node
+ },
+ pattern,
+ initializer: local.init.to_ref(),
+ lint_level: cx.lint_level_of(local.id),
+ },
+ opt_destruction_scope: opt_dxn_ext,
+ span: stmt_span,
+ })));
}
}
}
let constness = match body_owner_kind {
hir::BodyOwnerKind::Const |
hir::BodyOwnerKind::Static(_) => hir::Constness::Const,
+ hir::BodyOwnerKind::Closure |
hir::BodyOwnerKind::Fn => hir::Constness::NotConst,
};
}
impl<'tcx> Constructor<'tcx> {
- fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> VariantIdx {
+ fn variant_index_for_adt<'a>(
+ &self,
+ cx: &MatchCheckCtxt<'a, 'tcx>,
+ adt: &'tcx ty::AdtDef,
+ ) -> VariantIdx {
match self {
&Variant(vid) => adt.variant_index_with_id(vid),
&Single => {
assert!(!adt.is_enum());
VariantIdx::new(0)
}
+ &ConstantValue(c) => {
+ ::const_eval::const_variant_index(
+ cx.tcx,
+ cx.param_env,
+ c,
+ ).unwrap()
+ },
_ => bug!("bad constructor {:?} for adt {:?}", self, adt)
}
}
PatternKind::Variant {
adt_def: adt,
substs,
- variant_index: ctor.variant_index_for_adt(adt),
+ variant_index: ctor.variant_index_for_adt(cx, adt),
subpatterns: pats
}
} else {
///
/// For instance, a tuple pattern (_, 42, Some([])) has the arity of 3.
/// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> u64 {
+fn constructor_arity(cx: &MatchCheckCtxt<'a, 'tcx>, ctor: &Constructor<'tcx>, ty: Ty<'tcx>) -> u64 {
debug!("constructor_arity({:#?}, {:?})", ctor, ty);
match ty.sty {
ty::Tuple(ref fs) => fs.len() as u64,
},
ty::Ref(..) => 1,
ty::Adt(adt, _) => {
- adt.variants[ctor.variant_index_for_adt(adt)].fields.len() as u64
+ adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.len() as u64
}
_ => 0
}
///
/// For instance, a tuple pattern (43u32, 'a') has sub pattern types [u32, char].
fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>,
- ctor: &Constructor,
+ ctor: &Constructor<'tcx>,
ty: Ty<'tcx>) -> Vec<Ty<'tcx>>
{
debug!("constructor_sub_pattern_tys({:#?}, {:?})", ctor, ty);
// Use T as the sub pattern type of Box<T>.
vec![substs.type_at(0)]
} else {
- adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
+ adt.variants[ctor.variant_index_for_adt(cx, adt)].fields.iter().map(|field| {
let is_visible = adt.is_enum()
|| field.vis.is_accessible_from(cx.module, cx.tcx);
if is_visible {
let adt_subpattern = |i, variant_opt| {
let field = Field::new(i);
let val = const_field(
- self.tcx, self.param_env, instance,
+ self.tcx, self.param_env,
variant_opt, field, cv,
).expect("field access failed");
self.const_to_pat(instance, val, id, span)
},
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
let variant_index = const_variant_index(
- self.tcx, self.param_env, instance, cv
+ self.tcx, self.param_env, cv
).expect("const_variant_index failed");
let subpatterns = adt_subpatterns(
adt_def.variants[variant_index].fields.len(),
// The src operand does not matter, just its type
match src.layout.ty.sty {
ty::Closure(def_id, substs) => {
- let substs = self.tcx.subst_and_normalize_erasing_regions(
- self.substs(),
- ty::ParamEnv::reveal_all(),
- &substs,
- );
+ let substs = self.subst_and_normalize_erasing_regions(substs)?;
let instance = ty::Instance::resolve_closure(
*self.tcx,
def_id,
+use std::cell::Cell;
use std::fmt::Write;
use std::mem;
/// `None` represents a local that is currently dead, while a live local
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
+ pub local_layouts: IndexVec<mir::Local, Cell<Option<TyLayout<'tcx>>>>,
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
self.frame().mir
}
- pub fn substs(&self) -> &'tcx Substs<'tcx> {
- if let Some(frame) = self.stack.last() {
- frame.instance.substs
- } else {
- Substs::empty()
+ pub(super) fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
+ &self,
+ substs: T,
+ ) -> EvalResult<'tcx, T> {
+ match self.stack.last() {
+ Some(frame) => Ok(self.tcx.subst_and_normalize_erasing_regions(
+ frame.instance.substs,
+ self.param_env,
+ &substs,
+ )),
+ None => if substs.needs_subst() {
+ err!(TooGeneric).into()
+ } else {
+ Ok(substs)
+ },
}
}
substs: &'tcx Substs<'tcx>
) -> EvalResult<'tcx, ty::Instance<'tcx>> {
trace!("resolve: {:?}, {:#?}", def_id, substs);
- trace!("substs: {:#?}", self.substs());
trace!("param_env: {:#?}", self.param_env);
- let substs = self.tcx.subst_and_normalize_erasing_regions(
- self.substs(),
- self.param_env,
- &substs,
- );
+ let substs = self.subst_and_normalize_erasing_regions(substs)?;
+ trace!("substs: {:#?}", substs);
ty::Instance::resolve(
*self.tcx,
self.param_env,
}
}
- pub fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
+ pub(super) fn monomorphize<T: TypeFoldable<'tcx> + Subst<'tcx>>(
+ &self,
+ t: T,
+ ) -> EvalResult<'tcx, T> {
+ match self.stack.last() {
+ Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)),
+ None => if t.needs_subst() {
+ err!(TooGeneric).into()
+ } else {
+ Ok(t)
+ },
+ }
+ }
+
+ fn monomorphize_with_substs<T: TypeFoldable<'tcx> + Subst<'tcx>>(
&self,
t: T,
substs: &'tcx Substs<'tcx>
frame: &Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
local: mir::Local
) -> EvalResult<'tcx, TyLayout<'tcx>> {
- let local_ty = frame.mir.local_decls[local].ty;
- let local_ty = self.monomorphize(local_ty, frame.instance.substs);
- self.layout_of(local_ty)
+ let cell = &frame.local_layouts[local];
+ if cell.get().is_none() {
+ let local_ty = frame.mir.local_decls[local].ty;
+ let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
+ let layout = self.layout_of(local_ty)?;
+ cell.set(Some(layout));
+ }
+
+ Ok(cell.get().unwrap())
}
pub fn str_to_immediate(&mut self, s: &str) -> EvalResult<'tcx, Immediate<M::PointerTag>> {
// empty local array, we fill it in below, after we are inside the stack frame and
// all methods actually know about the frame
locals: IndexVec::new(),
+ local_layouts: IndexVec::from_elem_n(Default::default(), mir.local_decls.len()),
span,
instance,
stmt: 0,
},
}
// Finally, properly initialize all those that still have the dummy value
- for (local, decl) in locals.iter_mut().zip(mir.local_decls.iter()) {
+ for (idx, local) in locals.iter_enumerated_mut() {
match *local {
LocalValue::Live(_) => {
// This needs to be peoperly initialized.
- let layout = self.layout_of(self.monomorphize(decl.ty, instance.substs))?;
+ let layout = self.layout_of_local(self.frame(), idx)?;
*local = LocalValue::Live(self.uninit_operand(layout)?);
}
LocalValue::Dead => {
}
/// This is used by [priroda](https://github.com/oli-obk/priroda) to get an OpTy from a local
- ///
- /// When you know the layout of the local in advance, you can pass it as last argument
- pub fn access_local(
+ fn access_local(
&self,
frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>,
local: mir::Local,
- layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
assert_ne!(local, mir::RETURN_PLACE);
let op = *frame.locals[local].access()?;
- let layout = from_known_layout(layout,
- || self.layout_of_local(frame, local))?;
+ let layout = self.layout_of_local(frame, local)?;
Ok(OpTy { op, layout })
}
// Evaluate a place with the goal of reading from it. This lets us sometimes
- // avoid allocations. If you already know the layout, you can pass it in
- // to avoid looking it up again.
+ // avoid allocations.
fn eval_place_to_op(
&self,
mir_place: &mir::Place<'tcx>,
- layout: Option<TyLayout<'tcx>>,
) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
let op = match *mir_place {
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
- Local(local) => self.access_local(self.frame(), local, layout)?,
+ Local(local) => self.access_local(self.frame(), local)?,
Projection(ref proj) => {
- let op = self.eval_place_to_op(&proj.base, None)?;
+ let op = self.eval_place_to_op(&proj.base)?;
self.operand_projection(op, &proj.elem)?
}
// FIXME: do some more logic on `move` to invalidate the old location
Copy(ref place) |
Move(ref place) =>
- self.eval_place_to_op(place, layout)?,
+ self.eval_place_to_op(place)?,
Constant(ref constant) => {
let layout = from_known_layout(layout, || {
- let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs());
+ let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx))?;
self.layout_of(ty)
})?;
let op = self.const_value_to_op(*constant.literal)?;
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
+use rustc::ty::TypeFoldable;
use super::{
GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
}
Static(ref static_) => {
- let ty = self.monomorphize(static_.ty, self.substs());
- let layout = self.layout_of(ty)?;
+ assert!(!static_.ty.needs_subst());
+ let layout = self.layout_of(static_.ty)?;
let instance = ty::Instance::mono(*self.tcx, static_.def_id);
let cid = GlobalId {
instance,
stmt: usize,
}
-impl_stable_hash_for!(impl<'tcx, 'mir: 'tcx> for struct Frame<'mir, 'tcx> {
+impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> {
mir,
instance,
span,
return_to_block,
return_place -> (return_place.as_ref().map(|r| &**r)),
locals,
+ local_layouts -> _,
block,
stmt,
extra,
return_to_block,
return_place,
locals,
+ local_layouts: _,
block,
stmt,
extra: _,
}
NullaryOp(mir::NullOp::SizeOf, ty) => {
- let ty = self.monomorphize(ty, self.substs());
+ let ty = self.monomorphize(ty)?;
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(),
"SizeOf nullary MIR operator called for unsized type");
}
Cast(kind, ref operand, cast_ty) => {
- debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest.layout.ty);
+ debug_assert_eq!(self.monomorphize(cast_ty)?, dest.layout.ty);
let src = self.eval_operand(operand, None)?;
self.cast(src, kind, dest)?;
}
}
// At least one value is excluded. Get the bits.
let value = try_validation!(value.not_undef(),
- value, self.path,
- format!("something in the range {:?}", layout.valid_range));
+ value,
+ self.path,
+ format!(
+ "something {}",
+ wrapping_range_format(&layout.valid_range, max_hi),
+ )
+ );
let bits = match value {
Scalar::Ptr(ptr) => {
if lo == 1 && hi == max_hi {
// We've been here already, no need to search again.
return;
}
- debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx));
+ debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx, true));
let mut neighbors = Vec::new();
let recursion_depth_reset;
recursion_depths.insert(def_id, depth);
}
- debug!("END collect_items_rec({})", starting_point.to_string(tcx));
+ debug!("END collect_items_rec({})", starting_point.to_string(tcx, true));
}
fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.substitute_normalize_and_test_predicates((def_id, &substs))
}
- fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
+ fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, debug: bool) -> String {
return match *self.as_mono_item() {
MonoItem::Fn(instance) => {
- to_string_internal(tcx, "fn ", instance)
+ to_string_internal(tcx, "fn ", instance, debug)
},
MonoItem::Static(def_id) => {
let instance = Instance::new(def_id, tcx.intern_substs(&[]));
- to_string_internal(tcx, "static ", instance)
+ to_string_internal(tcx, "static ", instance, debug)
},
MonoItem::GlobalAsm(..) => {
"global_asm".to_string()
fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
prefix: &str,
- instance: Instance<'tcx>)
+ instance: Instance<'tcx>,
+ debug: bool)
-> String {
let mut result = String::with_capacity(32);
result.push_str(prefix);
let printer = DefPathBasedNames::new(tcx, false, false);
- printer.push_instance_as_string(instance, &mut result);
+ printer.push_instance_as_string(instance, &mut result, debug);
result
}
}
}
}
- pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
+ // Pushes the type name of the specified type to the provided string.
+ // If 'debug' is true, printing normally unprintable types is allowed
+ // (e.g. ty::GeneratorWitness). This parameter should only be set when
+ // this method is being used for logging purposes (e.g. with debug! or info!)
+ // When being used for codegen purposes, 'debug' should be set to 'false'
+ // in order to catch unexpected types that should never end up in a type name
+ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) {
match t.sty {
ty::Bool => output.push_str("bool"),
ty::Char => output.push_str("char"),
ty::Float(ast::FloatTy::F64) => output.push_str("f64"),
ty::Adt(adt_def, substs) => {
self.push_def_path(adt_def.did, output);
- self.push_type_params(substs, iter::empty(), output);
+ self.push_type_params(substs, iter::empty(), output, debug);
},
ty::Tuple(component_types) => {
output.push('(');
for &component_type in component_types {
- self.push_type_name(component_type, output);
+ self.push_type_name(component_type, output, debug);
output.push_str(", ");
}
if !component_types.is_empty() {
hir::MutMutable => output.push_str("mut "),
}
- self.push_type_name(inner_type, output);
+ self.push_type_name(inner_type, output, debug);
},
ty::Ref(_, inner_type, mutbl) => {
output.push('&');
output.push_str("mut ");
}
- self.push_type_name(inner_type, output);
+ self.push_type_name(inner_type, output, debug);
},
ty::Array(inner_type, len) => {
output.push('[');
- self.push_type_name(inner_type, output);
+ self.push_type_name(inner_type, output, debug);
write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
output.push(']');
},
ty::Slice(inner_type) => {
output.push('[');
- self.push_type_name(inner_type, output);
+ self.push_type_name(inner_type, output, debug);
output.push(']');
},
ty::Dynamic(ref trait_data, ..) => {
principal.skip_binder().substs,
trait_data.projection_bounds(),
output,
+ debug
);
} else {
output.push_str("dyn '_");
if !sig.inputs().is_empty() {
for ¶meter_type in sig.inputs() {
- self.push_type_name(parameter_type, output);
+ self.push_type_name(parameter_type, output, debug);
output.push_str(", ");
}
output.pop();
if !sig.output().is_unit() {
output.push_str(" -> ");
- self.push_type_name(sig.output(), output);
+ self.push_type_name(sig.output(), output, debug);
}
},
ty::Generator(def_id, GeneratorSubsts { ref substs }, _) |
self.push_def_path(def_id, output);
let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
let substs = substs.truncate_to(self.tcx, generics);
- self.push_type_params(substs, iter::empty(), output);
+ self.push_type_params(substs, iter::empty(), output, debug);
}
ty::Error |
ty::Bound(..) |
ty::Param(_) |
ty::GeneratorWitness(_) |
ty::Opaque(..) => {
- bug!("DefPathBasedNames: Trying to create type name for \
+ if debug {
+ output.push_str(&format!("`{:?}`", t));
+ } else {
+ bug!("DefPathBasedNames: Trying to create type name for \
unexpected type: {:?}", t);
+ }
}
}
}
fn push_type_params<I>(&self,
substs: &Substs<'tcx>,
projections: I,
- output: &mut String)
+ output: &mut String,
+ debug: bool)
where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
{
let mut projections = projections.peekable();
output.push('<');
for type_parameter in substs.types() {
- self.push_type_name(type_parameter, output);
+ self.push_type_name(type_parameter, output, debug);
output.push_str(", ");
}
let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str();
output.push_str(name);
output.push_str("=");
- self.push_type_name(projection.ty, output);
+ self.push_type_name(projection.ty, output, debug);
output.push_str(", ");
}
pub fn push_instance_as_string(&self,
instance: Instance<'tcx>,
- output: &mut String) {
+ output: &mut String,
+ debug: bool) {
self.push_def_path(instance.def_id(), output);
- self.push_type_params(instance.substs, iter::empty(), output);
+ self.push_type_params(instance.substs, iter::empty(), output, debug);
}
}
.unwrap_or("<no hash>");
debug!(" - {} [{:?}] [{}]",
- mono_item.to_string(tcx),
+ mono_item.to_string(tcx, true),
linkage,
symbol_hash);
}
let mut item_keys: Vec<_> = items
.iter()
.map(|i| {
- let mut output = i.to_string(tcx);
+ let mut output = i.to_string(tcx, false);
output.push_str(" @@");
let mut empty = Vec::new();
let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
use rustc::ty::query::Providers;
use rustc::ty::{self, TyCtxt};
+use rustc::ty::cast::CastTy;
use rustc::hir;
use rustc::hir::Node;
use rustc::hir::def_id::DefId;
pub struct UnsafetyChecker<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
+ const_context: bool,
min_const_fn: bool,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
violations: Vec<UnsafetyViolation>,
impl<'a, 'gcx, 'tcx> UnsafetyChecker<'a, 'tcx> {
fn new(
+ const_context: bool,
min_const_fn: bool,
mir: &'a Mir<'tcx>,
source_scope_local_data: &'a IndexVec<SourceScope, SourceScopeLocalData>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
+ // sanity check
+ if min_const_fn {
+ assert!(const_context);
+ }
Self {
mir,
+ const_context,
min_const_fn,
source_scope_local_data,
violations: vec![],
rvalue: &Rvalue<'tcx>,
location: Location)
{
- if let &Rvalue::Aggregate(box ref aggregate, _) = rvalue {
- match aggregate {
- &AggregateKind::Array(..) |
- &AggregateKind::Tuple => {}
- &AggregateKind::Adt(ref def, ..) => {
- match self.tcx.layout_scalar_valid_range(def.did) {
- (Bound::Unbounded, Bound::Unbounded) => {},
- _ => self.require_unsafe(
- "initializing type with `rustc_layout_scalar_valid_range` attr",
- "initializing a layout restricted type's field with a value outside \
- the valid range is undefined behavior",
- UnsafetyViolationKind::GeneralAndConstFn,
- ),
+ match rvalue {
+ Rvalue::Aggregate(box ref aggregate, _) => {
+ match aggregate {
+ &AggregateKind::Array(..) |
+ &AggregateKind::Tuple => {}
+ &AggregateKind::Adt(ref def, ..) => {
+ match self.tcx.layout_scalar_valid_range(def.did) {
+ (Bound::Unbounded, Bound::Unbounded) => {},
+ _ => self.require_unsafe(
+ "initializing type with `rustc_layout_scalar_valid_range` attr",
+ "initializing a layout restricted type's field with a value \
+ outside the valid range is undefined behavior",
+ UnsafetyViolationKind::GeneralAndConstFn,
+ ),
+ }
+ }
+ &AggregateKind::Closure(def_id, _) |
+ &AggregateKind::Generator(def_id, _, _) => {
+ let UnsafetyCheckResult {
+ violations, unsafe_blocks
+ } = self.tcx.unsafety_check_result(def_id);
+ self.register_violations(&violations, &unsafe_blocks);
}
}
- &AggregateKind::Closure(def_id, _) |
- &AggregateKind::Generator(def_id, _, _) => {
- let UnsafetyCheckResult {
- violations, unsafe_blocks
- } = self.tcx.unsafety_check_result(def_id);
- self.register_violations(&violations, &unsafe_blocks);
+ },
+ // casting pointers to ints is unsafe in const fn because the const evaluator cannot
+ // possibly know what the result of various operations like `address / 2` would be
+ // pointers during const evaluation have no integral address, only an abstract one
+ Rvalue::Cast(CastKind::Misc, ref operand, cast_ty)
+ if self.const_context && self.tcx.features().const_raw_ptr_to_usize_cast => {
+ let operand_ty = operand.ty(self.mir, self.tcx);
+ let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
+ let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+ match (cast_in, cast_out) {
+ (CastTy::Ptr(_), CastTy::Int(_)) |
+ (CastTy::FnPtr, CastTy::Int(_)) => {
+ self.register_violations(&[UnsafetyViolation {
+ source_info: self.source_info,
+ description: Symbol::intern("cast of pointer to int").as_interned_str(),
+ details: Symbol::intern("casting pointers to integers in constants")
+ .as_interned_str(),
+ kind: UnsafetyViolationKind::General,
+ }], &[]);
+ },
+ _ => {},
}
}
+ // raw pointer and fn pointer operations are unsafe as it is not clear whether one
+ // pointer would be "less" or "equal" to another, because we cannot know where llvm
+ // or the linker will place various statics in memory. Without this information the
+ // result of a comparison of addresses would differ between runtime and compile-time.
+ Rvalue::BinaryOp(_, ref lhs, _)
+ if self.const_context && self.tcx.features().const_compare_raw_pointers => {
+ if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.mir, self.tcx).sty {
+ self.register_violations(&[UnsafetyViolation {
+ source_info: self.source_info,
+ description: Symbol::intern("pointer operation").as_interned_str(),
+ details: Symbol::intern("operations on pointers in constants")
+ .as_interned_str(),
+ kind: UnsafetyViolationKind::General,
+ }], &[]);
+ }
+ }
+ _ => {},
}
self.super_rvalue(rvalue, location);
}
};
let param_env = tcx.param_env(def_id);
+
+ let id = tcx.hir().as_local_node_id(def_id).unwrap();
+ let (const_context, min_const_fn) = match tcx.hir().body_owner_kind(id) {
+ hir::BodyOwnerKind::Closure => (false, false),
+ hir::BodyOwnerKind::Fn => (tcx.is_const_fn(def_id), tcx.is_min_const_fn(def_id)),
+ hir::BodyOwnerKind::Const |
+ hir::BodyOwnerKind::Static(_) => (true, false),
+ };
let mut checker = UnsafetyChecker::new(
- tcx.is_min_const_fn(def_id),
+ const_context, min_const_fn,
mir, source_scope_local_data, tcx, param_env);
checker.visit_mir(mir);
use interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind};
use const_eval::{
- CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_borrowck_eval_cx,
+ CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
lazy_const_to_op,
};
use transform::{MirPass, MirSource};
source: MirSource,
) -> ConstPropagator<'a, 'mir, 'tcx> {
let param_env = tcx.param_env(source.def_id);
- let substs = Substs::identity_for_item(tcx, source.def_id);
- let instance = Instance::new(source.def_id, substs);
- let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
+ let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id), param_env);
ConstPropagator {
ecx,
mir,
//! Inlining pass for MIR functions
-use rustc::hir;
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::DefId;
// Only do inlining into fn bodies.
let id = self.tcx.hir().as_local_node_id(self.source.def_id).unwrap();
- let body_owner_kind = self.tcx.hir().body_owner_kind(id);
-
- if let (hir::BodyOwnerKind::Fn, None) = (body_owner_kind, self.source.promoted) {
-
+ if self.tcx.hir().body_owner_kind(id).is_fn_or_closure() && self.source.promoted.is_none() {
for (bb, bb_data) in caller_mir.basic_blocks().iter_enumerated() {
if let Some(callsite) = self.get_valid_function_call(bb,
- bb_data,
- caller_mir,
- param_env) {
+ bb_data,
+ caller_mir,
+ param_env) {
callsites.push_back(callsite);
}
}
let id = tcx.hir().as_local_node_id(def_id).unwrap();
let mut const_promoted_temps = None;
let mode = match tcx.hir().body_owner_kind(id) {
+ hir::BodyOwnerKind::Closure => Mode::Fn,
hir::BodyOwnerKind::Fn => {
if tcx.is_const_fn(def_id) {
Mode::ConstFn
| Predicate::RegionOutlives(_)
| Predicate::TypeOutlives(_)
| Predicate::WellFormed(_)
+ | Predicate::Projection(_)
| Predicate::ConstEvaluatable(..) => continue,
| Predicate::ObjectSafe(_) => {
bug!("object safe predicate on function: {:#?}", predicate)
bug!("closure kind predicate on function: {:#?}", predicate)
}
Predicate::Subtype(_) => bug!("subtype predicate on function: {:#?}", predicate),
- Predicate::Projection(_) => {
- let span = tcx.def_span(current);
- // we'll hit a `Predicate::Trait` later which will report an error
- tcx.sess
- .delay_span_bug(span, "projection without trait bound");
- continue;
- }
Predicate::Trait(pred) => {
if Some(pred.def_id()) == tcx.lang_items().sized_trait() {
continue;
let body_owner_kind = tcx.hir().body_owner_kind(id);
match (body_owner_kind, src.promoted) {
(_, Some(i)) => write!(w, "{:?} in", i)?,
+ (hir::BodyOwnerKind::Closure, _) |
(hir::BodyOwnerKind::Fn, _) => write!(w, "fn")?,
(hir::BodyOwnerKind::Const, _) => write!(w, "const")?,
(hir::BodyOwnerKind::Static(hir::MutImmutable), _) => write!(w, "static")?,
})?;
match (body_owner_kind, src.promoted) {
+ (hir::BodyOwnerKind::Closure, None) |
(hir::BodyOwnerKind::Fn, None) => {
write!(w, "(")?;
// This pass is supposed to perform only simple checks not requiring name resolution
// or type checking or some other kind of complex analysis.
+use std::mem;
use rustc::lint;
use rustc::session::Session;
use syntax::ast::*;
struct AstValidator<'a> {
session: &'a Session,
+
+ // 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<Span>,
+
+ // Used to ban `impl Trait` in path projections like `<impl Iterator>::Item`
+ // or `Foo::Bar<impl Trait>`
+ is_impl_trait_banned: bool,
}
impl<'a> AstValidator<'a> {
+ fn with_banned_impl_trait(&mut self, f: impl FnOnce(&mut Self)) {
+ let old = mem::replace(&mut self.is_impl_trait_banned, true);
+ f(self);
+ self.is_impl_trait_banned = old;
+ }
+
+ fn with_impl_trait(&mut self, outer_impl_trait: Option<Span>, f: impl FnOnce(&mut Self)) {
+ let old = mem::replace(&mut self.outer_impl_trait, outer_impl_trait);
+ f(self);
+ self.outer_impl_trait = old;
+ }
+
+ // Mirrors visit::walk_ty, but tracks relevant state
+ fn walk_ty(&mut self, t: &'a Ty) {
+ match t.node {
+ TyKind::ImplTrait(..) => {
+ self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t))
+ }
+ TyKind::Path(ref qself, ref path) => {
+ // We allow these:
+ // - `Option<impl Trait>`
+ // - `option::Option<impl Trait>`
+ // - `option::Option<T>::Foo<impl Trait>
+ //
+ // But not these:
+ // - `<impl Trait>::Foo`
+ // - `option::Option<impl Trait>::Foo`.
+ //
+ // To implement this, we disallow `impl Trait` from `qself`
+ // (for cases like `<impl Trait>::Foo>`)
+ // but we allow `impl Trait` in `GenericArgs`
+ // iff there are no more PathSegments.
+ if let Some(ref qself) = *qself {
+ // `impl Trait` in `qself` is always illegal
+ self.with_banned_impl_trait(|this| this.visit_ty(&qself.ty));
+ }
+
+ // Note that there should be a call to visit_path here,
+ // so if any logic is added to process `Path`s a call to it should be
+ // added both in visit_path and here. This code mirrors visit::walk_path.
+ for (i, segment) in path.segments.iter().enumerate() {
+ // Allow `impl Trait` iff we're on the final path segment
+ if i == path.segments.len() - 1 {
+ self.visit_path_segment(path.span, segment);
+ } else {
+ self.with_banned_impl_trait(|this| {
+ this.visit_path_segment(path.span, segment)
+ });
+ }
+ }
+ }
+ _ => visit::walk_ty(self, t),
+ }
+ }
+
fn err_handler(&self) -> &errors::Handler {
&self.session.diagnostic()
}
self.no_questions_in_bounds(bounds, "trait object types", false);
}
TyKind::ImplTrait(_, ref bounds) => {
+ if self.is_impl_trait_banned {
+ struct_span_err!(self.session, ty.span, E0667,
+ "`impl Trait` is not allowed in path parameters").emit();
+ }
+
+ if let Some(outer_impl_trait) = self.outer_impl_trait {
+ struct_span_err!(self.session, ty.span, E0666,
+ "nested `impl Trait` is not allowed")
+ .span_label(outer_impl_trait, "outer `impl Trait`")
+ .span_label(ty.span, "nested `impl Trait` here")
+ .emit();
+
+ }
if !bounds.iter()
.any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) {
self.err_handler().span_err(ty.span, "at least one trait must be specified");
_ => {}
}
- visit::walk_ty(self, ty)
+ self.walk_ty(ty)
}
fn visit_label(&mut self, label: &'a Label) {
visit::walk_foreign_item(self, fi)
}
+ // Mirrors visit::walk_generic_args, but tracks relevant state
+ fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
+ match *generic_args {
+ GenericArgs::AngleBracketed(ref data) => {
+ walk_list!(self, visit_generic_arg, &data.args);
+ // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
+ // are allowed to contain nested `impl Trait`.
+ self.with_impl_trait(None, |this| {
+ walk_list!(this, visit_assoc_type_binding, &data.bindings);
+ });
+ }
+ GenericArgs::Parenthesized(ref data) => {
+ walk_list!(self, visit_ty, &data.inputs);
+ if let Some(ref type_) = data.output {
+ // `-> Foo` syntax is essentially an associated type binding,
+ // so it is also allowed to contain nested `impl Trait`.
+ self.with_impl_trait(None, |this| visit::walk_ty(this, type_));
+ }
+ }
+ }
+ }
+
fn visit_generics(&mut self, generics: &'a Generics) {
let mut seen_non_lifetime_param = false;
let mut seen_default = None;
}
}
-// Bans 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>`
-struct NestedImplTraitVisitor<'a> {
- session: &'a Session,
- outer_impl_trait: Option<Span>,
-}
-
-impl<'a> NestedImplTraitVisitor<'a> {
- fn with_impl_trait<F>(&mut self, outer_impl_trait: Option<Span>, f: F)
- where F: FnOnce(&mut NestedImplTraitVisitor<'a>)
- {
- let old_outer_impl_trait = self.outer_impl_trait;
- self.outer_impl_trait = outer_impl_trait;
- f(self);
- self.outer_impl_trait = old_outer_impl_trait;
- }
-}
-
-
-impl<'a> Visitor<'a> for NestedImplTraitVisitor<'a> {
- fn visit_ty(&mut self, t: &'a Ty) {
- if let TyKind::ImplTrait(..) = t.node {
- if let Some(outer_impl_trait) = self.outer_impl_trait {
- struct_span_err!(self.session, t.span, E0666,
- "nested `impl Trait` is not allowed")
- .span_label(outer_impl_trait, "outer `impl Trait`")
- .span_label(t.span, "nested `impl Trait` here")
- .emit();
-
- }
- self.with_impl_trait(Some(t.span), |this| visit::walk_ty(this, t));
- } else {
- visit::walk_ty(self, t);
- }
- }
- fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
- match *generic_args {
- GenericArgs::AngleBracketed(ref data) => {
- for arg in &data.args {
- self.visit_generic_arg(arg)
- }
- for type_binding in &data.bindings {
- // Type bindings such as `Item=impl Debug` in `Iterator<Item=Debug>`
- // are allowed to contain nested `impl Trait`.
- self.with_impl_trait(None, |this| visit::walk_ty(this, &type_binding.ty));
- }
- }
- GenericArgs::Parenthesized(ref data) => {
- for type_ in &data.inputs {
- self.visit_ty(type_);
- }
- if let Some(ref type_) = data.output {
- // `-> Foo` syntax is essentially an associated type binding,
- // so it is also allowed to contain nested `impl Trait`.
- self.with_impl_trait(None, |this| visit::walk_ty(this, type_));
- }
- }
- }
- }
-
- fn visit_mac(&mut self, _mac: &Spanned<Mac_>) {
- // covered in AstValidator
- }
-}
-
-// Bans `impl Trait` in path projections like `<impl Iterator>::Item` or `Foo::Bar<impl Trait>`.
-struct ImplTraitProjectionVisitor<'a> {
- session: &'a Session,
- is_banned: bool,
-}
-
-impl<'a> ImplTraitProjectionVisitor<'a> {
- fn with_ban<F>(&mut self, f: F)
- where F: FnOnce(&mut ImplTraitProjectionVisitor<'a>)
- {
- let old_is_banned = self.is_banned;
- self.is_banned = true;
- f(self);
- self.is_banned = old_is_banned;
- }
-}
-
-impl<'a> Visitor<'a> for ImplTraitProjectionVisitor<'a> {
- fn visit_ty(&mut self, t: &'a Ty) {
- match t.node {
- TyKind::ImplTrait(..) => {
- if self.is_banned {
- struct_span_err!(self.session, t.span, E0667,
- "`impl Trait` is not allowed in path parameters").emit();
- }
- }
- TyKind::Path(ref qself, ref path) => {
- // We allow these:
- // - `Option<impl Trait>`
- // - `option::Option<impl Trait>`
- // - `option::Option<T>::Foo<impl Trait>
- //
- // But not these:
- // - `<impl Trait>::Foo`
- // - `option::Option<impl Trait>::Foo`.
- //
- // To implement this, we disallow `impl Trait` from `qself`
- // (for cases like `<impl Trait>::Foo>`)
- // but we allow `impl Trait` in `GenericArgs`
- // iff there are no more PathSegments.
- if let Some(ref qself) = *qself {
- // `impl Trait` in `qself` is always illegal
- self.with_ban(|this| this.visit_ty(&qself.ty));
- }
-
- for (i, segment) in path.segments.iter().enumerate() {
- // Allow `impl Trait` iff we're on the final path segment
- if i == path.segments.len() - 1 {
- visit::walk_path_segment(self, path.span, segment);
- } else {
- self.with_ban(|this|
- visit::walk_path_segment(this, path.span, segment));
- }
- }
- }
- _ => visit::walk_ty(self, t),
- }
- }
-
- fn visit_mac(&mut self, _mac: &Spanned<Mac_>) {
- // covered in AstValidator
- }
-}
-
pub fn check_crate(session: &Session, krate: &Crate) {
- visit::walk_crate(
- &mut NestedImplTraitVisitor {
- session,
- outer_impl_trait: None,
- }, krate);
-
- visit::walk_crate(
- &mut ImplTraitProjectionVisitor {
- session,
- is_banned: false,
- }, krate);
-
- visit::walk_crate(&mut AstValidator { session }, krate)
+ visit::walk_crate(&mut AstValidator {
+ session,
+ outer_impl_trait: None,
+ is_impl_trait_banned: false,
+ }, krate)
}
}
fn visit_stmt(&mut self, s: &'v hir::Stmt) {
- self.record("Stmt", Id::Node(s.node.id()), s);
+ self.record("Stmt", Id::Node(s.id), s);
hir_visit::walk_stmt(self, s)
}
hir_visit::walk_pat(self, p)
}
- fn visit_decl(&mut self, d: &'v hir::Decl) {
- self.record("Decl", Id::None, d);
- hir_visit::walk_decl(self, d)
- }
-
fn visit_expr(&mut self, ex: &'v hir::Expr) {
self.record("Expr", Id::Node(ex.id), ex);
hir_visit::walk_expr(self, ex)
self.in_static = false;
match self.tcx.hir().body_owner_kind(item_id) {
+ hir::BodyOwnerKind::Closure |
hir::BodyOwnerKind::Fn => self.in_fn = true,
hir::BodyOwnerKind::Static(_) => self.in_static = true,
_ => {}
fn check_stmt(&mut self, stmt: &'tcx hir::Stmt) -> Promotability {
match stmt.node {
- hir::StmtKind::Decl(ref decl, _node_id) => {
- match &decl.node {
- hir::DeclKind::Local(local) => {
- if self.remove_mut_rvalue_borrow(&local.pat) {
- if let Some(init) = &local.init {
- self.mut_rvalue_borrows.insert(init.id);
- }
- }
-
- if let Some(ref expr) = local.init {
- let _ = self.check_expr(&expr);
- }
- NotPromotable
+ hir::StmtKind::Local(ref local) => {
+ if self.remove_mut_rvalue_borrow(&local.pat) {
+ if let Some(init) = &local.init {
+ self.mut_rvalue_borrows.insert(init.id);
}
- // Item statements are allowed
- hir::DeclKind::Item(_) => Promotable
}
+
+ if let Some(ref expr) = local.init {
+ let _ = self.check_expr(&expr);
+ }
+ NotPromotable
}
- hir::StmtKind::Expr(ref box_expr, _node_id) |
- hir::StmtKind::Semi(ref box_expr, _node_id) => {
+ // Item statements are allowed
+ hir::StmtKind::Item(..) => Promotable,
+ hir::StmtKind::Expr(ref box_expr) |
+ hir::StmtKind::Semi(ref box_expr) => {
let _ = self.check_expr(box_expr);
NotPromotable
}
extern crate syntax_pos;
extern crate rustc_data_structures;
-use rustc::hir::{self, Node, PatKind};
+use rustc::hir::{self, Node, PatKind, AssociatedItemKind};
use rustc::hir::def::Def;
use rustc::hir::def_id::{CRATE_DEF_INDEX, LOCAL_CRATE, CrateNum, DefId};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
let mut reach = self.reach(trait_item_ref.id.node_id, item_level);
reach.generics().predicates();
- if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+ if trait_item_ref.kind == AssociatedItemKind::Type &&
!trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
- hir::AssociatedItemKind::Const => {
+ AssociatedItemKind::Const => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
- hir::AssociatedItemKind::Method { has_self: false } => {
+ AssociatedItemKind::Method { has_self: false } => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
in_assoc_ty: false,
}
}
+
+ fn check_trait_or_impl_item(&self, node_id: ast::NodeId, assoc_item_kind: AssociatedItemKind,
+ defaultness: hir::Defaultness, vis: ty::Visibility) {
+ let mut check = self.check(node_id, vis);
+
+ let (check_ty, is_assoc_ty) = match assoc_item_kind {
+ AssociatedItemKind::Const | AssociatedItemKind::Method { .. } => (true, false),
+ AssociatedItemKind::Type => (defaultness.has_value(), true),
+ // `ty()` for existential types is the underlying type,
+ // it's not a part of interface, so we skip it.
+ AssociatedItemKind::Existential => (false, true),
+ };
+ check.in_assoc_ty = is_assoc_ty;
+ check.generics().predicates();
+ if check_ty {
+ check.ty();
+ }
+ }
}
impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
self.check(item.id, item_visibility).generics().predicates();
for trait_item_ref in trait_item_refs {
- let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
- check.in_assoc_ty = trait_item_ref.kind == hir::AssociatedItemKind::Type;
- check.generics().predicates();
-
- if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
- !trait_item_ref.defaultness.has_value() {
- // No type to visit.
- } else {
- check.ty();
- }
+ self.check_trait_or_impl_item(trait_item_ref.id.node_id, trait_item_ref.kind,
+ trait_item_ref.defaultness, item_visibility);
}
}
hir::ItemKind::TraitAlias(..) => {
} else {
impl_vis
};
- let mut check = self.check(impl_item.id, impl_item_vis);
- check.in_assoc_ty = impl_item_ref.kind == hir::AssociatedItemKind::Type;
- check.generics().predicates().ty();
+ self.check_trait_or_impl_item(impl_item_ref.id.node_id, impl_item_ref.kind,
+ impl_item_ref.defaultness, impl_item_vis);
}
}
}
use std::ptr;
use rustc_data_structures::sync::Lrc;
+use errors::Applicability;
+
use syntax::ast::{Name, Ident};
use syntax::attr;
let module = if orig_name.is_none() && ident.name == keywords::SelfLower.name() {
self.session
.struct_span_err(item.span, "`extern crate self;` requires renaming")
- .span_suggestion(item.span, "try", "extern crate self as name;".into())
+ .span_suggestion_with_applicability(
+ item.span,
+ "try",
+ "extern crate self as name;".into(),
+ Applicability::HasPlaceholders,
+ )
.emit();
return;
} else if orig_name == Some(keywords::SelfLower.name()) {
}
module.populated.set(true);
}
+ Def::Existential(..) |
+ Def::TraitAlias(..) => {
+ self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion));
+ }
Def::Struct(..) | Def::Union(..) => {
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, expansion));
} else if ident.span.rust_2018() {
let msg = "relative paths are not supported in visibilities on 2018 edition";
self.session.struct_span_err(ident.span, msg)
- .span_suggestion(path.span, "try", format!("crate::{}", path))
- .emit();
+ .span_suggestion_with_applicability(
+ path.span,
+ "try",
+ format!("crate::{}", path),
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
return ty::Visibility::Public;
} else {
let ctxt = ident.span.ctxt();
))
}
- if b.span.is_dummy() {
- err.note(¬e_msg);
- } else {
- err.span_note(b.span, ¬e_msg);
- }
+ err.span_note(b.span, ¬e_msg);
for (i, help_msg) in help_msgs.iter().enumerate() {
let or = if i == 0 { "" } else { "or " };
err.help(&format!("{}{}", or, help_msg));
container));
err.span_label(span, format!("`{}` re{} here", name, new_participle));
- if !old_binding.span.is_dummy() {
- err.span_label(self.session.source_map().def_span(old_binding.span),
- format!("previous {} of the {} `{}` here", old_noun, old_kind, name));
- }
+ err.span_label(
+ self.session.source_map().def_span(old_binding.span),
+ format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
+ );
// See https://github.com/rust-lang/rust/issues/32354
if old_binding.is_import() || new_binding.is_import() {
("aarch64-unknown-freebsd", aarch64_unknown_freebsd),
("i686-unknown-freebsd", i686_unknown_freebsd),
+ ("powerpc64-unknown-freebsd", powerpc64_unknown_freebsd),
("x86_64-unknown-freebsd", x86_64_unknown_freebsd),
("i686-unknown-dragonfly", i686_unknown_dragonfly),
--- /dev/null
+use spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::freebsd_base::opts();
+ base.cpu = "ppc64".to_string();
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
+ base.max_atomic_width = Some(64);
+
+ Ok(Target {
+ llvm_target: "powerpc64-unknown-freebsd".to_string(),
+ target_endian: "big".to_string(),
+ target_pointer_width: "64".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "E-m:e-i64:64-n32:64".to_string(),
+ arch: "powerpc64".to_string(),
+ target_os: "freebsd".to_string(),
+ target_env: String::new(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: base,
+ })
+}
def_id: DefId,
) -> Clauses<'tcx> {
match tcx.def_key(def_id).disambiguated_data.data {
- DefPathData::Trait(_) => program_clauses_for_trait(tcx, def_id),
+ DefPathData::Trait(_) |
+ DefPathData::TraitAlias(_) => program_clauses_for_trait(tcx, def_id),
DefPathData::Impl => program_clauses_for_impl(tcx, def_id),
DefPathData::AssocTypeInImpl(..) => program_clauses_for_associated_type_value(tcx, def_id),
DefPathData::AssocTypeInTrait(..) => program_clauses_for_associated_type_def(tcx, def_id),
//! The main routine here is `ast_ty_to_ty()`; each use is parameterized by an
//! instance of `AstConv`.
-use errors::{Applicability, FatalError, DiagnosticId};
+use errors::{Applicability, DiagnosticId};
use hir::{self, GenericArg, GenericArgs};
use hir::def::Def;
use hir::def_id::DefId;
{
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
- let trait_def_id = self.trait_def_id(trait_ref);
self.ast_path_to_mono_trait_ref(trait_ref.path.span,
- trait_def_id,
+ trait_ref.trait_def_id(),
self_ty,
trait_ref.path.segments.last().unwrap())
}
- /// Get the `DefId` of the given trait ref. It _must_ actually be a trait.
- fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
- let path = &trait_ref.path;
- match path.def {
- Def::Trait(trait_def_id) => trait_def_id,
- Def::TraitAlias(alias_def_id) => alias_def_id,
- Def::Err => {
- FatalError.raise();
- }
- _ => unreachable!(),
- }
- }
-
- /// The given trait ref must actually be a trait.
+ /// The given trait-ref must actually be a trait.
pub(super) fn instantiate_poly_trait_ref_inner(&self,
trait_ref: &hir::TraitRef,
self_ty: Ty<'tcx>,
speculative: bool)
-> (ty::PolyTraitRef<'tcx>, Option<Vec<Span>>)
{
- let trait_def_id = self.trait_def_id(trait_ref);
+ let trait_def_id = trait_ref.trait_def_id();
debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
use check::{FnCtxt, Expectation, Diverges, Needs};
use check::coercion::CoerceMany;
+use errors::Applicability;
use rustc::hir::{self, PatKind};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
let suggested_name =
find_best_match_for_name(input, &ident.as_str(), None);
if let Some(suggested_name) = suggested_name {
- err.span_suggestion(*span, "did you mean", suggested_name.to_string());
+ err.span_suggestion_with_applicability(
+ *span,
+ "did you mean",
+ suggested_name.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+
// we don't want to throw `E0027` in case we have thrown `E0026` for them
unmentioned_fields.retain(|&x| x.as_str() != suggested_name.as_str());
}
(self.final_ty.unwrap_or(self.expected_ty), expression_ty)
};
- let reason_label = "expected because of this statement";
let mut db;
match cause.code {
ObligationCauseCode::ReturnNoExpression => {
db.span_label(cause.span, "return type is not `()`");
}
ObligationCauseCode::BlockTailExpression(blk_id) => {
- db = fcx.report_mismatched_types(cause, expected, found, err);
-
- let expr = expression.unwrap_or_else(|| {
- span_bug!(cause.span,
- "supposed to be part of a block tail expression, but the \
- expression is empty");
- });
- fcx.suggest_mismatched_types_on_tail(
- &mut db,
- expr,
+ let parent_id = fcx.tcx.hir().get_parent_node(blk_id);
+ db = self.report_return_mismatched_types(
+ cause,
expected,
found,
- cause.span,
- blk_id,
+ err,
+ fcx,
+ parent_id,
+ expression.map(|expr| (expr, blk_id)),
);
- if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
- if !sp.overlaps(cause.span) {
- db.span_label(*sp, reason_label);
- }
- }
+ }
+ ObligationCauseCode::ReturnType(id) => {
+ db = self.report_return_mismatched_types(
+ cause, expected, found, err, fcx, id, None);
}
_ => {
db = fcx.report_mismatched_types(cause, expected, found, err);
- if let Some(sp) = fcx.ret_coercion_span.borrow().as_ref() {
- if !sp.overlaps(cause.span) {
- db.span_label(*sp, reason_label);
- }
- }
}
}
}
}
+ fn report_return_mismatched_types<'a>(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ err: TypeError<'tcx>,
+ fcx: &FnCtxt<'a, 'gcx, 'tcx>,
+ id: syntax::ast::NodeId,
+ expression: Option<(&'gcx hir::Expr, syntax::ast::NodeId)>,
+ ) -> DiagnosticBuilder<'a> {
+ let mut db = fcx.report_mismatched_types(cause, expected, found, err);
+
+ let mut pointing_at_return_type = false;
+ let mut return_sp = None;
+
+ // Verify that this is a tail expression of a function, otherwise the
+ // label pointing out the cause for the type coercion will be wrong
+ // as prior return coercions would not be relevant (#57664).
+ let parent_id = fcx.tcx.hir().get_parent_node(id);
+ let fn_decl = if let Some((expr, blk_id)) = expression {
+ pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
+ &mut db,
+ expr,
+ expected,
+ found,
+ cause.span,
+ blk_id,
+ );
+ let parent = fcx.tcx.hir().get(parent_id);
+ fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
+ } else {
+ fcx.get_fn_decl(parent_id)
+ };
+
+ if let (Some((fn_decl, can_suggest)), _) = (fn_decl, pointing_at_return_type) {
+ if expression.is_none() {
+ pointing_at_return_type |= fcx.suggest_missing_return_type(
+ &mut db, &fn_decl, expected, found, can_suggest);
+ }
+ if !pointing_at_return_type {
+ return_sp = Some(fn_decl.output.span()); // `impl Trait` return type
+ }
+ }
+ if let (Some(sp), Some(return_sp)) = (fcx.ret_coercion_span.borrow().as_ref(), return_sp) {
+ db.span_label(return_sp, "expected because this return type...");
+ db.span_label( *sp, format!(
+ "...is found to be `{}` here",
+ fcx.resolve_type_vars_with_obligations(expected),
+ ));
+ }
+ db
+ }
+
pub fn complete<'a>(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
if let Some(final_ty) = self.final_ty {
final_ty
false
}
- pub fn check_for_cast(&self,
- err: &mut DiagnosticBuilder<'tcx>,
- expr: &hir::Expr,
- checked_ty: Ty<'tcx>,
- expected_ty: Ty<'tcx>)
- -> bool {
+ pub fn check_for_cast(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ expr: &hir::Expr,
+ checked_ty: Ty<'tcx>,
+ expected_ty: Ty<'tcx>,
+ ) -> bool {
let parent_id = self.tcx.hir().get_parent_node(expr.id);
if let Some(parent) = self.tcx.hir().find(parent_id) {
// Shouldn't suggest `.into()` on `const`s.
// For now, don't suggest casting with `as`.
let can_cast = false;
+ let mut prefix = String::new();
+ if let Some(hir::Node::Expr(hir::Expr {
+ node: hir::ExprKind::Struct(_, fields, _),
+ ..
+ })) = self.tcx.hir().find(self.tcx.hir().get_parent_node(expr.id)) {
+ // `expr` is a literal field for a struct, only suggest if appropriate
+ for field in fields {
+ if field.expr.id == expr.id && field.is_shorthand {
+ // This is a field literal
+ prefix = format!("{}: ", field.ident);
+ break;
+ }
+ }
+ if &prefix == "" {
+ // Likely a field was meant, but this field wasn't found. Do not suggest anything.
+ return false;
+ }
+ }
+
let needs_paren = expr.precedence().order() < (PREC_POSTFIX as i8);
if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) {
let msg = format!("you can cast an `{}` to `{}`", checked_ty, expected_ty);
- let cast_suggestion = format!("{}{}{} as {}",
- if needs_paren { "(" } else { "" },
- src,
- if needs_paren { ")" } else { "" },
- expected_ty);
+ let cast_suggestion = format!(
+ "{}{}{}{} as {}",
+ prefix,
+ if needs_paren { "(" } else { "" },
+ src,
+ if needs_paren { ")" } else { "" },
+ expected_ty,
+ );
let into_suggestion = format!(
- "{}{}{}.into()",
+ "{}{}{}{}.into()",
+ prefix,
if needs_paren { "(" } else { "" },
src,
if needs_paren { ")" } else { "" },
"simd_insert" => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
"simd_extract" => (2, vec![param(0), tcx.types.u32], param(1)),
"simd_cast" => (2, vec![param(0)], param(1)),
+ "simd_bitmask" => (2, vec![param(0)], param(1)),
"simd_select" |
"simd_select_bitmask" => (2, vec![param(0), param(1), param(1)], param(1)),
"simd_reduce_all" | "simd_reduce_any" => (1, vec![param(0)], tcx.types.bool),
match self_ty.value.value.sty {
ty::Dynamic(ref data, ..) => {
if let Some(p) = data.principal() {
- self.fcx.probe(|_| {
- let InferOk { value: self_ty, obligations: _ } =
- self.fcx.probe_instantiate_query_response(
- self.span, &self.orig_steps_var_values, self_ty)
- .unwrap_or_else(|_| {
- span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty)
- });
- self.assemble_inherent_candidates_from_object(self_ty);
- });
+ let InferOk { value: instantiated_self_ty, obligations: _ } =
+ self.fcx.probe_instantiate_query_response(
+ self.span, &self.orig_steps_var_values, self_ty)
+ .unwrap_or_else(|_| {
+ span_bug!(self.span, "{:?} was applicable but now isn't?", self_ty)
+ });
+ self.assemble_inherent_candidates_from_object(instantiated_self_ty);
self.assemble_inherent_impl_candidates_for_type(p.def_id());
}
}
);
if let Some(suggestion) = suggestion {
// enum variant
- err.help(&format!("did you mean `{}`?", suggestion));
+ err.span_suggestion_with_applicability(
+ item_name.span,
+ "did you mean",
+ suggestion.to_string(),
+ Applicability::MaybeIncorrect,
+ );
}
err
}
}
if let Some(lev_candidate) = lev_candidate {
- err.help(&format!("did you mean `{}`?", lev_candidate.ident));
+ err.span_suggestion_with_applicability(
+ span,
+ "did you mean",
+ lev_candidate.ident.to_string(),
+ Applicability::MaybeIncorrect,
+ );
}
err.emit();
}
opt_ty.unwrap_or_else(
|| tcx.mk_float_var(self.next_float_var_id()))
}
- ast::LitKind::Bool(_) => tcx.types.bool
+ ast::LitKind::Bool(_) => tcx.types.bool,
+ ast::LitKind::Err(_) => tcx.types.err,
}
}
struct_span_err!(self.tcx.sess, expr.span, E0572,
"return statement outside of function body").emit();
} else if let Some(ref e) = *expr_opt {
- *self.ret_coercion_span.borrow_mut() = Some(e.span);
+ if self.ret_coercion_span.borrow().is_none() {
+ *self.ret_coercion_span.borrow_mut() = Some(e.span);
+ }
self.check_return_expr(e);
} else {
let mut coercion = self.ret_coercion.as_ref().unwrap().borrow_mut();
- *self.ret_coercion_span.borrow_mut() = Some(expr.span);
+ if self.ret_coercion_span.borrow().is_none() {
+ *self.ret_coercion_span.borrow_mut() = Some(expr.span);
+ }
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
if let Some((fn_decl, _)) = self.get_fn_decl(expr.id) {
coercion.coerce_forced_unit(
pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) {
// Don't do all the complex logic below for `DeclItem`.
match stmt.node {
- hir::StmtKind::Decl(ref decl, _) => {
- if let hir::DeclKind::Item(_) = decl.node {
- return
- }
- }
- hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
+ hir::StmtKind::Item(..) => return,
+ hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {}
}
- self.warn_if_unreachable(stmt.node.id(), stmt.span, "statement");
+ self.warn_if_unreachable(stmt.id, stmt.span, "statement");
// Hide the outer diverging and `has_errors` flags.
let old_diverges = self.diverges.get();
self.has_errors.set(false);
match stmt.node {
- hir::StmtKind::Decl(ref decl, _) => {
- match decl.node {
- hir::DeclKind::Local(ref l) => {
- self.check_decl_local(&l);
- }
- // Ignore for now.
- hir::DeclKind::Item(_) => ()
- }
+ hir::StmtKind::Local(ref l) => {
+ self.check_decl_local(&l);
}
- hir::StmtKind::Expr(ref expr, _) => {
+ // Ignore for now.
+ hir::StmtKind::Item(_) => {}
+ hir::StmtKind::Expr(ref expr) => {
// Check with expected type of `()`.
self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit());
}
- hir::StmtKind::Semi(ref expr, _) => {
+ hir::StmtKind::Semi(ref expr) => {
self.check_expr(&expr);
}
}
found: Ty<'tcx>,
cause_span: Span,
blk_id: ast::NodeId,
- ) {
+ ) -> bool {
self.suggest_missing_semicolon(err, expression, expected, cause_span);
+ let mut pointing_at_return_type = false;
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
- self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest);
+ pointing_at_return_type = self.suggest_missing_return_type(
+ err, &fn_decl, expected, found, can_suggest);
}
self.suggest_ref_or_into(err, expression, expected, found);
+ pointing_at_return_type
}
pub fn suggest_ref_or_into(
/// This routine checks if the return type is left as default, the method is not part of an
/// `impl` block and that it isn't the `main` method. If so, it suggests setting the return
/// type.
- fn suggest_missing_return_type(&self,
- err: &mut DiagnosticBuilder<'tcx>,
- fn_decl: &hir::FnDecl,
- expected: Ty<'tcx>,
- found: Ty<'tcx>,
- can_suggest: bool) {
+ fn suggest_missing_return_type(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ fn_decl: &hir::FnDecl,
+ expected: Ty<'tcx>,
+ found: Ty<'tcx>,
+ can_suggest: bool,
+ ) -> bool {
// Only suggest changing the return type for methods that
// haven't set a return type at all (and aren't `fn main()` or an impl).
match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) {
"try adding a return type",
format!("-> {} ", self.resolve_type_vars_with_obligations(found)),
Applicability::MachineApplicable);
+ true
}
(&hir::FunctionRetTy::DefaultReturn(span), false, true, true) => {
err.span_label(span, "possibly return type missing here?");
+ true
}
(&hir::FunctionRetTy::DefaultReturn(span), _, false, true) => {
// `fn main()` must return `()`, do not suggest changing return type
err.span_label(span, "expected `()` because of default return type");
+ true
}
// expectation was caused by something else, not the default return
- (&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => {}
+ (&hir::FunctionRetTy::DefaultReturn(_), _, _, false) => false,
(&hir::FunctionRetTy::Return(ref ty), _, _, _) => {
// Only point to return type if the expected type is the return type, as if they
// are not, the expectation must have been caused by something else.
if ty.sty == expected.sty {
err.span_label(sp, format!("expected `{}` because of return type",
expected));
+ return true;
}
+ false
}
}
}
None => return None,
};
let last_expr = match last_stmt.node {
- hir::StmtKind::Semi(ref e, _) => e,
+ hir::StmtKind::Semi(ref e) => e,
_ => return None,
};
let last_expr_ty = self.node_ty(last_expr.hir_id);
if let ty::Opaque(def_id, substs) = ty.sty {
trace!("check_existential_types: opaque_ty, {:?}, {:?}", def_id, substs);
let generics = tcx.generics_of(def_id);
- // only check named existential types
- if generics.parent.is_none() {
+ // only check named existential types defined in this crate
+ if generics.parent.is_none() && def_id.is_local() {
let opaque_node_id = tcx.hir().as_local_node_id(def_id).unwrap();
if may_define_existential_type(tcx, fn_def_id, opaque_node_id) {
trace!("check_existential_types may define. Generics: {:#?}", generics);
// In the case of trait aliases, however, we include all bounds in the where clause,
// so e.g., `trait Foo = where u32: PartialEq<Self>` would include `u32: PartialEq<Self>`
// as one of its "superpredicates".
- let is_trait_alias = ty::is_trait_alias(tcx, trait_def_id);
+ let is_trait_alias = tcx.is_trait_alias(trait_def_id);
let superbounds2 = icx.type_parameter_bounds_in_generics(
generics, item.id, self_param_ty, OnlySelfBounds(!is_trait_alias));
#![feature(crate_visibility_modifier)]
#![feature(exhaustive_patterns)]
#![feature(nll)]
-#![feature(quote)]
#![feature(refcell_replace_swap)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_patterns)]
tooltip: Option<(&str, &str)>,
) -> String {
debug!("highlighting: ================\n{}\n==============", src);
- let sess = parse::ParseSess::new(FilePathMapping::empty());
- let fm = sess.source_map().new_source_file(FileName::Custom("stdin".to_string()),
- src.to_string());
-
let mut out = Vec::new();
if let Some((tooltip, class)) = tooltip {
write!(out, "<div class='information'><div class='tooltip {}'>ⓘ<span \
class='tooltiptext'>{}</span></div></div>",
class, tooltip).unwrap();
}
- write_header(class, &mut out).unwrap();
-
- let lexer = match lexer::StringReader::new_without_err(&sess, fm, None, "Output from rustc:") {
- Ok(l) => l,
- Err(_) => {
- let first_line = src.lines().next().unwrap_or_else(|| "");
- let mut err = sess.span_diagnostic
- .struct_warn(&format!("Invalid doc comment starting with: `{}`\n\
- (Ignoring this codeblock)",
- first_line));
- err.emit();
- return String::new();
+
+ let sess = parse::ParseSess::new(FilePathMapping::empty());
+ let fm = sess.source_map().new_source_file(
+ FileName::Custom(String::from("rustdoc-highlighting")),
+ src.to_owned(),
+ );
+ let highlight_result =
+ lexer::StringReader::new_or_buffered_errs(&sess, fm, None).and_then(|lexer| {
+ let mut classifier = Classifier::new(lexer, sess.source_map());
+
+ let mut highlighted_source = vec![];
+ if classifier.write_source(&mut highlighted_source).is_err() {
+ Err(classifier.lexer.buffer_fatal_errors())
+ } else {
+ Ok(String::from_utf8_lossy(&highlighted_source).into_owned())
+ }
+ });
+
+ match highlight_result {
+ Ok(highlighted_source) => {
+ write_header(class, &mut out).unwrap();
+ write!(out, "{}", highlighted_source).unwrap();
+ if let Some(extension) = extension {
+ write!(out, "{}", extension).unwrap();
+ }
+ write_footer(&mut out).unwrap();
}
- };
- let mut classifier = Classifier::new(lexer, sess.source_map());
- if classifier.write_source(&mut out).is_err() {
- classifier.lexer.emit_fatal_errors();
- return format!("<pre>{}</pre>", src);
- }
+ Err(errors) => {
+ // If errors are encountered while trying to highlight, cancel the errors and just emit
+ // the unhighlighted source. The errors will have already been reported in the
+ // `check-code-block-syntax` pass.
+ for mut error in errors {
+ error.cancel();
+ }
- if let Some(extension) = extension {
- write!(out, "{}", extension).unwrap();
+ write!(out, "<pre><code>{}</code></pre>", src).unwrap();
+ }
}
- write_footer(&mut out).unwrap();
+
String::from_utf8_lossy(&out[..]).into_owned()
}
}
}
+enum HighlightError {
+ LexError,
+ IoError(io::Error),
+}
+
+impl From<io::Error> for HighlightError {
+ fn from(err: io::Error) -> Self {
+ HighlightError::IoError(err)
+ }
+}
+
impl<'a> Classifier<'a> {
fn new(lexer: lexer::StringReader<'a>, source_map: &'a SourceMap) -> Classifier<'a> {
Classifier {
}
}
- /// Gets the next token out of the lexer, emitting fatal errors if lexing fails.
- fn try_next_token(&mut self) -> io::Result<TokenAndSpan> {
+ /// Gets the next token out of the lexer.
+ fn try_next_token(&mut self) -> Result<TokenAndSpan, HighlightError> {
match self.lexer.try_next_token() {
Ok(tas) => Ok(tas),
- Err(_) => {
- let mut err = self.lexer.sess.span_diagnostic
- .struct_warn("Backing out of syntax highlighting");
- err.note("You probably did not intend to render this as a rust code-block");
- err.emit();
- Err(io::Error::new(io::ErrorKind::Other, ""))
- }
+ Err(_) => Err(HighlightError::LexError),
}
}
/// source.
fn write_source<W: Writer>(&mut self,
out: &mut W)
- -> io::Result<()> {
+ -> Result<(), HighlightError> {
loop {
let next = self.try_next_token()?;
if next.tok == token::Eof {
fn write_token<W: Writer>(&mut self,
out: &mut W,
tas: TokenAndSpan)
- -> io::Result<()> {
+ -> Result<(), HighlightError> {
let klass = match tas.tok {
token::Shebang(s) => {
out.string(Escape(&s.as_str()), Class::None)?;
token::Literal(lit, _suf) => {
match lit {
// Text literals.
- token::Byte(..) | token::Char(..) |
+ token::Byte(..) | token::Char(..) | token::Err(..) |
token::ByteStr(..) | token::ByteStrRaw(..) |
token::Str_(..) | token::StrRaw(..) => Class::String,
// Anything that didn't return above is the simple case where we the
// class just spans a single token, so we can use the `string` method.
- out.string(Escape(&self.snip(tas.sp)), klass)
+ out.string(Escape(&self.snip(tas.sp)), klass)?;
+
+ Ok(())
}
// Helper function to get a snippet from the source_map.
root_path = page.root_path,
css_class = page.css_class,
logo = if layout.logo.is_empty() {
- String::new()
+ format!("<a href='{}{}/index.html'>\
+ <img src='{static_root_path}rust-logo{suffix}.png' alt='logo' width='100'></a>",
+ static_root_path=static_root_path,
+ suffix=page.resource_suffix)
} else {
format!("<a href='{}{}/index.html'>\
<img src='{}' alt='logo' width='100'></a>",
description = page.description,
keywords = page.keywords,
favicon = if layout.favicon.is_empty() {
- String::new()
+ format!(r#"<link rel="shortcut icon" href="{static_root_path}favicon{suffix}.ico">"#,
+ static_root_path=static_root_path,
+ suffix=page.resource_suffix)
} else {
format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
},
links
}
+#[derive(Debug)]
+crate struct RustCodeBlock {
+ /// The range in the markdown that the code block occupies. Note that this includes the fences
+ /// for fenced code blocks.
+ pub range: Range<usize>,
+ /// The range in the markdown that the code within the code block occupies.
+ pub code: Range<usize>,
+ pub is_fenced: bool,
+ pub syntax: Option<String>,
+}
+
+/// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
+/// untagged (and assumed to be rust).
+crate fn rust_code_blocks(md: &str) -> Vec<RustCodeBlock> {
+ let mut code_blocks = vec![];
+
+ if md.is_empty() {
+ return code_blocks;
+ }
+
+ let mut opts = Options::empty();
+ opts.insert(OPTION_ENABLE_TABLES);
+ opts.insert(OPTION_ENABLE_FOOTNOTES);
+ let mut p = Parser::new_ext(md, opts);
+
+ let mut code_block_start = 0;
+ let mut code_start = 0;
+ let mut is_fenced = false;
+ let mut previous_offset = 0;
+ let mut in_rust_code_block = false;
+ while let Some(event) = p.next() {
+ let offset = p.get_offset();
+
+ match event {
+ Event::Start(Tag::CodeBlock(syntax)) => {
+ let lang_string = if syntax.is_empty() {
+ LangString::all_false()
+ } else {
+ LangString::parse(&*syntax, ErrorCodes::Yes)
+ };
+
+ if lang_string.rust {
+ in_rust_code_block = true;
+
+ code_start = offset;
+ code_block_start = match md[previous_offset..offset].find("```") {
+ Some(fence_idx) => {
+ is_fenced = true;
+ previous_offset + fence_idx
+ }
+ None => offset,
+ };
+ }
+ }
+ Event::End(Tag::CodeBlock(syntax)) if in_rust_code_block => {
+ in_rust_code_block = false;
+
+ let code_block_end = if is_fenced {
+ let fence_str = &md[previous_offset..offset]
+ .chars()
+ .rev()
+ .collect::<String>();
+ fence_str
+ .find("```")
+ .map(|fence_idx| offset - fence_idx)
+ .unwrap_or_else(|| offset)
+ } else if md
+ .as_bytes()
+ .get(offset)
+ .map(|b| *b == b'\n')
+ .unwrap_or_default()
+ {
+ offset - 1
+ } else {
+ offset
+ };
+
+ let code_end = if is_fenced {
+ previous_offset
+ } else {
+ code_block_end
+ };
+
+ code_blocks.push(RustCodeBlock {
+ is_fenced,
+ range: Range {
+ start: code_block_start,
+ end: code_block_end,
+ },
+ code: Range {
+ start: code_start,
+ end: code_end,
+ },
+ syntax: if !syntax.is_empty() {
+ Some(syntax.into_owned())
+ } else {
+ None
+ },
+ });
+ }
+ _ => (),
+ }
+
+ previous_offset = offset;
+ }
+
+ code_blocks
+}
+
#[derive(Clone, Default, Debug)]
pub struct IdMap {
map: FxHashMap<String, usize>,
themes.insert(theme.to_owned());
}
+ if (*cx.shared).layout.logo.is_empty() {
+ write(cx.dst.join(&format!("rust-logo{}.png", cx.shared.resource_suffix)),
+ static_files::RUST_LOGO)?;
+ }
+ if (*cx.shared).layout.favicon.is_empty() {
+ write(cx.dst.join(&format!("favicon{}.ico", cx.shared.resource_suffix)),
+ static_files::RUST_FAVICON)?;
+ }
write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)),
static_files::BRUSH_SVG)?;
write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)),
themes.push(PathBuf::from("settings.css"));
let mut layout = self.shared.layout.clone();
layout.krate = String::new();
- layout.logo = String::new();
- layout.favicon = String::new();
try_err!(layout::render(&mut w, &layout,
&page, &sidebar, &settings,
self.shared.css_file_extension.is_some(),
/// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
pub static LICENSE_MIT: &'static [u8] = include_bytes!("static/LICENSE-MIT.txt");
+/// The contents of `rust-logo.png`, the default icon of the documentation.
+pub static RUST_LOGO: &'static [u8] = include_bytes!("static/rust-logo.png");
+/// The contents of `favicon.ico`, the default favicon of the documentation.
+pub static RUST_FAVICON: &'static [u8] = include_bytes!("static/favicon.ico");
+
/// The built-in themes given to every documentation site.
pub mod themes {
/// The "light" theme, selected by default when no setting is available. Used as the basis for
html_root_url = "https://doc.rust-lang.org/nightly/",
html_playground_url = "https://play.rust-lang.org/")]
+#![feature(bind_by_move_pattern_guards)]
#![feature(rustc_private)]
#![feature(box_patterns)]
#![feature(box_syntax)]
--- /dev/null
+use errors::Applicability;
+use syntax::parse::lexer::{TokenAndSpan, StringReader as Lexer};
+use syntax::parse::{ParseSess, token};
+use syntax::source_map::FilePathMapping;
+use syntax_pos::FileName;
+
+use clean;
+use core::DocContext;
+use fold::DocFolder;
+use html::markdown::{self, RustCodeBlock};
+use passes::Pass;
+
+pub const CHECK_CODE_BLOCK_SYNTAX: Pass =
+ Pass::early("check-code-block-syntax", check_code_block_syntax,
+ "validates syntax inside Rust code blocks");
+
+pub fn check_code_block_syntax(krate: clean::Crate, cx: &DocContext) -> clean::Crate {
+ SyntaxChecker { cx }.fold_crate(krate)
+}
+
+struct SyntaxChecker<'a, 'tcx: 'a, 'rcx: 'a> {
+ cx: &'a DocContext<'a, 'tcx, 'rcx>,
+}
+
+impl<'a, 'tcx, 'rcx> SyntaxChecker<'a, 'tcx, 'rcx> {
+ fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) {
+ let sess = ParseSess::new(FilePathMapping::empty());
+ let source_file = sess.source_map().new_source_file(
+ FileName::Custom(String::from("doctest")),
+ dox[code_block.code].to_owned(),
+ );
+
+ let errors = Lexer::new_or_buffered_errs(&sess, source_file, None).and_then(|mut lexer| {
+ while let Ok(TokenAndSpan { tok, .. }) = lexer.try_next_token() {
+ if tok == token::Eof {
+ break;
+ }
+ }
+
+ let errors = lexer.buffer_fatal_errors();
+
+ if !errors.is_empty() {
+ Err(errors)
+ } else {
+ Ok(())
+ }
+ });
+
+ if let Err(errors) = errors {
+ let mut diag = if let Some(sp) =
+ super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs)
+ {
+ let mut diag = self
+ .cx
+ .sess()
+ .struct_span_warn(sp, "could not parse code block as Rust code");
+
+ for mut err in errors {
+ diag.note(&format!("error from rustc: {}", err.message()));
+ err.cancel();
+ }
+
+ if code_block.syntax.is_none() && code_block.is_fenced {
+ let sp = sp.from_inner_byte_pos(0, 3);
+ diag.span_suggestion_with_applicability(
+ sp,
+ "mark blocks that do not contain Rust code as text",
+ String::from("```text"),
+ Applicability::MachineApplicable,
+ );
+ }
+
+ diag
+ } else {
+ // We couldn't calculate the span of the markdown block that had the error, so our
+ // diagnostics are going to be a bit lacking.
+ let mut diag = self.cx.sess().struct_span_warn(
+ super::span_of_attrs(&item.attrs),
+ "doc comment contains an invalid Rust code block",
+ );
+
+ for mut err in errors {
+ // Don't bother reporting the error, because we can't show where it happened.
+ err.cancel();
+ }
+
+ if code_block.syntax.is_none() && code_block.is_fenced {
+ diag.help("mark blocks that do not contain Rust code as text: ```text");
+ }
+
+ diag
+ };
+
+ diag.emit();
+ }
+ }
+}
+
+impl<'a, 'tcx, 'rcx> DocFolder for SyntaxChecker<'a, 'tcx, 'rcx> {
+ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+ if let Some(dox) = &item.attrs.collapsed_doc_value() {
+ for code_block in markdown::rust_code_blocks(&dox) {
+ self.check_rust_syntax(&item, &dox, code_block);
+ }
+ }
+
+ self.fold_item_recur(item)
+ }
+}
use syntax::ast::{self, Ident, NodeId};
use syntax::feature_gate::UnstableFeatures;
use syntax::symbol::Symbol;
-use syntax_pos::{self, DUMMY_SP};
+use syntax_pos::DUMMY_SP;
use std::ops::Range;
use clean::*;
use passes::{look_for_tests, Pass};
+use super::span_of_attrs;
pub const COLLECT_INTRA_DOC_LINKS: Pass =
Pass::early("collect-intra-doc-links", collect_intra_doc_links,
let parent_scope = resolver.dummy_parent_scope();
if let Ok(def) = resolver.resolve_macro_to_def_inner(&path, MacroKind::Bang,
&parent_scope, false, false) {
- if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
- return Some(def);
+ if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
+ // skip proc-macro stubs, they'll cause `get_macro` to crash
+ } else {
+ if let SyntaxExtension::DeclMacro { .. } = *resolver.get_macro(def) {
+ return Some(def);
+ }
}
}
if let Some(def) = resolver.all_macros.get(&Symbol::intern(path_str)) {
None
}
-pub fn span_of_attrs(attrs: &Attributes) -> syntax_pos::Span {
- if attrs.doc_strings.is_empty() {
- return DUMMY_SP;
- }
- let start = attrs.doc_strings[0].span();
- let end = attrs.doc_strings.last().expect("No doc strings provided").span();
- start.to(end)
-}
-
/// Reports a resolution failure diagnostic.
///
-/// Ideally we can report the diagnostic with the actual span in the source where the link failure
-/// occurred. However, there's a mismatch between the span in the source code and the span in the
-/// markdown, so we have to do a bit of work to figure out the correspondence.
-///
-/// It's not too hard to find the span for sugared doc comments (`///` and `/**`), because the
-/// source will match the markdown exactly, excluding the comment markers. However, it's much more
-/// difficult to calculate the spans for unsugared docs, because we have to deal with escaping and
-/// other source features. So, we attempt to find the exact source span of the resolution failure
-/// in sugared docs, but use the span of the documentation attributes themselves for unsugared
-/// docs. Because this span might be overly large, we display the markdown line containing the
-/// failure as a note.
+/// If we cannot find the exact source span of the resolution failure, we use the span of the
+/// documentation attributes themselves. This is a little heavy-handed, so we display the markdown
+/// line containing the failure as a note as well.
fn resolution_failure(
cx: &DocContext,
attrs: &Attributes,
let msg = format!("`[{}]` cannot be resolved, ignoring it...", path_str);
let mut diag = if let Some(link_range) = link_range {
- let src = cx.sess().source_map().span_to_snippet(sp);
- let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag {
- DocFragment::SugaredDoc(..) => true,
- _ => false,
- });
-
- if let (Ok(src), true) = (src, is_all_sugared_doc) {
- // The number of markdown lines up to and including the resolution failure.
- let num_lines = dox[..link_range.start].lines().count();
-
- // We use `split_terminator('\n')` instead of `lines()` when counting bytes to ensure
- // that DOS-style line endings do not cause the spans to be calculated incorrectly.
- let mut src_lines = src.split_terminator('\n');
- let mut md_lines = dox.split_terminator('\n').take(num_lines).peekable();
-
- // The number of bytes from the start of the source span to the resolution failure that
- // are *not* part of the markdown, like comment markers.
- let mut extra_src_bytes = 0;
-
- while let Some(md_line) = md_lines.next() {
- loop {
- let source_line = src_lines
- .next()
- .expect("could not find markdown line in source");
-
- match source_line.find(md_line) {
- Some(offset) => {
- extra_src_bytes += if md_lines.peek().is_some() {
- source_line.len() - md_line.len()
- } else {
- offset
- };
- break;
- }
- None => {
- // Since this is a source line that doesn't include a markdown line,
- // we have to count the newline that we split from earlier.
- extra_src_bytes += source_line.len() + 1;
- }
- }
- }
- }
-
- let sp = sp.from_inner_byte_pos(
- link_range.start + extra_src_bytes,
- link_range.end + extra_src_bytes,
- );
-
+ if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs) {
let mut diag = cx.tcx.struct_span_lint_node(
lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
NodeId::from_u32(0),
use std::mem;
use std::fmt;
use syntax::ast::NodeId;
+use syntax_pos::{DUMMY_SP, Span};
+use std::ops::Range;
use clean::{self, GetDefId, Item};
use core::{DocContext, DocAccessLevels};
use html::markdown::{find_testable_code, ErrorCodes, LangString};
-use self::collect_intra_doc_links::span_of_attrs;
-
mod collapse_docs;
pub use self::collapse_docs::COLLAPSE_DOCS;
mod collect_trait_impls;
pub use self::collect_trait_impls::COLLECT_TRAIT_IMPLS;
+mod check_code_block_syntax;
+pub use self::check_code_block_syntax::CHECK_CODE_BLOCK_SYNTAX;
+
/// Represents a single pass.
#[derive(Copy, Clone)]
pub enum Pass {
STRIP_PRIV_IMPORTS,
PROPAGATE_DOC_CFG,
COLLECT_INTRA_DOC_LINKS,
+ CHECK_CODE_BLOCK_SYNTAX,
COLLECT_TRAIT_IMPLS,
];
"strip-hidden",
"strip-private",
"collect-intra-doc-links",
+ "check-code-block-syntax",
"collapse-docs",
"unindent-comments",
"propagate-doc-cfg",
"check-private-items-doc-tests",
"strip-priv-imports",
"collect-intra-doc-links",
+ "check-code-block-syntax",
"collapse-docs",
"unindent-comments",
"propagate-doc-cfg",
}
}
}
+
+/// Return a span encompassing all the given attributes.
+crate fn span_of_attrs(attrs: &clean::Attributes) -> Span {
+ if attrs.doc_strings.is_empty() {
+ return DUMMY_SP;
+ }
+ let start = attrs.doc_strings[0].span();
+ let end = attrs.doc_strings.last().expect("No doc strings provided").span();
+ start.to(end)
+}
+
+/// Attempts to match a range of bytes from parsed markdown to a `Span` in the source code.
+///
+/// This method will return `None` if we cannot construct a span from the source map or if the
+/// attributes are not all sugared doc comments. It's difficult to calculate the correct span in
+/// that case due to escaping and other source features.
+crate fn source_span_for_markdown_range(
+ cx: &DocContext,
+ markdown: &str,
+ md_range: &Range<usize>,
+ attrs: &clean::Attributes,
+) -> Option<Span> {
+ let is_all_sugared_doc = attrs.doc_strings.iter().all(|frag| match frag {
+ clean::DocFragment::SugaredDoc(..) => true,
+ _ => false,
+ });
+
+ if !is_all_sugared_doc {
+ return None;
+ }
+
+ let snippet = cx
+ .sess()
+ .source_map()
+ .span_to_snippet(span_of_attrs(attrs))
+ .ok()?;
+
+ let starting_line = markdown[..md_range.start].lines().count() - 1;
+ let ending_line = markdown[..md_range.end].lines().count() - 1;
+
+ // We use `split_terminator('\n')` instead of `lines()` when counting bytes so that we only
+ // we can treat CRLF and LF line endings the same way.
+ let mut src_lines = snippet.split_terminator('\n');
+ let md_lines = markdown.split_terminator('\n');
+
+ // The number of bytes from the source span to the markdown span that are not part
+ // of the markdown, like comment markers.
+ let mut start_bytes = 0;
+ let mut end_bytes = 0;
+
+ 'outer: for (line_no, md_line) in md_lines.enumerate() {
+ loop {
+ let source_line = src_lines.next().expect("could not find markdown in source");
+ match source_line.find(md_line) {
+ Some(offset) => {
+ if line_no == starting_line {
+ start_bytes += offset;
+
+ if starting_line == ending_line {
+ break 'outer;
+ }
+ } else if line_no == ending_line {
+ end_bytes += offset;
+ break 'outer;
+ } else if line_no < starting_line {
+ start_bytes += source_line.len() - md_line.len();
+ } else {
+ end_bytes += source_line.len() - md_line.len();
+ }
+ break;
+ }
+ None => {
+ // Since this is a source line that doesn't include a markdown line,
+ // we have to count the newline that we split from earlier.
+ if line_no <= starting_line {
+ start_bytes += source_line.len() + 1;
+ } else {
+ end_bytes += source_line.len() + 1;
+ }
+ }
+ }
+ }
+ }
+
+ let sp = span_of_attrs(attrs).from_inner_byte_pos(
+ md_range.start + start_bytes,
+ md_range.end + start_bytes + end_bytes,
+ );
+
+ Some(sp)
+}
#[doc(inline)]
pub use core::future::*;
-/// Wrap a future in a generator.
+/// Wrap a generator in a future.
///
/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give
/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`).
//! primitives](#primitives), [standard macros](#macros), [I/O] and
//! [multithreading], among [many other things][other].
//!
-//! `std` is available to all Rust crates by default, just as if each one
-//! contained an `extern crate std;` import at the [crate root]. Therefore the
+//! `std` is available to all Rust crates by default. Therefore the
//! standard library can be accessed in [`use`] statements through the path
-//! `std`, as in [`use std::env`], or in expressions through the absolute path
-//! `::std`, as in [`::std::env::args`].
+//! `std`, as in [`use std::env`].
//!
//! # How to read this documentation
//!
//! [TCP]: net/struct.TcpStream.html
//! [The Rust Prelude]: prelude/index.html
//! [UDP]: net/struct.UdpSocket.html
-//! [`::std::env::args`]: env/fn.args.html
//! [`Arc`]: sync/struct.Arc.html
//! [owned slice]: boxed/index.html
//! [`Cell`]: cell/struct.Cell.html
//! [`thread`]: thread/index.html
//! [`use std::env`]: env/index.html
//! [`use`]: ../book/ch07-02-modules-and-use-to-control-scope-and-privacy.html#the-use-keyword-to-bring-paths-into-a-scope
-//! [crate root]: ../book/ch07-01-packages-and-crates-for-making-libraries-and-executables.html
//! [crates.io]: https://crates.io
//! [deref-coercions]: ../book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods
//! [files]: fs/struct.File.html
pub use sys::abi::mem::*;
}
-pub use sys::ext::{io, arch};
+pub use sys::ext::{io, arch, ffi};
--- /dev/null
+//! SGX-specific extension to the primitives in the `std::ffi` module
+
+#![unstable(feature = "sgx_platform", issue = "56975")]
+
+use ffi::{OsStr, OsString};
+use mem;
+use sys::os_str::Buf;
+use sys_common::{FromInner, IntoInner, AsInner};
+
+/// SGX-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait OsStringExt {
+ /// Creates an [`OsString`] from a byte vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let bytes = b"foo".to_vec();
+ /// let os_string = OsString::from_vec(bytes);
+ /// assert_eq!(os_string.to_str(), Some("foo"));
+ /// ```
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ fn from_vec(vec: Vec<u8>) -> Self;
+
+ /// Yields the underlying byte vector of this [`OsString`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let mut os_string = OsString::new();
+ /// os_string.push("foo");
+ /// let bytes = os_string.into_vec();
+ /// assert_eq!(bytes, b"foo");
+ /// ```
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ fn into_vec(self) -> Vec<u8>;
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl OsStringExt for OsString {
+ fn from_vec(vec: Vec<u8>) -> OsString {
+ FromInner::from_inner(Buf { inner: vec })
+ }
+ fn into_vec(self) -> Vec<u8> {
+ self.into_inner().inner
+ }
+}
+
+/// SGX-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
+#[unstable(feature = "sgx_platform", issue = "56975")]
+pub trait OsStrExt {
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ /// Creates an [`OsStr`] from a byte slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ /// use std::os::unix::ffi::OsStrExt;
+ ///
+ /// let bytes = b"foo";
+ /// let os_str = OsStr::from_bytes(bytes);
+ /// assert_eq!(os_str.to_str(), Some("foo"));
+ /// ```
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
+ fn from_bytes(slice: &[u8]) -> &Self;
+
+ /// Gets the underlying byte view of the [`OsStr`] slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ /// use std::os::unix::ffi::OsStrExt;
+ ///
+ /// let mut os_str = OsStr::new("foo");
+ /// let bytes = os_str.as_bytes();
+ /// assert_eq!(bytes, b"foo");
+ /// ```
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
+ #[unstable(feature = "sgx_platform", issue = "56975")]
+ fn as_bytes(&self) -> &[u8];
+}
+
+#[unstable(feature = "sgx_platform", issue = "56975")]
+impl OsStrExt for OsStr {
+ fn from_bytes(slice: &[u8]) -> &OsStr {
+ unsafe { mem::transmute(slice) }
+ }
+ fn as_bytes(&self) -> &[u8] {
+ &self.as_inner().inner
+ }
+}
pub mod arch;
pub mod io;
+pub mod ffi;
+use alloc::{self, Layout};
use num::NonZeroUsize;
use slice;
use str;
self.__write_unlock(rguard, wguard);
}
+ // only used by __rust_rwlock_unlock below
#[inline]
unsafe fn unlock(&self) {
let rguard = self.readers.lock();
const EINVAL: i32 = 22;
+// used by libunwind port
#[no_mangle]
pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
if p.is_null() {
return 0;
}
+// the following functions are also used by the libunwind port. They're
+// included here to make sure parallel codegen and LTO don't mess things up.
#[no_mangle]
pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
if s < 0 {
::sys::abort_internal();
}
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
+ alloc::alloc(Layout::from_size_align_unchecked(size, align))
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
+ alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+}
+
#[cfg(test)]
mod tests {
register_dtor_fallback(t, dtor);
}
-// macOS's analog of the above linux function is this _tlv_atexit function.
-// The disassembly of thread_local globals in C++ (at least produced by
-// clang) will have this show up in the output.
+// This implementation is very similar to register_dtor_fallback in
+// sys_common/thread_local.rs. The main difference is that we want to hook into
+// macOS's analog of the above linux function, _tlv_atexit. OSX will run the
+// registered dtors before any TLS slots get freed, and when the main thread
+// exits.
+//
+// Unfortunately, calling _tlv_atexit while tls dtors are running is UB. The
+// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
+// thread. thread_local dtors are pushed to the DTOR list without calling
+// _tlv_atexit.
#[cfg(target_os = "macos")]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+ use cell::Cell;
+ use ptr;
+
+ #[thread_local]
+ static REGISTERED: Cell<bool> = Cell::new(false);
+ if !REGISTERED.get() {
+ _tlv_atexit(run_dtors, ptr::null_mut());
+ REGISTERED.set(true);
+ }
+
+ type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+
+ #[thread_local]
+ static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+ if DTORS.get().is_null() {
+ let v: Box<List> = box Vec::new();
+ DTORS.set(Box::into_raw(v));
+ }
+
extern {
fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
arg: *mut u8);
}
- _tlv_atexit(dtor, t);
+
+ let list: &mut List = &mut *DTORS.get();
+ list.push((t, dtor));
+
+ unsafe extern fn run_dtors(_: *mut u8) {
+ let mut ptr = DTORS.replace(ptr::null_mut());
+ while !ptr.is_null() {
+ let list = Box::from_raw(ptr);
+ for (ptr, dtor) in list.into_iter() {
+ dtor(ptr);
+ }
+ ptr = DTORS.replace(ptr::null_mut());
+ }
+ }
}
pub fn requires_move_before_drop() -> bool {
- // The macOS implementation of TLS apparently had an odd aspect to it
- // where the pointer we have may be overwritten while this destructor
- // is running. Specifically if a TLS destructor re-accesses TLS it may
- // trigger a re-initialization of all TLS variables, paving over at
- // least some destroyed ones with initial values.
- //
- // This means that if we drop a TLS value in place on macOS that we could
- // revert the value to its original state halfway through the
- // destructor, which would be bad!
- //
- // Hence, we use `ptr::read` on macOS (to move to a "safe" location)
- // instead of drop_in_place.
- cfg!(target_os = "macos")
+ false
}
use cmp::Ordering;
use fmt;
use mem;
-use sync::Once;
use sys::c;
-use sys::cvt;
-use sys_common::mul_div_u64;
use time::Duration;
use convert::TryInto;
use core::hash::{Hash, Hasher};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct Instant {
- t: c::LARGE_INTEGER,
+ // This duration is relative to an arbitrary microsecond epoch
+ // from the winapi QueryPerformanceCounter function.
+ t: Duration,
}
#[derive(Copy, Clone)]
impl Instant {
pub fn now() -> Instant {
- let mut t = Instant { t: 0 };
- cvt(unsafe {
- c::QueryPerformanceCounter(&mut t.t)
- }).unwrap();
- t
+ // High precision timing on windows operates in "Performance Counter"
+ // units, as returned by the WINAPI QueryPerformanceCounter function.
+ // These relate to seconds by a factor of QueryPerformanceFrequency.
+ // In order to keep unit conversions out of normal interval math, we
+ // measure in QPC units and immediately convert to nanoseconds.
+ perf_counter::PerformanceCounterInstant::now().into()
}
pub fn actually_monotonic() -> bool {
}
pub const fn zero() -> Instant {
- Instant { t: 0 }
+ Instant { t: Duration::from_secs(0) }
}
pub fn sub_instant(&self, other: &Instant) -> Duration {
- // Values which are +- 1 need to be considered as basically the same
- // units in time due to various measurement oddities, according to
- // Windows [1]
- //
- // [1]:
- // https://msdn.microsoft.com/en-us/library/windows/desktop
- // /dn553408%28v=vs.85%29.aspx#guidance
- if other.t > self.t && other.t - self.t == 1 {
+ // On windows there's a threshold below which we consider two timestamps
+ // equivalent due to measurement error. For more details + doc link,
+ // check the docs on epsilon.
+ let epsilon =
+ perf_counter::PerformanceCounterInstant::epsilon();
+ if other.t > self.t && other.t - self.t <= epsilon {
return Duration::new(0, 0)
}
- let diff = (self.t as u64).checked_sub(other.t as u64)
- .expect("specified instant was later than \
- self");
- let nanos = mul_div_u64(diff, NANOS_PER_SEC, frequency() as u64);
- Duration::new(nanos / NANOS_PER_SEC, (nanos % NANOS_PER_SEC) as u32)
+ self.t.checked_sub(other.t)
+ .expect("specified instant was later than self")
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
- let freq = frequency() as u64;
- let t = other.as_secs()
- .checked_mul(freq)?
- .checked_add(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))?
- .checked_add(self.t as u64)?;
Some(Instant {
- t: t as c::LARGE_INTEGER,
+ t: self.t.checked_add(*other)?
})
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
- let freq = frequency() as u64;
- let t = other.as_secs().checked_mul(freq).and_then(|i| {
- (self.t as u64).checked_sub(i)
- }).and_then(|i| {
- i.checked_sub(mul_div_u64(other.subsec_nanos() as u64, freq, NANOS_PER_SEC))
- })?;
Some(Instant {
- t: t as c::LARGE_INTEGER,
+ t: self.t.checked_sub(*other)?
})
}
}
((intervals % INTERVALS_PER_SEC) * 100) as u32)
}
-fn frequency() -> c::LARGE_INTEGER {
- static mut FREQUENCY: c::LARGE_INTEGER = 0;
- static ONCE: Once = Once::new();
+mod perf_counter {
+ use super::{NANOS_PER_SEC};
+ use sync::Once;
+ use sys_common::mul_div_u64;
+ use sys::c;
+ use sys::cvt;
+ use time::Duration;
+
+ pub struct PerformanceCounterInstant {
+ ts: c::LARGE_INTEGER
+ }
+ impl PerformanceCounterInstant {
+ pub fn now() -> Self {
+ Self {
+ ts: query()
+ }
+ }
- unsafe {
- ONCE.call_once(|| {
- cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap();
- });
- FREQUENCY
+ // Per microsoft docs, the margin of error for cross-thread time comparisons
+ // using QueryPerformanceCounter is 1 "tick" -- defined as 1/frequency().
+ // Reference: https://docs.microsoft.com/en-us/windows/desktop/SysInfo
+ // /acquiring-high-resolution-time-stamps
+ pub fn epsilon() -> Duration {
+ let epsilon = NANOS_PER_SEC / (frequency() as u64);
+ Duration::from_nanos(epsilon)
+ }
+ }
+ impl From<PerformanceCounterInstant> for super::Instant {
+ fn from(other: PerformanceCounterInstant) -> Self {
+ let freq = frequency() as u64;
+ let instant_nsec = mul_div_u64(other.ts as u64, NANOS_PER_SEC, freq);
+ Self {
+ t: Duration::from_nanos(instant_nsec)
+ }
+ }
+ }
+
+ fn frequency() -> c::LARGE_INTEGER {
+ static mut FREQUENCY: c::LARGE_INTEGER = 0;
+ static ONCE: Once = Once::new();
+
+ unsafe {
+ ONCE.call_once(|| {
+ cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap();
+ });
+ FREQUENCY
+ }
+ }
+
+ fn query() -> c::LARGE_INTEGER {
+ let mut qpc_value: c::LARGE_INTEGER = 0;
+ cvt(unsafe {
+ c::QueryPerformanceCounter(&mut qpc_value)
+ }).unwrap();
+ qpc_value
}
}
/// destroyed, but not all platforms have this guard. Those platforms that do
/// not guard typically have a synthetic limit after which point no more
/// destructors are run.
-/// 3. On macOS, initializing TLS during destruction of other TLS slots can
-/// sometimes cancel *all* destructors for the current thread, whether or not
-/// the slots have already had their destructors run or not.
///
/// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
/// [`thread_local!`]: ../../std/macro.thread_local.html
}
// Note that this test will deadlock if TLS destructors aren't run (this
- // requires the destructor to be run to pass the test). macOS has a known bug
- // where dtors-in-dtors may cancel other destructors, so we just ignore this
- // test on macOS.
+ // requires the destructor to be run to pass the test).
#[test]
- #[cfg_attr(target_os = "macos", ignore)]
fn dtors_in_dtors_in_dtors() {
struct S1(Sender<()>);
thread_local!(static K1: UnsafeCell<Option<S1>> = UnsafeCell::new(None));
assert_eq!(a + year, a.checked_add(year).unwrap());
}
+ #[test]
+ fn instant_math_is_associative() {
+ let now = Instant::now();
+ let offset = Duration::from_millis(5);
+ // Changing the order of instant math shouldn't change the results,
+ // especially when the expression reduces to X + identity.
+ assert_eq!((now + offset) - now, (now - now) + offset);
+ }
+
#[test]
#[should_panic]
fn instant_duration_panic() {
use source_map::{dummy_spanned, respan, Spanned};
use symbol::{keywords, Symbol};
use syntax_pos::{Span, DUMMY_SP};
-use tokenstream::{ThinTokenStream, TokenStream};
+use tokenstream::TokenStream;
use ThinVec;
use rustc_data_structures::fx::FxHashSet;
/// The `<'a, A,B,C>` in `foo::bar::baz::<'a, A,B,C>`
AngleBracketed(AngleBracketedArgs),
/// The `(A,B)` and `C` in `Foo(A,B) -> C`
- Parenthesized(ParenthesisedArgs),
+ Parenthesized(ParenthesizedArgs),
}
impl GenericArgs {
+ pub fn is_parenthesized(&self) -> bool {
+ match *self {
+ Parenthesized(..) => true,
+ _ => false,
+ }
+ }
+
+ pub fn is_angle_bracketed(&self) -> bool {
+ match *self {
+ AngleBracketed(..) => true,
+ _ => false,
+ }
+ }
+
pub fn span(&self) -> Span {
match *self {
AngleBracketed(ref data) => data.span,
}
}
-impl Into<Option<P<GenericArgs>>> for ParenthesisedArgs {
+impl Into<Option<P<GenericArgs>>> for ParenthesizedArgs {
fn into(self) -> Option<P<GenericArgs>> {
Some(P(GenericArgs::Parenthesized(self)))
}
/// A path like `Foo(A,B) -> C`
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
-pub struct ParenthesisedArgs {
+pub struct ParenthesizedArgs {
/// Overall span
pub span: Span,
pub output: Option<P<Ty>>,
}
+impl ParenthesizedArgs {
+ pub fn as_angle_bracketed_args(&self) -> AngleBracketedArgs {
+ AngleBracketedArgs {
+ span: self.span,
+ args: self.inputs.iter().cloned().map(|input| GenericArg::Type(input)).collect(),
+ bindings: vec![],
+ }
+ }
+}
+
// hack to ensure that we don't try to access the private parts of `NodeId` in this module
mod node_id_inner {
use rustc_data_structures::indexed_vec::Idx;
pub struct Mac_ {
pub path: Path,
pub delim: MacDelimiter,
- pub tts: ThinTokenStream,
+ pub tts: TokenStream,
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Debug)]
impl Mac_ {
pub fn stream(&self) -> TokenStream {
- self.tts.stream()
+ self.tts.clone()
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct MacroDef {
- pub tokens: ThinTokenStream,
+ pub tokens: TokenStream,
pub legacy: bool,
}
FloatUnsuffixed(Symbol),
/// A boolean literal.
Bool(bool),
+ /// A recovered character literal that contains mutliple `char`s, most likely a typo.
+ Err(Symbol),
}
impl LitKind {
| LitKind::ByteStr(..)
| LitKind::Byte(..)
| LitKind::Char(..)
+ | LitKind::Err(..)
| LitKind::Int(_, LitIntType::Unsuffixed)
| LitKind::FloatUnsuffixed(..)
| LitKind::Bool(..) => true,
}
Some(TokenTree::Delimited(_, delim, ref tts)) if delim == token::Paren => {
tokens.next();
- tts.stream()
+ tts.clone()
}
_ => return Some(MetaItemKind::Word),
};
} else {
"false"
})), false),
+ LitKind::Err(val) => Token::Literal(token::Lit::Err(val), None),
}
}
+++ /dev/null
-use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, Ty};
-use source_map::respan;
-use syntax_pos::{Span, DUMMY_SP};
-use ext::base::ExtCtxt;
-use ext::base;
-use ext::build::AstBuilder;
-use parse::parser::{Parser, PathStyle};
-use parse::token;
-use ptr::P;
-use tokenstream::{DelimSpan, TokenStream, TokenTree};
-
-/// Quasiquoting works via token trees.
-///
-/// This is registered as a set of expression syntax extension called quote!
-/// that lifts its argument token-tree to an AST representing the
-/// construction of the same token tree, with `token::SubstNt` interpreted
-/// as antiquotes (splices).
-
-pub mod rt {
- use ast;
- use source_map::Spanned;
- use ext::base::ExtCtxt;
- use parse::{self, classify};
- use parse::token::{self, Token};
- use ptr::P;
- use symbol::Symbol;
- use ThinVec;
-
- use tokenstream::{DelimSpan, TokenTree, TokenStream};
-
- pub use parse::new_parser_from_tts;
- pub use syntax_pos::{BytePos, Span, DUMMY_SP, FileName};
- pub use source_map::{dummy_spanned};
-
- pub trait ToTokens {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>;
- }
-
- impl ToTokens for TokenTree {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- vec![self.clone()]
- }
- }
-
- impl<T: ToTokens> ToTokens for Vec<T> {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- self.iter().flat_map(|t| t.to_tokens(cx)).collect()
- }
- }
-
- impl<T: ToTokens> ToTokens for Spanned<T> {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- // FIXME: use the span?
- self.node.to_tokens(cx)
- }
- }
-
- impl<T: ToTokens> ToTokens for Option<T> {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- match *self {
- Some(ref t) => t.to_tokens(cx),
- None => Vec::new(),
- }
- }
- }
-
- impl ToTokens for ast::Ident {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- vec![TokenTree::Token(self.span, Token::from_ast_ident(*self))]
- }
- }
-
- impl ToTokens for ast::Path {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtPath(self.clone());
- vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Ty {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtTy(P(self.clone()));
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Block {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtBlock(P(self.clone()));
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Generics {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtGenerics(self.clone());
- vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::WhereClause {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtWhereClause(self.clone());
- vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for P<ast::Item> {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtItem(self.clone());
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::ImplItem {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtImplItem(self.clone());
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for P<ast::ImplItem> {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtImplItem((**self).clone());
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::TraitItem {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtTraitItem(self.clone());
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Stmt {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtStmt(self.clone());
- let mut tts = vec![TokenTree::Token(self.span, Token::interpolated(nt))];
-
- // Some statements require a trailing semicolon.
- if classify::stmt_ends_with_semi(&self.node) {
- tts.push(TokenTree::Token(self.span, token::Semi));
- }
-
- tts
- }
- }
-
- impl ToTokens for P<ast::Expr> {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtExpr(self.clone());
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for P<ast::Pat> {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtPat(self.clone());
- vec![TokenTree::Token(self.span, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Arm {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtArm(self.clone());
- vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Arg {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtArg(self.clone());
- vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for P<ast::Block> {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtBlock(self.clone());
- vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Lifetime {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- vec![TokenTree::Token(self.ident.span, token::Lifetime(self.ident))]
- }
- }
-
- macro_rules! impl_to_tokens_slice {
- ($t: ty, $sep: expr) => {
- impl ToTokens for [$t] {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- let mut v = vec![];
- for (i, x) in self.iter().enumerate() {
- if i > 0 {
- v.extend_from_slice(&$sep);
- }
- v.extend(x.to_tokens(cx));
- }
- v
- }
- }
- };
- }
-
- impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] }
- impl_to_tokens_slice! { P<ast::Item>, [] }
- impl_to_tokens_slice! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] }
-
- impl ToTokens for ast::MetaItem {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let nt = token::NtMeta(self.clone());
- vec![TokenTree::Token(DUMMY_SP, Token::interpolated(nt))]
- }
- }
-
- impl ToTokens for ast::Attribute {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- let mut r = vec![];
- // FIXME: The spans could be better
- r.push(TokenTree::Token(self.span, token::Pound));
- if self.style == ast::AttrStyle::Inner {
- r.push(TokenTree::Token(self.span, token::Not));
- }
- let mut inner = Vec::new();
- for (i, segment) in self.path.segments.iter().enumerate() {
- if i > 0 {
- inner.push(TokenTree::Token(self.span, token::Colon).into());
- }
- inner.push(TokenTree::Token(
- self.span, token::Token::from_ast_ident(segment.ident)
- ).into());
- }
- self.tokens.clone().append_to_tree_and_joint_vec(&mut inner);
-
- let delim_span = DelimSpan::from_single(self.span);
- r.push(TokenTree::Delimited(
- delim_span, token::Bracket, TokenStream::new(inner).into()
- ));
- r
- }
- }
-
- impl ToTokens for str {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- let lit = ast::LitKind::Str(Symbol::intern(self), ast::StrStyle::Cooked);
- dummy_spanned(lit).to_tokens(cx)
- }
- }
-
- impl ToTokens for () {
- fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> {
- vec![
- TokenTree::Delimited(DelimSpan::dummy(), token::Paren, TokenStream::empty().into())
- ]
- }
- }
-
- impl ToTokens for ast::Lit {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- // FIXME: This is wrong
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Lit(self.clone()),
- span: DUMMY_SP,
- attrs: ThinVec::new(),
- }).to_tokens(cx)
- }
- }
-
- impl ToTokens for bool {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- dummy_spanned(ast::LitKind::Bool(*self)).to_tokens(cx)
- }
- }
-
- impl ToTokens for char {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- dummy_spanned(ast::LitKind::Char(*self)).to_tokens(cx)
- }
- }
-
- macro_rules! impl_to_tokens_int {
- (signed, $t:ty, $tag:expr) => (
- impl ToTokens for $t {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- let val = if *self < 0 {
- -self
- } else {
- *self
- };
- let lit = ast::LitKind::Int(val as u128, ast::LitIntType::Signed($tag));
- let lit = P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Lit(dummy_spanned(lit)),
- span: DUMMY_SP,
- attrs: ThinVec::new(),
- });
- if *self >= 0 {
- return lit.to_tokens(cx);
- }
- P(ast::Expr {
- id: ast::DUMMY_NODE_ID,
- node: ast::ExprKind::Unary(ast::UnOp::Neg, lit),
- span: DUMMY_SP,
- attrs: ThinVec::new(),
- }).to_tokens(cx)
- }
- }
- );
- (unsigned, $t:ty, $tag:expr) => (
- impl ToTokens for $t {
- fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> {
- let lit = ast::LitKind::Int(*self as u128, ast::LitIntType::Unsigned($tag));
- dummy_spanned(lit).to_tokens(cx)
- }
- }
- );
- }
-
- impl_to_tokens_int! { signed, isize, ast::IntTy::Isize }
- impl_to_tokens_int! { signed, i8, ast::IntTy::I8 }
- impl_to_tokens_int! { signed, i16, ast::IntTy::I16 }
- impl_to_tokens_int! { signed, i32, ast::IntTy::I32 }
- impl_to_tokens_int! { signed, i64, ast::IntTy::I64 }
-
- impl_to_tokens_int! { unsigned, usize, ast::UintTy::Usize }
- impl_to_tokens_int! { unsigned, u8, ast::UintTy::U8 }
- impl_to_tokens_int! { unsigned, u16, ast::UintTy::U16 }
- impl_to_tokens_int! { unsigned, u32, ast::UintTy::U32 }
- impl_to_tokens_int! { unsigned, u64, ast::UintTy::U64 }
-
- pub trait ExtParseUtils {
- fn parse_item(&self, s: String) -> P<ast::Item>;
- fn parse_expr(&self, s: String) -> P<ast::Expr>;
- fn parse_stmt(&self, s: String) -> ast::Stmt;
- fn parse_tts(&self, s: String) -> Vec<TokenTree>;
- }
-
- impl<'a> ExtParseUtils for ExtCtxt<'a> {
- fn parse_item(&self, s: String) -> P<ast::Item> {
- panictry!(parse::parse_item_from_source_str(
- FileName::quote_expansion_source_code(&s),
- s,
- self.parse_sess())).expect("parse error")
- }
-
- fn parse_stmt(&self, s: String) -> ast::Stmt {
- panictry!(parse::parse_stmt_from_source_str(
- FileName::quote_expansion_source_code(&s),
- s,
- self.parse_sess())).expect("parse error")
- }
-
- fn parse_expr(&self, s: String) -> P<ast::Expr> {
- panictry!(parse::parse_expr_from_source_str(
- FileName::quote_expansion_source_code(&s),
- s,
- self.parse_sess()))
- }
-
- fn parse_tts(&self, s: String) -> Vec<TokenTree> {
- let source_name = FileName::quote_expansion_source_code(&s);
- parse::parse_stream_from_source_str(source_name, s, self.parse_sess(), None)
- .into_trees().collect()
- }
- }
-}
-
-// Replaces `Token::OpenDelim .. Token::CloseDelim` with `TokenTree::Delimited(..)`.
-pub fn unflatten(tts: Vec<TokenTree>) -> Vec<TokenTree> {
- let mut results = Vec::new();
- let mut result = Vec::new();
- let mut open_span = DUMMY_SP;
- for tree in tts {
- match tree {
- TokenTree::Token(span, token::OpenDelim(..)) => {
- open_span = span;
- results.push(::std::mem::replace(&mut result, Vec::new()));
- }
- TokenTree::Token(span, token::CloseDelim(delim)) => {
- let delim_span = DelimSpan::from_pair(open_span, span);
- let tree = TokenTree::Delimited(
- delim_span,
- delim,
- result.into_iter().map(TokenStream::from).collect::<TokenStream>().into(),
- );
- result = results.pop().unwrap();
- result.push(tree);
- }
- tree => result.push(tree),
- }
- }
- result
-}
-
-// These panicking parsing functions are used by the quote_*!() syntax extensions,
-// but shouldn't be used otherwise.
-pub fn parse_expr_panic(parser: &mut Parser) -> P<Expr> {
- panictry!(parser.parse_expr())
-}
-
-pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> {
- panictry!(parser.parse_item())
-}
-
-pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> {
- panictry!(parser.parse_pat(None))
-}
-
-pub fn parse_arm_panic(parser: &mut Parser) -> Arm {
- panictry!(parser.parse_arm())
-}
-
-pub fn parse_ty_panic(parser: &mut Parser) -> P<Ty> {
- panictry!(parser.parse_ty())
-}
-
-pub fn parse_stmt_panic(parser: &mut Parser) -> Option<Stmt> {
- panictry!(parser.parse_stmt())
-}
-
-pub fn parse_attribute_panic(parser: &mut Parser, permit_inner: bool) -> ast::Attribute {
- panictry!(parser.parse_attribute(permit_inner))
-}
-
-pub fn parse_arg_panic(parser: &mut Parser) -> Arg {
- panictry!(parser.parse_arg())
-}
-
-pub fn parse_block_panic(parser: &mut Parser) -> P<Block> {
- panictry!(parser.parse_block())
-}
-
-pub fn parse_meta_item_panic(parser: &mut Parser) -> ast::MetaItem {
- panictry!(parser.parse_meta_item())
-}
-
-pub fn parse_path_panic(parser: &mut Parser, mode: PathStyle) -> ast::Path {
- panictry!(parser.parse_path(mode))
-}
-
-pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'cx> {
- let (cx_expr, expr) = expand_tts(cx, sp, tts);
- let expanded = expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]]);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'cx> {
- let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_item<'cx>(cx: &'cx mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'cx> {
- let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'cx> {
- let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_arm(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_ty(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_stmt(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_attr(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let expanded = expand_parse_call(cx, sp, "parse_attribute_panic",
- vec![cx.expr_bool(sp, true)], tts);
-
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_arg(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_block(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_meta_item(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec![], tts);
- base::MacEager::expr(expanded)
-}
-
-pub fn expand_quote_path(cx: &mut ExtCtxt,
- sp: Span,
- tts: &[TokenTree])
- -> Box<dyn base::MacResult+'static> {
- let mode = mk_parser_path(cx, sp, &["PathStyle", "Type"]);
- let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec![mode], tts);
- base::MacEager::expr(expanded)
-}
-
-fn ids_ext(strs: Vec<String>) -> Vec<ast::Ident> {
- strs.iter().map(|s| ast::Ident::from_str(s)).collect()
-}
-
-fn id_ext(s: &str) -> ast::Ident {
- ast::Ident::from_str(s)
-}
-
-// Lift an ident to the expr that evaluates to that ident.
-fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
- let e_str = cx.expr_str(sp, ident.name);
- cx.expr_method_call(sp,
- cx.expr_ident(sp, id_ext("ext_cx")),
- id_ext("ident_of"),
- vec![e_str])
-}
-
-// Lift a name to the expr that evaluates to that name
-fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> {
- let e_str = cx.expr_str(sp, ident.name);
- cx.expr_method_call(sp,
- cx.expr_ident(sp, id_ext("ext_cx")),
- id_ext("name_of"),
- vec![e_str])
-}
-
-fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
- let idents = vec![id_ext("syntax"), id_ext("tokenstream"), id_ext("TokenTree"), id_ext(name)];
- cx.expr_path(cx.path_global(sp, idents))
-}
-
-fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> {
- let idents = vec![id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name)];
- cx.expr_path(cx.path_global(sp, idents))
-}
-
-fn mk_parser_path(cx: &ExtCtxt, sp: Span, names: &[&str]) -> P<ast::Expr> {
- let mut idents = vec![id_ext("syntax"), id_ext("parse"), id_ext("parser")];
- idents.extend(names.iter().cloned().map(id_ext));
- cx.expr_path(cx.path_global(sp, idents))
-}
-
-fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> {
- let name = match bop {
- token::Plus => "Plus",
- token::Minus => "Minus",
- token::Star => "Star",
- token::Slash => "Slash",
- token::Percent => "Percent",
- token::Caret => "Caret",
- token::And => "And",
- token::Or => "Or",
- token::Shl => "Shl",
- token::Shr => "Shr"
- };
- mk_token_path(cx, sp, name)
-}
-
-fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> {
- let name = match delim {
- token::Paren => "Paren",
- token::Bracket => "Bracket",
- token::Brace => "Brace",
- token::NoDelim => "NoDelim",
- };
- mk_token_path(cx, sp, name)
-}
-
-#[allow(non_upper_case_globals)]
-fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> {
- macro_rules! mk_lit {
- ($name: expr, $suffix: expr, $content: expr $(, $count: expr)*) => {{
- let name = mk_name(cx, sp, ast::Ident::with_empty_ctxt($content));
- let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![
- name $(, cx.expr_u16(sp, $count))*
- ]);
- let suffix = match $suffix {
- Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
- None => cx.expr_none(sp)
- };
- cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix])
- }}
- }
-
- let name = match *tok {
- token::BinOp(binop) => {
- return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec![mk_binop(cx, sp, binop)]);
- }
- token::BinOpEq(binop) => {
- return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"),
- vec![mk_binop(cx, sp, binop)]);
- }
-
- token::OpenDelim(delim) => {
- return cx.expr_call(sp, mk_token_path(cx, sp, "OpenDelim"),
- vec![mk_delim(cx, sp, delim)]);
- }
- token::CloseDelim(delim) => {
- return cx.expr_call(sp, mk_token_path(cx, sp, "CloseDelim"),
- vec![mk_delim(cx, sp, delim)]);
- }
-
- token::Literal(token::Byte(i), suf) => return mk_lit!("Byte", suf, i),
- token::Literal(token::Char(i), suf) => return mk_lit!("Char", suf, i),
- token::Literal(token::Integer(i), suf) => return mk_lit!("Integer", suf, i),
- token::Literal(token::Float(i), suf) => return mk_lit!("Float", suf, i),
- token::Literal(token::Str_(i), suf) => return mk_lit!("Str_", suf, i),
- token::Literal(token::StrRaw(i, n), suf) => return mk_lit!("StrRaw", suf, i, n),
- token::Literal(token::ByteStr(i), suf) => return mk_lit!("ByteStr", suf, i),
- token::Literal(token::ByteStrRaw(i, n), suf) => return mk_lit!("ByteStrRaw", suf, i, n),
-
- token::Ident(ident, is_raw) => {
- return cx.expr_call(sp,
- mk_token_path(cx, sp, "Ident"),
- vec![mk_ident(cx, sp, ident), cx.expr_bool(sp, is_raw)]);
- }
-
- token::Lifetime(ident) => {
- return cx.expr_call(sp,
- mk_token_path(cx, sp, "Lifetime"),
- vec![mk_ident(cx, sp, ident)]);
- }
-
- token::DocComment(ident) => {
- return cx.expr_call(sp,
- mk_token_path(cx, sp, "DocComment"),
- vec![mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))]);
- }
-
- token::Interpolated(_) => {
- cx.span_err(sp, "quote! with interpolated token");
- // Use dummy name.
- "Interpolated"
- }
-
- token::Eq => "Eq",
- token::Lt => "Lt",
- token::Le => "Le",
- token::EqEq => "EqEq",
- token::Ne => "Ne",
- token::Ge => "Ge",
- token::Gt => "Gt",
- token::AndAnd => "AndAnd",
- token::OrOr => "OrOr",
- token::Not => "Not",
- token::Tilde => "Tilde",
- token::At => "At",
- token::Dot => "Dot",
- token::DotDot => "DotDot",
- token::DotDotDot => "DotDotDot",
- token::DotDotEq => "DotDotEq",
- token::Comma => "Comma",
- token::Semi => "Semi",
- token::Colon => "Colon",
- token::ModSep => "ModSep",
- token::RArrow => "RArrow",
- token::LArrow => "LArrow",
- token::FatArrow => "FatArrow",
- token::Pound => "Pound",
- token::Dollar => "Dollar",
- token::Question => "Question",
- token::SingleQuote => "SingleQuote",
- token::Eof => "Eof",
-
- token::Whitespace | token::Comment | token::Shebang(_) => {
- panic!("unhandled token in quote!");
- }
- };
- mk_token_path(cx, sp, name)
-}
-
-fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, quoted: bool) -> Vec<ast::Stmt> {
- match *tt {
- TokenTree::Token(sp, token::Ident(ident, _)) if quoted => {
- // tt.extend($ident.to_tokens(ext_cx))
-
- let e_to_toks =
- cx.expr_method_call(sp,
- cx.expr_ident(sp, ident),
- id_ext("to_tokens"),
- vec![cx.expr_ident(sp, id_ext("ext_cx"))]);
- let e_to_toks =
- cx.expr_method_call(sp, e_to_toks, id_ext("into_iter"), vec![]);
-
- let e_push =
- cx.expr_method_call(sp,
- cx.expr_ident(sp, id_ext("tt")),
- id_ext("extend"),
- vec![e_to_toks]);
-
- vec![cx.stmt_expr(e_push)]
- }
- TokenTree::Token(sp, ref tok) => {
- let e_sp = cx.expr_ident(sp, id_ext("_sp"));
- let e_tok = cx.expr_call(sp,
- mk_tt_path(cx, sp, "Token"),
- vec![e_sp, expr_mk_token(cx, sp, tok)]);
- let e_push =
- cx.expr_method_call(sp,
- cx.expr_ident(sp, id_ext("tt")),
- id_ext("push"),
- vec![e_tok]);
- vec![cx.stmt_expr(e_push)]
- },
- TokenTree::Delimited(span, delim, ref tts) => {
- let mut stmts = statements_mk_tt(cx, &TokenTree::open_tt(span.open, delim), false);
- stmts.extend(statements_mk_tts(cx, tts.stream()));
- stmts.extend(statements_mk_tt(cx, &TokenTree::close_tt(span.close, delim), false));
- stmts
- }
- }
-}
-
-fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree])
- -> (P<ast::Expr>, Vec<TokenTree>) {
- let mut p = cx.new_parser_from_tts(tts);
-
- let cx_expr = panictry!(p.parse_expr());
- if !p.eat(&token::Comma) {
- let _ = p.diagnostic().fatal("expected token `,`");
- }
-
- let tts = panictry!(p.parse_all_token_trees());
- p.abort_if_errors();
-
- (cx_expr, tts)
-}
-
-fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<ast::Stmt> {
- // We also bind a single value, sp, to ext_cx.call_site()
- //
- // This causes every span in a token-tree quote to be attributed to the
- // call site of the extension using the quote. We can't really do much
- // better since the source of the quote may well be in a library that
- // was not even parsed by this compilation run, that the user has no
- // source code for (eg. in libsyntax, which they're just _using_).
- //
- // The old quasiquoter had an elaborate mechanism for denoting input
- // file locations from which quotes originated; unfortunately this
- // relied on feeding the source string of the quote back into the
- // compiler (which we don't really want to do) and, in any case, only
- // pushed the problem a very small step further back: an error
- // resulting from a parse of the resulting quote is still attributed to
- // the site the string literal occurred, which was in a source file
- // _other_ than the one the user has control over. For example, an
- // error in a quote from the protocol compiler, invoked in user code
- // using macro_rules! for example, will be attributed to the macro_rules.rs
- // file in libsyntax, which the user might not even have source to (unless
- // they happen to have a compiler on hand). Over all, the phase distinction
- // just makes quotes "hard to attribute". Possibly this could be fixed
- // by recreating some of the original qq machinery in the tt regime
- // (pushing fake SourceFiles onto the parser to account for original sites
- // of quotes, for example) but at this point it seems not likely to be
- // worth the hassle.
-
- let e_sp = cx.expr_method_call(sp,
- cx.expr_ident(sp, id_ext("ext_cx")),
- id_ext("call_site"),
- Vec::new());
-
- let stmt_let_sp = cx.stmt_let(sp, false,
- id_ext("_sp"),
- e_sp);
-
- let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp));
-
- vec![stmt_let_sp, stmt_let_tt]
-}
-
-fn statements_mk_tts(cx: &ExtCtxt, tts: TokenStream) -> Vec<ast::Stmt> {
- let mut ss = Vec::new();
- let mut quoted = false;
- for tt in tts.into_trees() {
- quoted = match tt {
- TokenTree::Token(_, token::Dollar) if !quoted => true,
- _ => {
- ss.extend(statements_mk_tt(cx, &tt, quoted));
- false
- }
- }
- }
- ss
-}
-
-fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) -> (P<ast::Expr>, P<ast::Expr>) {
- let (cx_expr, tts) = parse_arguments_to_quote(cx, tts);
-
- let mut vector = mk_stmts_let(cx, sp);
- vector.extend(statements_mk_tts(cx, tts.iter().cloned().collect()));
- vector.push(cx.stmt_expr(cx.expr_ident(sp, id_ext("tt"))));
- let block = cx.expr_block(cx.block(sp, vector));
- let unflatten = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext("unflatten")];
-
- (cx_expr, cx.expr_call_global(sp, unflatten, vec![block]))
-}
-
-fn expand_wrapper(cx: &ExtCtxt,
- sp: Span,
- cx_expr: P<ast::Expr>,
- expr: P<ast::Expr>,
- imports: &[&[&str]]) -> P<ast::Expr> {
- // Explicitly borrow to avoid moving from the invoker (#16992)
- let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr));
- let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow);
-
- let mut stmts = imports.iter().map(|path| {
- // make item: `use ...;`
- let path = path.iter().map(|s| s.to_string()).collect();
- let use_item = cx.item_use_glob(
- sp,
- respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited),
- ids_ext(path),
- );
- cx.stmt_item(sp, use_item)
- }).chain(Some(stmt_let_ext_cx)).collect::<Vec<_>>();
- stmts.push(cx.stmt_expr(expr));
-
- cx.expr_block(cx.block(sp, stmts))
-}
-
-fn expand_parse_call(cx: &ExtCtxt,
- sp: Span,
- parse_method: &str,
- arg_exprs: Vec<P<ast::Expr>> ,
- tts: &[TokenTree]) -> P<ast::Expr> {
- let (cx_expr, tts_expr) = expand_tts(cx, sp, tts);
-
- let parse_sess_call = || cx.expr_method_call(
- sp, cx.expr_ident(sp, id_ext("ext_cx")),
- id_ext("parse_sess"), Vec::new());
-
- let new_parser_call =
- cx.expr_call(sp,
- cx.expr_ident(sp, id_ext("new_parser_from_tts")),
- vec![parse_sess_call(), tts_expr]);
-
- let path = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method)];
- let mut args = vec![cx.expr_mut_addr_of(sp, new_parser_call)];
- args.extend(arg_exprs);
- let expr = cx.expr_call_global(sp, path, args);
-
- if parse_method == "parse_attribute" {
- expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"],
- &["syntax", "parse", "attr"]])
- } else {
- expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]])
- }
-}
(active, link_llvm_intrinsics, "1.0.0", Some(29602), None),
(active, linkage, "1.0.0", Some(29603), None),
- (active, quote, "1.0.0", Some(29601), None),
// rustc internal
(active, rustc_diagnostic_macros, "1.0.0", None, None),
// Paths of the form: `extern::foo::bar`
(removed, extern_in_paths, "1.33.0", Some(55600), None,
Some("subsumed by `::foo::bar` paths")),
+ (removed, quote, "1.0.0", Some(29601), None, None),
);
declare_features! (
noop_fold_angle_bracketed_parameter_data(p, self)
}
- fn fold_parenthesized_parameter_data(&mut self, p: ParenthesisedArgs)
- -> ParenthesisedArgs
+ fn fold_parenthesized_parameter_data(&mut self, p: ParenthesizedArgs)
+ -> ParenthesizedArgs
{
noop_fold_parenthesized_parameter_data(p, self)
}
}
}
-pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesisedArgs,
+pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedArgs,
fld: &mut T)
- -> ParenthesisedArgs
+ -> ParenthesizedArgs
{
- let ParenthesisedArgs { inputs, output, span } = data;
- ParenthesisedArgs {
+ let ParenthesizedArgs { inputs, output, span } = data;
+ ParenthesizedArgs {
inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
output: output.map(|ty| fld.fold_ty(ty)),
span: fld.new_span(span)
TokenTree::Delimited(span, delim, tts) => TokenTree::Delimited(
DelimSpan::from_pair(fld.new_span(span.open), fld.new_span(span.close)),
delim,
- fld.fold_tts(tts.stream()).into(),
+ fld.fold_tts(tts).into(),
),
}
}
pub mod derive;
pub mod expand;
pub mod placeholders;
- pub mod quote;
pub mod source_util;
pub mod tt {
sr
}
- pub fn new_without_err(sess: &'a ParseSess,
- source_file: Lrc<syntax_pos::SourceFile>,
- override_span: Option<Span>,
- prepend_error_text: &str) -> Result<Self, ()> {
- let mut sr = StringReader::new_raw(sess, source_file, override_span);
- if sr.advance_token().is_err() {
- eprintln!("{}", prepend_error_text);
- sr.emit_fatal_errors();
- return Err(());
- }
- Ok(sr)
- }
-
pub fn new_or_buffered_errs(sess: &'a ParseSess,
source_file: Lrc<syntax_pos::SourceFile>,
override_span: Option<Span>) -> Result<Self, Vec<Diagnostic>> {
// lifetimes shouldn't end with a single quote
// if we find one, then this is an invalid character literal
if self.ch_is('\'') {
- self.fatal_span_verbose(start_with_quote, self.next_pos,
- String::from("character literal may only contain one codepoint"))
- .raise();
+ self.err_span_(start_with_quote, self.next_pos,
+ "character literal may only contain one codepoint");
+ self.bump();
+ return Ok(token::Literal(token::Err(Symbol::intern("??")), None))
}
format!("\"{}\"", &self.src[start..end]),
Applicability::MachineApplicable
).emit();
- return Ok(token::Literal(token::Str_(Symbol::intern("??")), None))
+ return Ok(token::Literal(token::Err(Symbol::intern("??")), None))
}
if self.ch_is('\n') || self.is_eof() || self.ch_is('/') {
// Only attempt to infer single line string literals. If we encounter
use errors::{FatalError, Level, Handler, ColorConfig, Diagnostic, DiagnosticBuilder};
use feature_gate::UnstableFeatures;
use parse::parser::Parser;
-use ptr::P;
use symbol::Symbol;
use tokenstream::{TokenStream, TokenTree};
use diagnostics::plugin::ErrorMap;
new_parser_from_source_str(sess, name, source).parse_inner_attributes()
}
-crate fn parse_expr_from_source_str(name: FileName, source: String, sess: &ParseSess)
- -> PResult<P<ast::Expr>> {
- new_parser_from_source_str(sess, name, source).parse_expr()
-}
-
-/// Parses an item.
-///
-/// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err`
-/// when a syntax error occurred.
-crate fn parse_item_from_source_str(name: FileName, source: String, sess: &ParseSess)
- -> PResult<Option<P<ast::Item>>> {
- new_parser_from_source_str(sess, name, source).parse_item()
-}
-
-crate fn parse_stmt_from_source_str(name: FileName, source: String, sess: &ParseSess)
- -> PResult<Option<ast::Stmt>> {
- new_parser_from_source_str(sess, name, source).parse_stmt()
-}
-
pub fn parse_stream_from_source_str(name: FileName, source: String, sess: &ParseSess,
override_span: Option<Span>)
-> TokenStream {
match lit {
token::Byte(i) => (true, Some(LitKind::Byte(byte_lit(&i.as_str()).0))),
token::Char(i) => (true, Some(LitKind::Char(char_lit(&i.as_str(), diag).0))),
+ token::Err(i) => (true, Some(LitKind::Err(i))),
// There are some valid suffixes for integer and float literals,
// so all the handling is done internally.
use syntax_pos::{Span, BytePos, Pos, NO_EXPANSION};
use ast::{self, Ident, PatKind};
use attr::first_attr_value_str_by_name;
- use parse;
+ use ptr::P;
use print::pprust::item_to_string;
use tokenstream::{DelimSpan, TokenTree};
use util::parser_testing::string_to_stream;
use util::parser_testing::{string_to_expr, string_to_item};
use with_globals;
+ /// Parses an item.
+ ///
+ /// Returns `Ok(Some(item))` when successful, `Ok(None)` when no item was found, and `Err`
+ /// when a syntax error occurred.
+ fn parse_item_from_source_str(name: FileName, source: String, sess: &ParseSess)
+ -> PResult<Option<P<ast::Item>>> {
+ new_parser_from_source_str(sess, name, source).parse_item()
+ }
+
// produce a syntax_pos::span
fn sp(a: u32, b: u32) -> Span {
Span::new(BytePos(a), BytePos(b), NO_EXPANSION)
)
if name_macro_rules.name == "macro_rules"
&& name_zip.name == "zip" => {
- let tts = ¯o_tts.stream().trees().collect::<Vec<_>>();
+ let tts = ¯o_tts.trees().collect::<Vec<_>>();
match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) {
(
3,
Some(&TokenTree::Delimited(_, second_delim, ref second_tts)),
)
if macro_delim == token::Paren => {
- let tts = &first_tts.stream().trees().collect::<Vec<_>>();
+ let tts = &first_tts.trees().collect::<Vec<_>>();
match (tts.len(), tts.get(0), tts.get(1)) {
(
2,
if first_delim == token::Paren && ident.name == "a" => {},
_ => panic!("value 3: {:?} {:?}", first_delim, first_tts),
}
- let tts = &second_tts.stream().trees().collect::<Vec<_>>();
+ let tts = &second_tts.trees().collect::<Vec<_>>();
match (tts.len(), tts.get(0), tts.get(1)) {
(
2,
#[test]
fn ttdelim_span() {
+ fn parse_expr_from_source_str(
+ name: FileName, source: String, sess: &ParseSess
+ ) -> PResult<P<ast::Expr>> {
+ new_parser_from_source_str(sess, name, source).parse_expr()
+ }
+
with_globals(|| {
let sess = ParseSess::new(FilePathMapping::empty());
- let expr = parse::parse_expr_from_source_str(PathBuf::from("foo").into(),
+ let expr = parse_expr_from_source_str(PathBuf::from("foo").into(),
"foo!( fn main() { body } )".to_string(), &sess).unwrap();
let tts: Vec<_> = match expr.node {
use rustc_target::spec::abi::{self, Abi};
-use ast::{AngleBracketedArgs, ParenthesisedArgs, AttrStyle, BareFnTy};
+use ast::{AngleBracketedArgs, ParenthesizedArgs, AttrStyle, BareFnTy};
use ast::{GenericBound, TraitBoundModifier};
use ast::Unsafety;
use ast::{Mod, AnonConst, Arg, Arm, Guard, Attribute, BindingMode, TraitItemKind};
use ptr::P;
use parse::PResult;
use ThinVec;
-use tokenstream::{self, DelimSpan, ThinTokenStream, TokenTree, TokenStream};
+use tokenstream::{self, DelimSpan, TokenTree, TokenStream, TreeAndJoint};
use symbol::{Symbol, keywords};
use std::borrow::Cow;
enum SemiColonMode {
Break,
Ignore,
+ Comma,
}
#[derive(Clone, Copy, PartialEq, Debug)]
/// on the parser.
#[derive(Clone)]
enum LastToken {
- Collecting(Vec<TokenStream>),
- Was(Option<TokenStream>),
+ Collecting(Vec<TreeAndJoint>),
+ Was(Option<TreeAndJoint>),
}
impl TokenCursorFrame {
- fn new(sp: DelimSpan, delim: DelimToken, tts: &ThinTokenStream) -> Self {
+ fn new(sp: DelimSpan, delim: DelimToken, tts: &TokenStream) -> Self {
TokenCursorFrame {
delim: delim,
span: sp,
open_delim: delim == token::NoDelim,
- tree_cursor: tts.stream().into_trees(),
+ tree_cursor: tts.clone().into_trees(),
close_delim: delim == token::NoDelim,
last_token: LastToken::Was(None),
}
crate fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: &str) -> ! {
self.sess.span_diagnostic.span_bug(sp, m)
}
- crate fn abort_if_errors(&self) {
- self.sess.span_diagnostic.abort_if_errors();
- }
fn cancel(&self, err: &mut DiagnosticBuilder) {
self.sess.span_diagnostic.cancel(err)
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().get();
+ if ["f32", "f64"].contains(&s) {
+ Some(s)
+ } 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_with_applicability(
+ 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); }
};
enable_warning: bool)
-> PResult<'a, ()> {
loop {
- segments.push(self.parse_path_segment(style, enable_warning)?);
+ let segment = self.parse_path_segment(style, enable_warning)?;
+ if style == PathStyle::Expr {
+ // In order to check for trailing angle brackets, we must have finished
+ // recursing (`parse_path_segment` can indirectly call this function),
+ // that is, the next token must be the highlighted part of the below example:
+ //
+ // `Foo::<Bar as Baz<T>>::Qux`
+ // ^ here
+ //
+ // As opposed to the below highlight (if we had only finished the first
+ // recursion):
+ //
+ // `Foo::<Bar as Baz<T>>::Qux`
+ // ^ here
+ //
+ // `PathStyle::Expr` is only provided at the root invocation and never in
+ // `parse_path_segment` to recurse and therefore can be checked to maintain
+ // this invariant.
+ self.check_trailing_angle_brackets(&segment, token::ModSep);
+ }
+ segments.push(segment);
if self.is_import_coupler() || !self.eat(&token::ModSep) {
return Ok(());
style != PathStyle::Mod && self.check(&token::ModSep)
&& self.look_ahead(1, |t| is_args_start(t)) {
// Generic arguments are found - `<`, `(`, `::<` or `::(`.
- let lo = self.span;
if self.eat(&token::ModSep) && style == PathStyle::Type && enable_warning {
self.diagnostic().struct_span_warn(self.prev_span, "unnecessary path disambiguator")
.span_label(self.prev_span, "try removing `::`").emit();
}
+ let lo = self.span;
let args = if self.eat_lt() {
// `<'a, T, A = U>`
} else {
None
};
- ParenthesisedArgs { inputs, output, span }.into()
+ ParenthesizedArgs { inputs, output, span }.into()
};
PathSegment { ident, args, id: ast::DUMMY_NODE_ID }
let lo = self.span;
// Check if a colon exists one ahead. This means we're parsing a fieldname.
- let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| t == &token::Colon) {
+ let (fieldname, expr, is_shorthand) = if self.look_ahead(1, |t| {
+ t == &token::Colon || t == &token::Eq
+ }) {
let fieldname = self.parse_field_name()?;
+
+ // Check for an equals token. This means the source incorrectly attempts to
+ // initialize a field with an eq rather than a colon.
+ if self.token == token::Eq {
+ self.diagnostic()
+ .struct_span_err(self.span, "expected `:`, found `=`")
+ .span_suggestion_with_applicability(
+ fieldname.span.shrink_to_hi().to(self.span),
+ "replace equals symbol with a colon",
+ ":".to_string(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
self.bump(); // `:`
(fieldname, self.parse_expr()?, false)
} else {
})
}
- fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, ThinTokenStream)> {
+ fn expect_delimited_token_tree(&mut self) -> PResult<'a, (MacDelimiter, TokenStream)> {
let delim = match self.token {
token::OpenDelim(delim) => delim,
_ => {
token::Brace => MacDelimiter::Brace,
token::NoDelim => self.bug("unexpected no delimiter"),
};
- Ok((delim, tts.stream().into()))
+ Ok((delim, tts.into()))
}
/// At the bottom (top?) of the precedence hierarchy,
break;
}
+ let mut recovery_field = None;
+ if let token::Ident(ident, _) = self.token {
+ if !self.token.is_reserved_ident() && self.look_ahead(1, |t| *t == token::Colon) {
+ // Use in case of error after field-looking code: `S { foo: () with a }`
+ let mut ident = ident.clone();
+ ident.span = self.span;
+ recovery_field = Some(ast::Field {
+ ident,
+ span: self.span,
+ expr: self.mk_expr(self.span, ExprKind::Err, ThinVec::new()),
+ is_shorthand: false,
+ attrs: ThinVec::new(),
+ });
+ }
+ }
+ let mut parsed_field = None;
match self.parse_field() {
- Ok(f) => fields.push(f),
+ Ok(f) => parsed_field = Some(f),
Err(mut e) => {
e.span_label(struct_sp, "while parsing this struct");
e.emit();
// what comes next as additional fields, rather than
// bailing out until next `}`.
if self.token != token::Comma {
- self.recover_stmt();
- break;
+ self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
+ if self.token != token::Comma {
+ break;
+ }
}
}
}
match self.expect_one_of(&[token::Comma],
&[token::CloseDelim(token::Brace)]) {
- Ok(()) => {}
+ Ok(()) => if let Some(f) = parsed_field.or(recovery_field) {
+ // only include the field if there's no parse error for the field name
+ fields.push(f);
+ }
Err(mut e) => {
+ if let Some(f) = recovery_field {
+ fields.push(f);
+ }
+ e.span_label(struct_sp, "while parsing this struct");
e.emit();
- self.recover_stmt();
- break;
+ self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
+ self.eat(&token::Comma);
}
}
}
// Assuming we have just parsed `.`, continue parsing into an expression.
fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
let segment = self.parse_path_segment(PathStyle::Expr, true)?;
+ self.check_trailing_angle_brackets(&segment, token::OpenDelim(token::Paren));
+
Ok(match self.token {
token::OpenDelim(token::Paren) => {
// Method call `expr.f()`
})
}
+ /// This function checks if there are trailing angle brackets and produces
+ /// a diagnostic to suggest removing them.
+ ///
+ /// ```ignore (diagnostic)
+ /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+ /// ^^ help: remove extra angle brackets
+ /// ```
+ fn check_trailing_angle_brackets(&mut self, segment: &PathSegment, end: token::Token) {
+ // This function is intended to be invoked after parsing a path segment where there are two
+ // cases:
+ //
+ // 1. A specific token is expected after the path segment.
+ // eg. `x.foo(`, `x.foo::<u32>(` (parenthesis - method call),
+ // `Foo::`, or `Foo::<Bar>::` (mod sep - continued path).
+ // 2. No specific token is expected after the path segment.
+ // eg. `x.foo` (field access)
+ //
+ // This function is called after parsing `.foo` and before parsing the token `end` (if
+ // present). This includes any angle bracket arguments, such as `.foo::<u32>` or
+ // `Foo::<Bar>`.
+
+ // We only care about trailing angle brackets if we previously parsed angle bracket
+ // arguments. This helps stop us incorrectly suggesting that extra angle brackets be
+ // removed in this case:
+ //
+ // `x.foo >> (3)` (where `x.foo` is a `u32` for example)
+ //
+ // This case is particularly tricky as we won't notice it just looking at the tokens -
+ // it will appear the same (in terms of upcoming tokens) as below (since the `::<u32>` will
+ // have already been parsed):
+ //
+ // `x.foo::<u32>>>(3)`
+ let parsed_angle_bracket_args = segment.args
+ .as_ref()
+ .map(|args| args.is_angle_bracketed())
+ .unwrap_or(false);
+
+ debug!(
+ "check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
+ parsed_angle_bracket_args,
+ );
+ if !parsed_angle_bracket_args {
+ return;
+ }
+
+ // Keep the span at the start so we can highlight the sequence of `>` characters to be
+ // removed.
+ let lo = self.span;
+
+ // We need to look-ahead to see if we have `>` characters without moving the cursor forward
+ // (since we might have the field access case and the characters we're eating are
+ // actual operators and not trailing characters - ie `x.foo >> 3`).
+ let mut position = 0;
+
+ // We can encounter `>` or `>>` tokens in any order, so we need to keep track of how
+ // many of each (so we can correctly pluralize our error messages) and continue to
+ // advance.
+ let mut number_of_shr = 0;
+ let mut number_of_gt = 0;
+ while self.look_ahead(position, |t| {
+ trace!("check_trailing_angle_brackets: t={:?}", t);
+ if *t == token::BinOp(token::BinOpToken::Shr) {
+ number_of_shr += 1;
+ true
+ } else if *t == token::Gt {
+ number_of_gt += 1;
+ true
+ } else {
+ false
+ }
+ }) {
+ position += 1;
+ }
+
+ // If we didn't find any trailing `>` characters, then we have nothing to error about.
+ debug!(
+ "check_trailing_angle_brackets: number_of_gt={:?} number_of_shr={:?}",
+ number_of_gt, number_of_shr,
+ );
+ if number_of_gt < 1 && number_of_shr < 1 {
+ return;
+ }
+
+ // Finally, double check that we have our end token as otherwise this is the
+ // second case.
+ if self.look_ahead(position, |t| {
+ trace!("check_trailing_angle_brackets: t={:?}", t);
+ *t == end
+ }) {
+ // Eat from where we started until the end token so that parsing can continue
+ // as if we didn't have those extra angle brackets.
+ self.eat_to_tokens(&[&end]);
+ let span = lo.until(self.span);
+
+ let plural = number_of_gt > 1 || number_of_shr >= 1;
+ self.diagnostic()
+ .struct_span_err(
+ span,
+ &format!("unmatched angle bracket{}", if plural { "s" } else { "" }),
+ )
+ .span_suggestion_with_applicability(
+ span,
+ &format!("remove extra angle bracket{}", if plural { "s" } else { "" }),
+ String::new(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ }
+ }
+
fn parse_dot_or_call_expr_with_(&mut self, e0: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
let mut e = e0;
let mut hi;
if let Some(mut err) = delayed_err {
if let Some(etc_span) = etc_span {
- err.multipart_suggestion(
+ err.multipart_suggestion_with_applicability(
"move the `..` to the end of the field list",
vec![
(etc_span, String::new()),
(self.span, format!("{}.. }}", if ate_comma { "" } else { ", " })),
],
+ Applicability::MachineApplicable,
);
}
err.emit();
}
/// Emit an expected item after attributes error.
- fn expected_item_err(&self, attrs: &[Attribute]) {
+ fn expected_item_err(&mut self, attrs: &[Attribute]) -> PResult<'a, ()> {
let message = match attrs.last() {
Some(&Attribute { is_sugared_doc: true, .. }) => "expected item after doc comment",
_ => "expected item after attributes",
};
- self.span_err(self.prev_span, message);
+ let mut err = self.diagnostic().struct_span_err(self.prev_span, message);
+ if attrs.last().unwrap().is_sugared_doc {
+ err.span_label(self.prev_span, "this doc comment doesn't document anything");
+ }
+ Err(err)
}
/// Parse a statement. This stops just before trailing semicolons on everything but items.
token::CloseDelim(token::DelimToken::Brace) => {
if brace_depth == 0 {
debug!("recover_stmt_ return - close delim {:?}", self.token);
- return;
+ break;
}
brace_depth -= 1;
self.bump();
if in_block && bracket_depth == 0 && brace_depth == 0 {
debug!("recover_stmt_ return - block end {:?}", self.token);
- return;
+ break;
}
}
token::CloseDelim(token::DelimToken::Bracket) => {
}
token::Eof => {
debug!("recover_stmt_ return - Eof");
- return;
+ break;
}
token::Semi => {
self.bump();
brace_depth == 0 &&
bracket_depth == 0 {
debug!("recover_stmt_ return - Semi");
- return;
+ break;
+ }
+ }
+ token::Comma => {
+ if break_on_semi == SemiColonMode::Comma &&
+ brace_depth == 0 &&
+ bracket_depth == 0 {
+ debug!("recover_stmt_ return - Semi");
+ break;
+ } else {
+ self.bump();
}
}
_ => {
let ident = self.parse_ident()?;
let tokens = if self.check(&token::OpenDelim(token::Brace)) {
match self.parse_token_tree() {
- TokenTree::Delimited(_, _, tts) => tts.stream(),
+ TokenTree::Delimited(_, _, tts) => tts,
_ => unreachable!(),
}
} else if self.check(&token::OpenDelim(token::Paren)) {
let mut err = self.struct_span_err(fixed_name_sp, error_msg);
err.span_label(fixed_name_sp, "dash-separated idents are not valid");
- err.multipart_suggestion(suggestion_msg, replacement);
+ err.multipart_suggestion_with_applicability(
+ suggestion_msg,
+ replacement,
+ Applicability::MachineApplicable,
+ );
err.emit();
}
Ok(ident)
// CONST ITEM
if self.eat_keyword(keywords::Mut) {
let prev_span = self.prev_span;
- self.diagnostic().struct_span_err(prev_span, "const globals cannot be mutable")
- .help("did you mean to declare a static?")
- .emit();
+ let mut err = self.diagnostic()
+ .struct_span_err(prev_span, "const globals cannot be mutable");
+ err.span_label(prev_span, "cannot be mutable");
+ err.span_suggestion_with_applicability(
+ const_span,
+ "you might want to declare a static instead",
+ "static".to_owned(),
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
}
let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
let prev_span = self.prev_span;
}
None => {
if !attrs.is_empty() {
- self.expected_item_err(&attrs);
+ self.expected_item_err(&attrs)?;
}
self.unexpected()
}
if !attributes_allowed && !attrs.is_empty() {
- self.expected_item_err(&attrs);
+ self.expected_item_err(&attrs)?;
}
Ok(None)
}
&mut self.token_cursor.stack[prev].last_token
};
- // Pull our the toekns that we've collected from the call to `f` above
+ // Pull out the tokens that we've collected from the call to `f` above.
let mut collected_tokens = match *last_token {
LastToken::Collecting(ref mut v) => mem::replace(v, Vec::new()),
LastToken::Was(_) => panic!("our vector went away?"),
// call. In that case we need to record all the tokens we collected in
// our parent list as well. To do that we push a clone of our stream
// onto the previous list.
- let stream = collected_tokens.into_iter().collect::<TokenStream>();
match prev_collecting {
Some(mut list) => {
- list.push(stream.clone());
+ list.extend(collected_tokens.iter().cloned());
list.extend(extra_token);
*last_token = LastToken::Collecting(list);
}
}
}
- Ok((ret?, stream))
+ Ok((ret?, TokenStream::new(collected_tokens)))
}
pub fn parse_item(&mut self) -> PResult<'a, Option<P<Item>>> {
pub enum Lit {
Byte(ast::Name),
Char(ast::Name),
+ Err(ast::Name),
Integer(ast::Name),
Float(ast::Name),
Str_(ast::Name),
match *self {
Byte(_) => "byte literal",
Char(_) => "char literal",
+ Err(_) => "invalid literal",
Integer(_) => "integer literal",
Float(_) => "float literal",
Str_(_) | StrRaw(..) => "string literal",
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot |
DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
- Question | OpenDelim(..) | CloseDelim(..) => return None,
-
+ Question | OpenDelim(..) | CloseDelim(..) |
Literal(..) | Ident(..) | Lifetime(..) | Interpolated(..) | DocComment(..) |
Whitespace | Comment | Shebang(..) | Eof => return None,
})
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),
}
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();
+ 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));
TokenTree::Delimited(_, delim, tts) => {
self.writer().word(token_to_string(&token::OpenDelim(delim)))?;
self.writer().space()?;
- self.print_tts(tts.stream())?;
+ self.print_tts(tts)?;
self.writer().space()?;
self.writer().word(token_to_string(&token::CloseDelim(delim)))
},
// Recreate self from the raw pointer.
Some(P { ptr: Box::from_raw(p) })
} else {
+ drop(Box::from_raw(p));
None
}
}
/// A single token
Token(Span, token::Token),
/// A delimited sequence of token trees
- Delimited(DelimSpan, DelimToken, ThinTokenStream),
+ Delimited(DelimSpan, DelimToken, TokenStream),
}
impl TokenTree {
(&TokenTree::Token(_, ref tk), &TokenTree::Token(_, ref tk2)) => tk == tk2,
(&TokenTree::Delimited(_, delim, ref tts),
&TokenTree::Delimited(_, delim2, ref tts2)) => {
- delim == delim2 &&
- tts.stream().eq_unspanned(&tts2.stream())
+ delim == delim2 && tts.eq_unspanned(&tts2)
}
(_, _) => false,
}
}
(&TokenTree::Delimited(_, delim, ref tts),
&TokenTree::Delimited(_, delim2, ref tts2)) => {
- delim == delim2 &&
- tts.stream().probably_equal_for_proc_macro(&tts2.stream())
+ delim == delim2 && tts.probably_equal_for_proc_macro(&tts2)
}
(_, _) => false,
}
}
pub fn joint(self) -> TokenStream {
- TokenStream::Tree(self, Joint)
+ TokenStream::new(vec![(self, Joint)])
}
/// Returns the opening delimiter as a token tree.
/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
/// instead of a representation of the abstract syntax tree.
/// Today's `TokenTree`s can still contain AST via `Token::Interpolated` for back-compat.
+///
+/// The use of `Option` is an optimization that avoids the need for an
+/// allocation when the stream is empty. However, it is not guaranteed that an
+/// empty stream is represented with `None`; it may be represented as a `Some`
+/// around an empty `Vec`.
#[derive(Clone, Debug)]
-pub enum TokenStream {
- Empty,
- Tree(TokenTree, IsJoint),
- Stream(Lrc<Vec<TreeAndJoint>>),
-}
+pub struct TokenStream(Option<Lrc<Vec<TreeAndJoint>>>);
pub type TreeAndJoint = (TokenTree, IsJoint);
// `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
-static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 32);
+static_assert!(MEM_SIZE_OF_TOKEN_STREAM: mem::size_of::<TokenStream>() == 8);
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum IsJoint {
/// separating the two arguments with a comma for diagnostic suggestions.
pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> {
// Used to suggest if a user writes `foo!(a b);`
- if let TokenStream::Stream(ref stream) = self {
+ if let Some(ref stream) = self.0 {
let mut suggestion = None;
let mut iter = stream.iter().enumerate().peekable();
while let Some((pos, ts)) = iter.next() {
impl From<TokenTree> for TokenStream {
fn from(tree: TokenTree) -> TokenStream {
- TokenStream::Tree(tree, NonJoint)
+ TokenStream::new(vec![(tree, NonJoint)])
}
}
impl TokenStream {
pub fn len(&self) -> usize {
- if let TokenStream::Stream(ref slice) = self {
+ if let Some(ref slice) = self.0 {
slice.len()
} else {
0
}
pub fn empty() -> TokenStream {
- TokenStream::Empty
+ TokenStream(None)
}
pub fn is_empty(&self) -> bool {
- match self {
- TokenStream::Empty => true,
- _ => false,
+ match self.0 {
+ None => true,
+ Some(ref stream) => stream.is_empty(),
}
}
_ => {
let mut vec = vec![];
for stream in streams {
- match stream {
- TokenStream::Empty => {},
- TokenStream::Tree(tree, is_joint) => vec.push((tree, is_joint)),
- TokenStream::Stream(stream2) => vec.extend(stream2.iter().cloned()),
+ match stream.0 {
+ None => {},
+ Some(stream2) => vec.extend(stream2.iter().cloned()),
}
}
TokenStream::new(vec)
}
}
- pub fn new(mut streams: Vec<TreeAndJoint>) -> TokenStream {
+ pub fn new(streams: Vec<TreeAndJoint>) -> TokenStream {
match streams.len() {
- 0 => TokenStream::empty(),
- 1 => {
- let (tree, is_joint) = streams.pop().unwrap();
- TokenStream::Tree(tree, is_joint)
- }
- _ => TokenStream::Stream(Lrc::new(streams)),
+ 0 => TokenStream(None),
+ _ => TokenStream(Some(Lrc::new(streams))),
}
}
pub fn append_to_tree_and_joint_vec(self, vec: &mut Vec<TreeAndJoint>) {
- match self {
- TokenStream::Empty => {}
- TokenStream::Tree(tree, is_joint) => vec.push((tree, is_joint)),
- TokenStream::Stream(stream) => vec.extend(stream.iter().cloned()),
+ if let Some(stream) = self.0 {
+ vec.extend(stream.iter().cloned());
}
}
}
pub fn map_enumerated<F: FnMut(usize, TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
- match self {
- TokenStream::Empty => TokenStream::Empty,
- TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(0, tree), is_joint),
- TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new(
+ TokenStream(self.0.map(|stream| {
+ Lrc::new(
stream
.iter()
.enumerate()
.map(|(i, (tree, is_joint))| (f(i, tree.clone()), *is_joint))
- .collect()
- )),
- }
+ .collect())
+ }))
}
pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream {
- match self {
- TokenStream::Empty => TokenStream::Empty,
- TokenStream::Tree(tree, is_joint) => TokenStream::Tree(f(tree), is_joint),
- TokenStream::Stream(stream) => TokenStream::Stream(Lrc::new(
+ TokenStream(self.0.map(|stream| {
+ Lrc::new(
stream
.iter()
.map(|(tree, is_joint)| (f(tree.clone()), *is_joint))
- .collect()
- )),
- }
+ .collect())
+ }))
}
- fn first_tree_and_joint(&self) -> Option<(TokenTree, IsJoint)> {
- match self {
- TokenStream::Empty => None,
- TokenStream::Tree(ref tree, is_joint) => Some((tree.clone(), *is_joint)),
- TokenStream::Stream(ref stream) => Some(stream.first().unwrap().clone())
- }
+ fn first_tree_and_joint(&self) -> Option<TreeAndJoint> {
+ self.0.as_ref().map(|stream| {
+ stream.first().unwrap().clone()
+ })
}
fn last_tree_if_joint(&self) -> Option<TokenTree> {
- match self {
- TokenStream::Empty => None,
- TokenStream::Tree(ref tree, is_joint) => {
- if *is_joint == Joint {
- Some(tree.clone())
- } else {
- None
- }
- }
- TokenStream::Stream(ref stream) => {
+ match self.0 {
+ None => None,
+ Some(ref stream) => {
if let (tree, Joint) = stream.last().unwrap() {
Some(tree.clone())
} else {
self.push_all_but_last_tree(&last_stream);
let glued_span = last_span.to(span);
let glued_tt = TokenTree::Token(glued_span, glued_tok);
- let glued_tokenstream = TokenStream::Tree(glued_tt, is_joint);
+ let glued_tokenstream = TokenStream::new(vec![(glued_tt, is_joint)]);
self.0.push(glued_tokenstream);
self.push_all_but_first_tree(&stream);
return
}
fn push_all_but_last_tree(&mut self, stream: &TokenStream) {
- if let TokenStream::Stream(ref streams) = stream {
+ if let Some(ref streams) = stream.0 {
let len = streams.len();
match len {
1 => {}
- 2 => self.0.push(TokenStream::Tree(streams[0].0.clone(), streams[0].1)),
- _ => self.0.push(TokenStream::Stream(Lrc::new(streams[0 .. len - 1].to_vec()))),
+ _ => self.0.push(TokenStream(Some(Lrc::new(streams[0 .. len - 1].to_vec())))),
}
}
}
fn push_all_but_first_tree(&mut self, stream: &TokenStream) {
- if let TokenStream::Stream(ref streams) = stream {
+ if let Some(ref streams) = stream.0 {
let len = streams.len();
match len {
1 => {}
- 2 => self.0.push(TokenStream::Tree(streams[1].0.clone(), streams[1].1)),
- _ => self.0.push(TokenStream::Stream(Lrc::new(streams[1 .. len].to_vec()))),
+ _ => self.0.push(TokenStream(Some(Lrc::new(streams[1 .. len].to_vec())))),
}
}
}
}
pub fn next_with_joint(&mut self) -> Option<TreeAndJoint> {
- match self.stream {
- TokenStream::Empty => None,
- TokenStream::Tree(ref tree, ref is_joint) => {
- if self.index == 0 {
- self.index = 1;
- Some((tree.clone(), *is_joint))
- } else {
- None
- }
- }
- TokenStream::Stream(ref stream) => {
+ match self.stream.0 {
+ None => None,
+ Some(ref stream) => {
if self.index < stream.len() {
self.index += 1;
Some(stream[self.index - 1].clone())
return;
}
let index = self.index;
- let stream = mem::replace(&mut self.stream, TokenStream::Empty);
+ let stream = mem::replace(&mut self.stream, TokenStream(None));
*self = TokenStream::from_streams(vec![stream, new_stream]).into_trees();
self.index = index;
}
pub fn look_ahead(&self, n: usize) -> Option<TokenTree> {
- match self.stream {
- TokenStream::Empty => None,
- TokenStream::Tree(ref tree, _) => {
- if n == 0 && self.index == 0 {
- Some(tree.clone())
- } else {
- None
- }
- }
- TokenStream::Stream(ref stream) =>
- stream[self.index ..].get(n).map(|(tree, _)| tree.clone()),
+ match self.stream.0 {
+ None => None,
+ Some(ref stream) => stream[self.index ..].get(n).map(|(tree, _)| tree.clone()),
}
}
}
-/// The `TokenStream` type is large enough to represent a single `TokenTree` without allocation.
-/// `ThinTokenStream` is smaller, but needs to allocate to represent a single `TokenTree`.
-/// We must use `ThinTokenStream` in `TokenTree::Delimited` to avoid infinite size due to recursion.
-#[derive(Debug, Clone)]
-pub struct ThinTokenStream(Option<Lrc<Vec<TreeAndJoint>>>);
-
-impl ThinTokenStream {
- pub fn stream(&self) -> TokenStream {
- self.clone().into()
- }
-}
-
-impl From<TokenStream> for ThinTokenStream {
- fn from(stream: TokenStream) -> ThinTokenStream {
- ThinTokenStream(match stream {
- TokenStream::Empty => None,
- TokenStream::Tree(tree, is_joint) => Some(Lrc::new(vec![(tree, is_joint)])),
- TokenStream::Stream(stream) => Some(stream),
- })
- }
-}
-
-impl From<ThinTokenStream> for TokenStream {
- fn from(stream: ThinTokenStream) -> TokenStream {
- stream.0.map(TokenStream::Stream).unwrap_or_else(TokenStream::empty)
- }
-}
-
-impl Eq for ThinTokenStream {}
-
-impl PartialEq<ThinTokenStream> for ThinTokenStream {
- fn eq(&self, other: &ThinTokenStream) -> bool {
- TokenStream::from(self.clone()) == TokenStream::from(other.clone())
- }
-}
-
impl fmt::Display for TokenStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&pprust::tokens_to_string(self.clone()))
}
}
-impl Encodable for ThinTokenStream {
- fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), E::Error> {
- TokenStream::from(self.clone()).encode(encoder)
- }
-}
-
-impl Decodable for ThinTokenStream {
- fn decode<D: Decoder>(decoder: &mut D) -> Result<ThinTokenStream, D::Error> {
- TokenStream::decode(decoder).map(Into::into)
- }
-}
-
#[derive(Debug, Copy, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub struct DelimSpan {
pub open: Span,
{
let mut p = string_to_parser(&ps, s);
let x = panictry!(f(&mut p));
- p.abort_if_errors();
+ p.sess.span_diagnostic.abort_if_errors();
x
}
pub fn walk_tt<'a, V: Visitor<'a>>(visitor: &mut V, tt: TokenTree) {
match tt {
TokenTree::Token(_, tok) => visitor.visit_token(tok),
- TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts.stream()),
+ TokenTree::Delimited(_, _, tts) => visitor.visit_tts(tts),
}
}
match e.node {
ast::ExprKind::Lit(ref lit) => match lit.node {
ast::LitKind::Str(ref s, _)
+ | ast::LitKind::Err(ref s)
| ast::LitKind::Float(ref s, _)
| ast::LitKind::FloatUnsuffixed(ref s) => {
accumulator.push_str(&s.as_str());
let fill = arg.format.fill.unwrap_or(' ');
- if *arg != simple_arg || fill != ' ' {
+ let pos_simple =
+ arg.position.index() == simple_arg.position.index();
+
+ if !pos_simple || arg.format != simple_arg.format || fill != ' ' {
self.all_pieces_simple = false;
}
#![feature(decl_macro)]
#![feature(nll)]
#![feature(str_escape)]
-#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![recursion_limit="256"]
use syntax::symbol::Symbol;
pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
- user_exts: Vec<NamedSyntaxExtension>,
- enable_quotes: bool) {
+ user_exts: Vec<NamedSyntaxExtension>) {
deriving::register_builtin_derives(resolver);
let mut register = |name, ext| {
)* }
}
- if enable_quotes {
- use syntax::ext::quote::*;
- register! {
- quote_tokens: expand_quote_tokens,
- quote_expr: expand_quote_expr,
- quote_ty: expand_quote_ty,
- quote_item: expand_quote_item,
- quote_pat: expand_quote_pat,
- quote_arm: expand_quote_arm,
- quote_stmt: expand_quote_stmt,
- quote_attr: expand_quote_attr,
- quote_arg: expand_quote_arg,
- quote_block: expand_quote_block,
- quote_meta_item: expand_quote_meta_item,
- quote_path: expand_quote_path,
- }
- }
-
use syntax::ext::source_util::*;
register! {
line: expand_line,
};
let tree = tokenstream::TokenTree::Token(span, token);
- TokenStream::Tree(tree, if joint { Joint } else { NonJoint })
+ TokenStream::new(vec![(tree, if joint { Joint } else { NonJoint })])
}
}
&self.primary_spans
}
+ /// Returns whether any of the primary spans is displayable.
+ pub fn has_primary_spans(&self) -> bool {
+ self.primary_spans.iter().any(|sp| !sp.is_dummy())
+ }
+
/// Returns `true` if this contains only a dummy primary span with any hygienic context.
pub fn is_dummy(&self) -> bool {
let mut is_dummy = true;
span_labels
}
+
+ /// Returns whether any of the span labels is displayable.
+ pub fn has_span_labels(&self) -> bool {
+ self.span_labels.iter().any(|(sp, _)| !sp.is_dummy())
+ }
}
impl From<Span> for MultiSpan {
--- /dev/null
+// compile-flags: -C no-prepopulate-passes
+// ignore-tidy-linelength
+
+#![crate_type = "lib"]
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct u32x2(u32, u32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct i32x2(i32, i32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct i8x16(
+ i8, i8, i8, i8, i8, i8, i8, i8,
+ i8, i8, i8, i8, i8, i8, i8, i8,
+);
+
+
+extern "platform-intrinsic" {
+ fn simd_bitmask<T, U>(x: T) -> U;
+}
+
+// CHECK-LABEL: @bitmask_int
+#[no_mangle]
+pub unsafe fn bitmask_int(x: i32x2) -> u8 {
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9]+}}, <i32 31, i32 31>
+ // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+ // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
+ // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
+ simd_bitmask(x)
+}
+
+// CHECK-LABEL: @bitmask_uint
+#[no_mangle]
+pub unsafe fn bitmask_uint(x: u32x2) -> u8 {
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{[0-9]+}}, <i32 31, i32 31>
+ // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+ // CHECK: [[C:%[0-9]+]] = bitcast <2 x i1> [[B]] to i2
+ // CHECK: %{{[0-9]+}} = zext i2 [[C]] to i8
+ simd_bitmask(x)
+}
+
+// CHECK-LABEL: @bitmask_int16
+#[no_mangle]
+pub unsafe fn bitmask_int16(x: i8x16) -> u16 {
+ // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{[0-9]+}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+ // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
+ // CHECK: %{{[0-9]+}} = bitcast <16 x i1> [[B]] to i16
+ // CHECK-NOT: zext
+ simd_bitmask(x)
+}
+++ /dev/null
-// ignore-cross-compile
-
-// error-pattern:expected expression, found statement (`let`)
-
-#![feature(quote, rustc_private)]
-
-extern crate syntax;
-extern crate syntax_pos;
-
-use syntax::ast;
-use syntax::source_map;
-use syntax::print::pprust;
-use syntax::symbol::Symbol;
-use syntax_pos::DUMMY_SP;
-
-fn main() {
- syntax::with_globals(|| run());
-}
-
-fn run() {
- let ps = syntax::parse::ParseSess::new(source_map::FilePathMapping::empty());
- let mut resolver = syntax::ext::base::DummyResolver;
- let mut cx = syntax::ext::base::ExtCtxt::new(
- &ps,
- syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
- &mut resolver);
- let cx = &mut cx;
-
- println!("{}", pprust::expr_to_string(&*quote_expr!(&cx, 23)));
- assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
-
- let expr = quote_expr!(&cx, let x isize = 20;);
- println!("{}", pprust::expr_to_string(&*expr));
- assert_eq!(pprust::expr_to_string(&*expr), "let x isize = 20;");
-}
+++ /dev/null
-// force-host
-
-#![feature(plugin_registrar, quote, rustc_private)]
-#![crate_type = "dylib"]
-
-extern crate syntax;
-extern crate rustc;
-extern crate rustc_data_structures;
-extern crate rustc_plugin;
-#[macro_use] extern crate smallvec;
-extern crate syntax_pos;
-
-use smallvec::SmallVec;
-use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
-use syntax::tokenstream;
-use rustc_plugin::Registry;
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_macro("multiple_items", expand)
-}
-
-fn expand(cx: &mut ExtCtxt, _: syntax_pos::Span, _: &[tokenstream::TokenTree])
- -> Box<MacResult+'static> {
- MacEager::items(smallvec![
- quote_item!(cx, struct Struct1;).unwrap(),
- quote_item!(cx, struct Struct2;).unwrap()
- ])
-}
// force-host
+// no-prefer-dynamic
-#![feature(plugin_registrar, quote, rustc_private)]
+#![crate_type = "proc-macro"]
+#![feature(rustc_private)]
extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;
extern crate syntax_pos;
-
-use syntax::ast::{self, Item, MetaItem, ItemKind};
-use syntax::source_map::DUMMY_SP;
-use syntax::ext::base::*;
-use syntax::ext::quote::rt::ToTokens;
-use syntax::parse::{self, token};
-use syntax::ptr::P;
-use syntax::symbol::Symbol;
-use syntax::tokenstream::TokenTree;
-use syntax_pos::Span;
-use rustc_plugin::Registry;
-
-#[macro_export]
-macro_rules! exported_macro { () => (2) }
-macro_rules! unexported_macro { () => (3) }
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_macro("make_a_1", expand_make_a_1);
- reg.register_macro("identity", expand_identity);
- reg.register_syntax_extension(
- Symbol::intern("rustc_into_multi_foo"),
- MultiModifier(Box::new(expand_into_foo_multi)));
- reg.register_syntax_extension(
- Symbol::intern("rustc_duplicate"),
- MultiDecorator(Box::new(expand_duplicate)));
- reg.register_syntax_extension(
- Symbol::intern("rustc_caller"),
- MultiDecorator(Box::new(expand_caller)));
-}
-
-fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
- if !tts.is_empty() {
- cx.span_fatal(sp, "make_a_1 takes no arguments");
- }
- MacEager::expr(quote_expr!(cx, 1))
-}
-
-// See Issue #15750
-fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) -> Box<MacResult + 'static> {
- // Parse an expression and emit it unchanged.
- let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.to_vec());
- let expr = parser.parse_expr().unwrap();
- MacEager::expr(quote_expr!(&mut *cx, $expr))
-}
-
-fn expand_into_foo_multi(cx: &mut ExtCtxt,
- _sp: Span,
- _attr: &MetaItem,
- it: Annotatable)
- -> Vec<Annotatable> {
- match it {
- Annotatable::Item(it) => vec![
- Annotatable::Item(P(Item {
- attrs: it.attrs.clone(),
- ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
- })),
- Annotatable::Item(quote_item!(cx, enum Foo3 { Bar }).unwrap()),
- Annotatable::Item(quote_item!(cx, #[cfg(any())] fn foo2() {}).unwrap()),
- ],
- Annotatable::ImplItem(_it) => vec![
- quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
- match i.node {
- ItemKind::Impl(.., mut items) => {
- Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
- }
- _ => unreachable!("impl parsed to something other than impl")
- }
- })
- ],
- Annotatable::TraitItem(_it) => vec![
- quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
- match i.node {
- ItemKind::Trait(.., mut items) => {
- Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
- }
- _ => unreachable!("trait parsed to something other than trait")
- }
- })
- ],
- // covered in proc_macro/macros-in-extern.rs
- Annotatable::ForeignItem(..) => unimplemented!(),
- // covered in proc_macro/attr-stmt-expr.rs
- Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item"),
- }
+extern crate proc_macro;
+
+use proc_macro::{TokenTree, TokenStream};
+
+#[proc_macro_attribute]
+pub fn rustc_duplicate(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let mut new_name = Some(attr.into_iter().nth(0).unwrap());
+ let mut encountered_idents = 0;
+ let input = item.to_string();
+ let ret = item.into_iter().map(move |token| match token {
+ TokenTree::Ident(_) if encountered_idents == 1 => {
+ encountered_idents += 1;
+ new_name.take().unwrap()
+ }
+ TokenTree::Ident(_) => {
+ encountered_idents += 1;
+ token
+ }
+ _ => token
+ }).collect::<TokenStream>();
+ let mut input_again = input.parse::<TokenStream>().unwrap();
+ input_again.extend(ret);
+ input_again
}
-
-// Create a duplicate of the annotatable, based on the MetaItem
-fn expand_duplicate(cx: &mut ExtCtxt,
- _sp: Span,
- mi: &MetaItem,
- it: &Annotatable,
- push: &mut FnMut(Annotatable)) {
- let copy_name = match mi.node {
- ast::MetaItemKind::List(ref xs) => {
- if let Some(word) = xs[0].word() {
- word.ident.segments.last().unwrap().ident
- } else {
- cx.span_err(mi.span, "Expected word");
- return;
- }
- }
- _ => {
- cx.span_err(mi.span, "Expected list");
- return;
- }
- };
-
- // Duplicate the item but replace its ident by the MetaItem
- match it.clone() {
- Annotatable::Item(it) => {
- let mut new_it = (*it).clone();
- new_it.attrs.clear();
- new_it.ident = copy_name;
- push(Annotatable::Item(P(new_it)));
- }
- Annotatable::ImplItem(it) => {
- let mut new_it = (*it).clone();
- new_it.attrs.clear();
- new_it.ident = copy_name;
- push(Annotatable::ImplItem(P(new_it)));
- }
- Annotatable::TraitItem(tt) => {
- let mut new_it = (*tt).clone();
- new_it.attrs.clear();
- new_it.ident = copy_name;
- push(Annotatable::TraitItem(P(new_it)));
- }
- // covered in proc_macro/macros-in-extern.rs
- Annotatable::ForeignItem(..) => unimplemented!(),
- // covered in proc_macro/attr-stmt-expr.rs
- Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
- }
-}
-
-pub fn token_separate<T: ToTokens>(ecx: &ExtCtxt, things: &[T],
- token: token::Token) -> Vec<TokenTree> {
- let mut output: Vec<TokenTree> = vec![];
- for (i, thing) in things.iter().enumerate() {
- output.extend(thing.to_tokens(ecx));
- if i < things.len() - 1 {
- output.push(TokenTree::Token(DUMMY_SP, token.clone()));
- }
- }
-
- output
-}
-
-fn expand_caller(cx: &mut ExtCtxt,
- sp: Span,
- mi: &MetaItem,
- it: &Annotatable,
- push: &mut FnMut(Annotatable)) {
- let (orig_fn_name, ret_type) = match *it {
- Annotatable::Item(ref item) => match item.node {
- ItemKind::Fn(ref decl, ..) => {
- (item.ident, &decl.output)
- }
- _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.")
- },
- _ => cx.span_fatal(sp, "Only functions can be annotated.")
- };
-
- let (caller_name, arguments) = if let Some(list) = mi.meta_item_list() {
- if list.len() < 2 {
- cx.span_fatal(mi.span(), "Need a function name and at least one parameter.");
- }
-
- let fn_name = match list[0].name() {
- Some(name) => ast::Ident::with_empty_ctxt(name),
- None => cx.span_fatal(list[0].span(), "First parameter must be an ident.")
- };
-
- (fn_name, &list[1..])
- } else {
- cx.span_fatal(mi.span, "Expected list.");
- };
-
- let literals: Vec<ast::Lit> = arguments.iter().map(|arg| {
- if let Some(lit) = arg.literal() {
- lit.clone()
- } else {
- cx.span_fatal(arg.span(), "Expected literal.");
- }
- }).collect();
-
- let arguments = token_separate(cx, literals.as_slice(), token::Comma);
- if let ast::FunctionRetTy::Ty(ref rt) = *ret_type {
- push(Annotatable::Item(quote_item!(cx,
- fn $caller_name() -> $rt {
- $orig_fn_name($arguments)
- }).unwrap()))
- } else {
- push(Annotatable::Item(quote_item!(cx,
- fn $caller_name() {
- $orig_fn_name($arguments)
- }).unwrap()))
- }
-}
-
-pub fn foo() {}
+++ /dev/null
-// force-host
-
-#![feature(plugin_registrar, rustc_private)]
-#![deny(plugin_as_library)] // should have no effect in a plugin crate
-
-extern crate macro_crate_test;
-extern crate rustc;
-extern crate rustc_plugin;
-
-use rustc_plugin::Registry;
-
-#[plugin_registrar]
-pub fn plugin_registrar(_: &mut Registry) { }
+++ /dev/null
-// force-host
-
-#![crate_type="dylib"]
-#![feature(plugin_registrar, quote, rustc_private)]
-
-extern crate syntax;
-extern crate syntax_pos;
-extern crate rustc;
-extern crate rustc_plugin;
-
-use syntax::feature_gate::Features;
-use syntax::parse::token::{NtExpr, NtPat};
-use syntax::ast::{Ident, Pat, NodeId};
-use syntax::tokenstream::{TokenTree};
-use syntax::ext::base::{ExtCtxt, MacResult, MacEager};
-use syntax::ext::build::AstBuilder;
-use syntax::ext::tt::quoted;
-use syntax::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
-use syntax::ext::tt::macro_parser::{Success, Failure, Error};
-use syntax::ext::tt::macro_parser::parse_failure_msg;
-use syntax::ptr::P;
-use syntax_pos::{Span, edition::Edition};
-use rustc_plugin::Registry;
-
-fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree])
- -> Box<MacResult + 'static> {
-
- let mbe_matcher = quote_tokens!(cx, $$matched:expr, $$($$pat:pat)|+);
- let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(),
- true,
- cx.parse_sess,
- &Features::new(),
- &[],
- Edition::Edition2015,
- // not used...
- NodeId::from_u32(0));
- let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) {
- Success(map) => map,
- Failure(_, tok, msg) => {
- panic!("expected Success, but got Failure: {} - {}", parse_failure_msg(tok), msg);
- }
- Error(_, s) => {
- panic!("expected Success, but got Error: {}", s);
- }
- };
-
- let matched_nt = match *map[&Ident::from_str("matched")] {
- MatchedNonterminal(ref nt) => nt.clone(),
- _ => unreachable!(),
- };
-
- let mac_expr = match (&*matched_nt, &*map[&Ident::from_str("pat")]) {
- (&NtExpr(ref matched_expr), &MatchedSeq(ref pats, seq_sp)) => {
- let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt| {
- match *pat_nt {
- MatchedNonterminal(ref nt) => match **nt {
- NtPat(ref pat) => pat.clone(),
- _ => unreachable!(),
- },
- _ => unreachable!(),
- }
- }).collect();
- let span = seq_sp.entire();
- let arm = cx.arm(span, pats, cx.expr_bool(span, true));
-
- quote_expr!(cx,
- match $matched_expr {
- $arm
- _ => false
- }
- )
- }
- _ => unreachable!()
- };
-
- MacEager::expr(mac_expr)
-}
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_macro("matches", expand_mbe_matches);
-}
+++ /dev/null
-// force-host
-
-#![crate_type = "dylib"]
-#![feature(plugin_registrar, quote, rustc_private)]
-
-extern crate syntax_extension_with_dll_deps_1 as other;
-extern crate syntax;
-extern crate syntax_pos;
-extern crate rustc;
-extern crate rustc_plugin;
-
-use syntax::ast::{Item, MetaItem};
-use syntax::ext::base::*;
-use syntax::tokenstream::TokenTree;
-use syntax_pos::Span;
-use rustc_plugin::Registry;
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_macro("foo", expand_foo);
-}
-
-fn expand_foo(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
- -> Box<MacResult+'static> {
- let answer = other::the_answer();
- MacEager::expr(quote_expr!(cx, $answer))
-}
+++ /dev/null
-// ignore-stage1
-// aux-build:issue-16723.rs
-#![feature(plugin)]
-#![plugin(issue_16723)]
-
-multiple_items!();
-
-impl Struct1 {
- fn foo() {}
-}
-impl Struct2 {
- fn foo() {}
-}
-
-fn main() {
- Struct1::foo();
- Struct2::foo();
- println!("hallo");
-}
+++ /dev/null
-// ignore-cross-compile
-
-#![feature(quote, rustc_private)]
-
-extern crate syntax;
-
-use syntax::ext::base::ExtCtxt;
-
-#[allow(dead_code)]
-fn foobar(cx: &mut ExtCtxt) {
- quote_expr!(cx, 1);
- quote_expr!(cx, 2);
-}
-
-fn main() { }
+++ /dev/null
-#![allow(dead_code)]
-#![allow(unused_imports)]
-// ignore-cross-compile
-#![feature(quote, rustc_private)]
-
-extern crate syntax;
-
-use syntax::ext::base::ExtCtxt;
-
-fn syntax_extension(cx: &ExtCtxt) {
- let _toks_1 = vec![quote_tokens!(cx, /** comment */ fn foo() {})];
- let name = quote_tokens!(cx, bar);
- let _toks_2 = vec![quote_item!(cx, static $name:isize = 2;)];
- let _toks_4 = quote_tokens!(cx, $name:static $name:sizeof);
- let _toks_3 = vec![quote_item!(cx,
- /// comment
- fn foo() { let $name:isize = 3; }
- )];
-}
-
-fn main() {
-}
+++ /dev/null
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-
-// Issue #15750: a macro that internally parses its input and then
-// uses `quote_expr!` to rearrange it should be hygiene-preserving.
-
-#![feature(plugin)]
-#![plugin(macro_crate_test)]
-
-fn main() {
- let x = 3;
- assert_eq!(3, identity!(x));
- assert_eq!(6, identity!(x+x));
- let x = 4;
- assert_eq!(4, identity!(x));
-}
+++ /dev/null
-#![allow(plugin_as_library)]
-#![allow(unused_imports)]
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-
-#![feature(plugin, rustc_attrs)]
-#![plugin(macro_crate_test)]
-
-#[macro_use]
-#[no_link]
-extern crate macro_crate_test;
-
-// The `caller(name, args...)` attribute emits a new nullary function named
-// `name` that calls the annotated function with `args`. As an example, consider
-// the following:
-//
-// #[caller(simple, 1, "hello", 3.14)]
-// fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, float) {
-// (num, string, float)
-// }
-//
-// This results in a function named `simple` that calls `f(1, "hello", 3.14)`.
-// As a result, the expression `simple()` evaluates to `(1, "helllo", 3.14)`.
-
-#[rustc_caller(simple, 1, "hello", 3.14)]
-#[rustc_caller(simple1, 2, "bye", 6.28)]
-#[rustc_caller(simple2, 3, "hi", 1.01)]
-fn f(num: isize, string: &'static str, float: f32) -> (isize, &'static str, f32) {
- (num, string, float)
-}
-
-#[rustc_caller(complex, true, 10)]
-#[rustc_caller(complex1, false, 15)]
-#[rustc_caller(complex2, true, 20)]
-fn g(emit: bool, num: i32) -> Option<i32> {
- match emit {
- true => Some(num),
- false => None
- }
-}
-
-fn main() {
- assert_eq!(simple(), (1, "hello", 3.14));
- assert_eq!(simple1(), (2, "bye", 6.28));
- assert_eq!(simple2(), (3, "hi", 1.01));
-
- assert_eq!(complex(), Some(10));
- assert_eq!(complex1(), None);
- assert_eq!(complex2(), Some(20));
-}
// aux-build:macro_crate_test.rs
// ignore-stage1
-#![feature(plugin, rustc_attrs)]
-#![plugin(macro_crate_test)]
+#![feature(rustc_attrs)]
#[macro_use]
-#[no_link]
extern crate macro_crate_test;
// The duplicate macro will create a copy of the item with the given identifier.
+++ /dev/null
-#![allow(plugin_as_library)]
-#![allow(dead_code)]
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-
-#![feature(plugin, rustc_attrs)]
-#![plugin(macro_crate_test)]
-
-#[macro_use] #[no_link]
-extern crate macro_crate_test;
-
-#[rustc_into_multi_foo]
-#[derive(PartialEq, Clone, Debug)]
-fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
-
-// Check that the `#[into_multi_foo]`-generated `foo2` is configured away
-fn foo2() {}
-
-trait Qux {
- #[rustc_into_multi_foo]
- fn bar();
-}
-
-impl Qux for i32 {
- #[rustc_into_multi_foo]
- fn bar() {}
-}
-
-impl Qux for u8 {}
-
-pub fn main() {
- assert_eq!(1, make_a_1!());
- assert_eq!(2, exported_macro!());
-
- assert_eq!(Foo2::Bar2, Foo2::Bar2);
- test(None::<Foo2>);
-
- let _ = Foo3::Bar;
-
- let x = 10i32;
- assert_eq!(x.foo(), 42);
- let x = 10u8;
- assert_eq!(x.foo(), 0);
-}
-
-fn test<T: PartialEq+Clone>(_: Option<T>) {}
+++ /dev/null
-// aux-build:procedural_mbe_matching.rs
-// ignore-stage1
-
-#![feature(plugin)]
-#![plugin(procedural_mbe_matching)]
-
-pub fn main() {
- assert_eq!(matches!(Some(123), None | Some(0)), false);
- assert_eq!(matches!(Some(123), None | Some(123)), true);
- assert_eq!(matches!(true, true), true);
-}
+++ /dev/null
-// aux-build:macro_crate_test.rs
-// aux-build:plugin_with_plugin_lib.rs
-// ignore-stage1
-// ignore-cross-compile
-//
-// macro_crate_test will not compile on a cross-compiled target because
-// libsyntax is not compiled for it.
-
-#![deny(plugin_as_library)]
-#![feature(plugin)]
-#![plugin(macro_crate_test)]
-#![plugin(plugin_with_plugin_lib)]
-
-fn main() {
- assert_eq!(1, make_a_1!());
-}
+++ /dev/null
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-// ignore-cross-compile
-//
-// macro_crate_test will not compile on a cross-compiled target because
-// libsyntax is not compiled for it.
-
-#![allow(plugin_as_library)]
-#![feature(plugin)]
-#![plugin(macro_crate_test)]
-
-extern crate macro_crate_test;
-
-fn main() {
- assert_eq!(1, make_a_1!());
- macro_crate_test::foo();
-}
+++ /dev/null
-#![allow(unused_imports)]
-// ignore-cross-compile
-
-#![feature(quote, rustc_private)]
-
-extern crate syntax;
-extern crate syntax_pos;
-
-use syntax::source_map::FilePathMapping;
-use syntax::print::pprust::*;
-use syntax::symbol::Symbol;
-use syntax_pos::DUMMY_SP;
-
-fn main() {
- syntax::with_globals(|| run());
-}
-
-fn run() {
- let ps = syntax::parse::ParseSess::new(FilePathMapping::empty());
- let mut resolver = syntax::ext::base::DummyResolver;
- let mut cx = syntax::ext::base::ExtCtxt::new(
- &ps,
- syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
- &mut resolver);
- let cx = &mut cx;
-
- macro_rules! check {
- ($f: ident, $($e: expr),+; $expect: expr) => ({
- $(assert_eq!($f(&$e), $expect);)+
- });
- }
-
- let abc = quote_expr!(cx, 23);
- check!(expr_to_string, abc, *quote_expr!(cx, $abc); "23");
-
- let ty = quote_ty!(cx, isize);
- check!(ty_to_string, ty, *quote_ty!(cx, $ty); "isize");
-
- let item = quote_item!(cx, static x: $ty = 10;).unwrap();
- check!(item_to_string, item, quote_item!(cx, $item).unwrap(); "static x: isize = 10;");
-
- let twenty: u16 = 20;
- let stmt = quote_stmt!(cx, let x = $twenty;).unwrap();
- check!(stmt_to_string, stmt, quote_stmt!(cx, $stmt).unwrap(); "let x = 20u16;");
-
- let pat = quote_pat!(cx, Some(_));
- check!(pat_to_string, pat, *quote_pat!(cx, $pat); "Some(_)");
-
- let expr = quote_expr!(cx, (x, y));
- let arm = quote_arm!(cx, (ref x, ref y) => $expr,);
- check!(arm_to_string, arm, quote_arm!(cx, $arm); " (ref x, ref y) => (x, y),");
-
- let attr = quote_attr!(cx, #![cfg(foo = "bar")]);
- check!(attribute_to_string, attr, quote_attr!(cx, $attr); r#"#![cfg(foo = "bar")]"#);
-
- // quote_arg!
-
- let arg = quote_arg!(cx, foo: i32);
- check!(arg_to_string, arg, quote_arg!(cx, $arg); "foo: i32");
-
- let function = quote_item!(cx, fn f($arg) { }).unwrap();
- check!(item_to_string, function; "fn f(foo: i32) { }");
-
- let args = vec![arg, quote_arg!(cx, bar: u32)];
- let args = &args[..];
- let function = quote_item!(cx, fn f($args) { }).unwrap();
- check!(item_to_string, function; "fn f(foo: i32, bar: u32) { }");
-
- // quote_block!
-
- let block = quote_block!(cx, { $stmt let y = 40u32; });
- check!(block_to_string, block, *quote_block!(cx, $block); "{ let x = 20u16; let y = 40u32; }");
-
- let function = quote_item!(cx, fn f() $block).unwrap();
- check!(item_to_string, function; "fn f() { let x = 20u16; let y = 40u32; }");
-
- // quote_path!
-
- let path = quote_path!(cx, ::syntax::ptr::P<MetaItem>);
- check!(path_to_string, path, quote_path!(cx, $path); "::syntax::ptr::P<MetaItem>");
-
- let ty = quote_ty!(cx, $path);
- check!(ty_to_string, ty; "::syntax::ptr::P<MetaItem>");
-
- // quote_meta_item!
-
- let meta = quote_meta_item!(cx, cfg(foo = "bar"));
- check!(meta_item_to_string, meta, quote_meta_item!(cx, $meta); r#"cfg(foo = "bar")"#);
-
- let attr = quote_attr!(cx, #![$meta]);
- check!(attribute_to_string, attr; r#"#![cfg(foo = "bar")]"#);
-}
+++ /dev/null
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![allow(unused_imports)]
-// ignore-cross-compile
-#![feature(quote, rustc_private)]
-
-extern crate syntax;
-
-use syntax::ext::base::ExtCtxt;
-use syntax::ptr::P;
-use syntax::parse::PResult;
-
-fn syntax_extension(cx: &ExtCtxt) {
- let e_toks : Vec<syntax::tokenstream::TokenTree> = quote_tokens!(cx, 1 + 2);
- let p_toks : Vec<syntax::tokenstream::TokenTree> = quote_tokens!(cx, (x, 1 .. 4, *));
-
- let a: P<syntax::ast::Expr> = quote_expr!(cx, 1 + 2);
- let _b: Option<P<syntax::ast::Item>> = quote_item!(cx, static foo : isize = $e_toks; );
- let _c: P<syntax::ast::Pat> = quote_pat!(cx, (x, 1 .. 4, *) );
- let _d: Option<syntax::ast::Stmt> = quote_stmt!(cx, let x = $a; );
- let _d: syntax::ast::Arm = quote_arm!(cx, (ref x, ref y) = (x, y) );
- let _e: P<syntax::ast::Expr> = quote_expr!(cx, match foo { $p_toks => 10 } );
-
- let _f: P<syntax::ast::Expr> = quote_expr!(cx, ());
- let _g: P<syntax::ast::Expr> = quote_expr!(cx, true);
- let _h: P<syntax::ast::Expr> = quote_expr!(cx, 'a');
-
- let i: Option<P<syntax::ast::Item>> = quote_item!(cx, #[derive(Eq)] struct Foo; );
- assert!(i.is_some());
-
- let _l: P<syntax::ast::Ty> = quote_ty!(cx, &isize);
-
- let _n: syntax::ast::Attribute = quote_attr!(cx, #![cfg(foo, bar = "baz")]);
-
- let _o: Option<P<syntax::ast::Item>> = quote_item!(cx, fn foo<T: ?Sized>() {});
-
- let stmts = vec![
- quote_stmt!(cx, let x = 1;).unwrap(),
- quote_stmt!(cx, let y = 2;).unwrap(),
- ];
- let expr: P<syntax::ast::Expr> = quote_expr!(cx, x + y);
-}
-
-fn main() {
-}
+++ /dev/null
-#![allow(dead_code)]
-// ignore-cross-compile
-#![feature(quote, rustc_private)]
-#![deny(unused_variables)]
-
-extern crate syntax;
-
-use syntax::ext::base::ExtCtxt;
-
-fn test(cx: &mut ExtCtxt) {
- let foo = 10;
- let _e = quote_expr!(cx, $foo);
-}
-
-pub fn main() { }
+++ /dev/null
-// aux-build:syntax_extension_with_dll_deps_1.rs
-// aux-build:syntax_extension_with_dll_deps_2.rs
-// ignore-stage1
-
-#![feature(plugin, rustc_private)]
-#![plugin(syntax_extension_with_dll_deps_2)]
-
-fn main() {
- foo!();
-}
--- /dev/null
+// run-pass
+#![allow(non_camel_case_types)]
+
+// ignore-emscripten
+
+// Test that the simd_bitmask intrinsic produces correct results.
+
+#![feature(repr_simd, platform_intrinsics)]
+#[allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct u32x4(pub u32, pub u32, pub u32, pub u32);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct u8x4(pub u8, pub u8, pub u8, pub u8);
+
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+struct Tx4<T>(pub T, pub T, pub T, pub T);
+
+extern "platform-intrinsic" {
+ fn simd_bitmask<T, U>(x: T) -> U;
+}
+
+fn main() {
+ let z = u32x4(0, 0, 0, 0);
+ let ez = 0_u8;
+
+ let o = u32x4(!0, !0, !0, !0);
+ let eo = 0b_1111_u8;
+
+ let m0 = u32x4(!0, 0, !0, 0);
+ let e0 = 0b_0000_0101_u8;
+
+ // Check that the MSB is extracted:
+ let m = u8x4(0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111);
+ let e = 0b_1101;
+
+ // Check usize / isize
+ let msize: Tx4<usize> = Tx4(usize::max_value(), 0, usize::max_value(), usize::max_value());
+
+ unsafe {
+ let r: u8 = simd_bitmask(z);
+ assert_eq!(r, ez);
+
+ let r: u8 = simd_bitmask(o);
+ assert_eq!(r, eo);
+
+ let r: u8 = simd_bitmask(m0);
+ assert_eq!(r, e0);
+
+ let r: u8 = simd_bitmask(m);
+ assert_eq!(r, e);
+
+ let r: u8 = simd_bitmask(msize);
+ assert_eq!(r, e);
+
+ }
+}
--- /dev/null
+// This test relies on `TryFrom` being blanket impl for all `T: Into`
+// and `TryInto` being blanket impl for all `U: TryFrom`
+
+// This test was added to show the motivation for doing this
+// over `TryFrom` being blanket impl for all `T: From`
+
+#![feature(try_from, never_type)]
+
+use std::convert::TryInto;
+
+struct Foo<T> {
+ t: T,
+}
+
+// This fails to compile due to coherence restrictions
+// as of Rust version 1.32.x, therefore it could not be used
+// instead of the `Into` version of the impl, and serves as
+// motivation for a blanket impl for all `T: Into`, instead
+// of a blanket impl for all `T: From`
+/*
+impl<T> From<Foo<T>> for Box<T> {
+ fn from(foo: Foo<T>) -> Box<T> {
+ Box::new(foo.t)
+ }
+}
+*/
+
+impl<T> Into<Vec<T>> for Foo<T> {
+ fn into(self) -> Vec<T> {
+ vec![self.t]
+ }
+}
+
+pub fn main() {
+ let _: Result<Vec<i32>, !> = Foo { t: 10 }.try_into();
+}
+
// compile-pass
-// compile-flags: --error-format=human
/// ```
/// \__________pkt->size___________/ \_result->size_/ \__pkt->size__/
/// ```
pub fn foo() {}
+
+/// ```
+/// |
+/// LL | use foobar::Baz;
+/// | ^^^^^^ did you mean `baz::foobar`?
+/// ```
+pub fn bar() {}
+
+/// ```
+/// valid
+/// ```
+///
+/// ```
+/// \_
+/// ```
+///
+/// ```text
+/// "invalid
+/// ```
+pub fn valid_and_invalid() {}
+
+/// This is a normal doc comment, but...
+///
+/// There's a code block with bad syntax in it:
+///
+/// ```rust
+/// \_
+/// ```
+///
+/// Good thing we tested it!
+pub fn baz() {}
+
+/// Indented block start
+///
+/// code with bad syntax
+/// \_
+///
+/// Indented block end
+pub fn quux() {}
+
+/// Unclosed fence
+///
+/// ```
+/// slkdjf
+pub fn xyzzy() {}
+
+/// Indented code that contains a fence
+///
+/// ```
+pub fn blah() {}
+
+/// ```edition2018
+/// \_
+/// ```
+pub fn blargh() {}
+
+#[doc = "```"]
+/// \_
+#[doc = "```"]
+pub fn crazy_attrs() {}
-Output from rustc:
-error: unknown start of token: /
- --> <stdin>:1:1
- |
-1 | /__________pkt->size___________/ /_result->size_/ /__pkt->size__/
- | ^
-
-warning: Invalid doc comment starting with: `/__________pkt->size___________/ /_result->size_/ /__pkt->size__/`
-(Ignoring this codeblock)
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:3:5
+ |
+LL | /// ```
+ | _____^
+LL | | /// /__________pkt->size___________/ /_result->size_/ /__pkt->size__/
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: /
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ^^^^^^^
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:8:5
+ |
+LL | /// ```
+ | _____^
+LL | | /// |
+LL | | /// LL | use foobar::Baz;
+LL | | /// | ^^^^^^ did you mean `baz::foobar`?
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: `
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ^^^^^^^
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:19:5
+ |
+LL | /// ```
+ | _____^
+LL | | /// /_
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: /
+help: mark blocks that do not contain Rust code as text
+ |
+LL | /// ```text
+ | ^^^^^^^
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:32:5
+ |
+LL | /// ```rust
+ | _____^
+LL | | /// /_
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: /
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:41:9
+ |
+LL | /// code with bad syntax
+ | _________^
+LL | | /// /_
+ | |__________^
+ |
+ = note: error from rustc: unknown start of token: /
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:55:9
+ |
+LL | /// ```
+ | ^^^
+ |
+ = note: error from rustc: unknown start of token: `
+
+warning: could not parse code block as Rust code
+ --> $DIR/invalid-syntax.rs:58:5
+ |
+LL | /// ```edition2018
+ | _____^
+LL | | /// /_
+LL | | /// ```
+ | |_______^
+ |
+ = note: error from rustc: unknown start of token: /
+
+warning: doc comment contains an invalid Rust code block
+ --> $DIR/invalid-syntax.rs:63:1
+ |
+LL | / #[doc = "```"]
+LL | | /// /_
+LL | | #[doc = "```"]
+ | |______________^
+ |
+ = help: mark blocks that do not contain Rust code as text: ```text
--- /dev/null
+// @has bad_codeblock_syntax/fn.foo.html
+// @has - '//*[@class="docblock"]/pre/code' '\_'
+/// ```
+/// \_
+/// ```
+pub fn foo() {}
+
+// @has bad_codeblock_syntax/fn.bar.html
+// @has - '//*[@class="docblock"]/pre/code' '`baz::foobar`'
+/// ```
+/// `baz::foobar`
+/// ```
+pub fn bar() {}
+
+// @has bad_codeblock_syntax/fn.quux.html
+// @has - '//*[@class="docblock"]/pre/code' '\_'
+/// ```rust
+/// \_
+/// ```
+pub fn quux() {}
+
+// @has bad_codeblock_syntax/fn.ok.html
+// @has - '//*[@class="docblock"]/pre/code[@class="language-text"]' '\_'
+/// ```text
+/// \_
+/// ```
+pub fn ok() {}
#![crate_type="proc-macro"]
#![crate_name="some_macros"]
+// @has some_macros/index.html
+// @has - '//a/[@href="attr.some_proc_attr.html"]' 'some_proc_attr'
+
+//! include a link to [some_proc_attr] to make sure it works.
+
extern crate proc_macro;
use proc_macro::TokenStream;
+++ /dev/null
-// force-host
-
-#![feature(plugin_registrar, quote, rustc_private)]
-
-extern crate syntax;
-extern crate syntax_pos;
-extern crate rustc;
-extern crate rustc_plugin;
-
-use syntax::ast::{self, Item, MetaItem, ItemKind};
-use syntax::ext::base::*;
-use syntax::parse;
-use syntax::ptr::P;
-use syntax::symbol::Symbol;
-use syntax::tokenstream::TokenTree;
-use syntax_pos::Span;
-use rustc_plugin::Registry;
-
-#[macro_export]
-macro_rules! exported_macro { () => (2) }
-macro_rules! unexported_macro { () => (3) }
-
-#[plugin_registrar]
-pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_macro("make_a_1", expand_make_a_1);
- reg.register_macro("identity", expand_identity);
- reg.register_syntax_extension(
- Symbol::intern("into_multi_foo"),
- MultiModifier(Box::new(expand_into_foo_multi)));
- reg.register_syntax_extension(
- Symbol::intern("noop_attribute"),
- MultiModifier(Box::new(expand_noop_attribute)));
- reg.register_syntax_extension(
- Symbol::intern("duplicate"),
- MultiDecorator(Box::new(expand_duplicate)));
-}
-
-fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree])
- -> Box<MacResult+'static> {
- if !tts.is_empty() {
- cx.span_fatal(sp, "make_a_1 takes no arguments");
- }
- MacEager::expr(quote_expr!(cx, 1))
-}
-
-// See Issue #15750
-fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree])
- -> Box<MacResult+'static> {
- // Parse an expression and emit it unchanged.
- let mut parser = parse::new_parser_from_tts(cx.parse_sess(), tts.to_vec());
- let expr = parser.parse_expr().unwrap();
- MacEager::expr(quote_expr!(&mut *cx, $expr))
-}
-
-fn expand_into_foo_multi(cx: &mut ExtCtxt,
- _sp: Span,
- _attr: &MetaItem,
- it: Annotatable) -> Annotatable {
- match it {
- Annotatable::Item(it) => {
- Annotatable::Item(P(Item {
- attrs: it.attrs.clone(),
- ..(*quote_item!(cx, enum Foo2 { Bar2, Baz2 }).unwrap()).clone()
- }))
- }
- Annotatable::ImplItem(_) => {
- quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
- match i.node {
- ItemKind::Impl(.., mut items) => {
- Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
- }
- _ => unreachable!("impl parsed to something other than impl")
- }
- })
- }
- Annotatable::TraitItem(_) => {
- quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
- match i.node {
- ItemKind::Trait(.., mut items) => {
- Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
- }
- _ => unreachable!("trait parsed to something other than trait")
- }
- })
- }
- // covered in proc_macro/macros-in-extern.rs
- Annotatable::ForeignItem(_) => unimplemented!(),
- // covered in proc_macro/attr-stmt-expr.rs
- Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
- }
-}
-
-fn expand_noop_attribute(_cx: &mut ExtCtxt,
- _sp: Span,
- _attr: &MetaItem,
- it: Annotatable) -> Annotatable {
- it
-}
-
-// Create a duplicate of the annotatable, based on the MetaItem
-fn expand_duplicate(cx: &mut ExtCtxt,
- _sp: Span,
- mi: &MetaItem,
- it: &Annotatable,
- push: &mut FnMut(Annotatable))
-{
- let copy_name = match mi.node {
- ast::MetaItemKind::List(ref xs) => {
- if let Some(word) = xs[0].word() {
- word.ident.segments.last().unwrap().ident
- } else {
- cx.span_err(mi.span, "Expected word");
- return;
- }
- }
- _ => {
- cx.span_err(mi.span, "Expected list");
- return;
- }
- };
-
- // Duplicate the item but replace its ident by the MetaItem
- match it.clone() {
- Annotatable::Item(it) => {
- let mut new_it = (*it).clone();
- new_it.attrs.clear();
- new_it.ident = copy_name;
- push(Annotatable::Item(P(new_it)));
- }
- Annotatable::ImplItem(it) => {
- let mut new_it = (*it).clone();
- new_it.attrs.clear();
- new_it.ident = copy_name;
- push(Annotatable::ImplItem(P(new_it)));
- }
- Annotatable::TraitItem(tt) => {
- let mut new_it = (*tt).clone();
- new_it.attrs.clear();
- new_it.ident = copy_name;
- push(Annotatable::TraitItem(P(new_it)));
- }
- // covered in proc_macro/macros-in-extern.rs
- Annotatable::ForeignItem(_) => unimplemented!(),
- // covered in proc_macro/attr-stmt-expr.rs
- Annotatable::Stmt(_) | Annotatable::Expr(_) => panic!("expected item")
- }
-}
-
-pub fn foo() {}
-// aux-build:macro_crate_test.rs
+// aux-build:attr_plugin_test.rs
-#![plugin(macro_crate_test)]
+#![plugin(attr_plugin_test)]
//~^ ERROR compiler plugins are experimental and possibly buggy
fn main() {}
error[E0658]: compiler plugins are experimental and possibly buggy (see issue #29597)
--> $DIR/gated-plugin.rs:3:1
|
-LL | #![plugin(macro_crate_test)]
+LL | #![plugin(attr_plugin_test)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(plugin)] to the crate attributes to enable
+++ /dev/null
-// Test that `quote`-related macro are gated by `quote` feature gate.
-
-// (To sanity-check the code, uncomment this.)
-// #![feature(quote)]
-
-// FIXME the error message that is current emitted seems pretty bad.
-
-// gate-test-quote
-
-#![feature(rustc_private)]
-#![allow(dead_code, unused_imports, unused_variables)]
-
-#[macro_use]
-extern crate syntax;
-
-use syntax::ast;
-use syntax::parse;
-
-struct ParseSess;
-
-impl ParseSess {
- fn cfg(&self) -> ast::CrateConfig { loop { } }
- fn parse_sess<'a>(&'a self) -> &'a parse::ParseSess { loop { } }
- fn call_site(&self) -> () { loop { } }
- fn ident_of(&self, st: &str) -> ast::Ident { loop { } }
- fn name_of(&self, st: &str) -> ast::Name { loop { } }
-}
-
-pub fn main() {
- let ecx = &ParseSess;
- let x = quote_tokens!(ecx, 3);
- //~^ ERROR cannot find macro `quote_tokens!` in this scope
- let x = quote_expr!(ecx, 3);
- //~^ ERROR cannot find macro `quote_expr!` in this scope
- let x = quote_ty!(ecx, 3);
- //~^ ERROR cannot find macro `quote_ty!` in this scope
- let x = quote_method!(ecx, 3);
- //~^ ERROR cannot find macro `quote_method!` in this scope
- let x = quote_item!(ecx, 3);
- //~^ ERROR cannot find macro `quote_item!` in this scope
- let x = quote_pat!(ecx, 3);
- //~^ ERROR cannot find macro `quote_pat!` in this scope
- let x = quote_arm!(ecx, 3);
- //~^ ERROR cannot find macro `quote_arm!` in this scope
- let x = quote_stmt!(ecx, 3);
- //~^ ERROR cannot find macro `quote_stmt!` in this scope
- let x = quote_attr!(ecx, 3);
- //~^ ERROR cannot find macro `quote_attr!` in this scope
- let x = quote_arg!(ecx, 3);
- //~^ ERROR cannot find macro `quote_arg!` in this scope
- let x = quote_block!(ecx, 3);
- //~^ ERROR cannot find macro `quote_block!` in this scope
- let x = quote_meta_item!(ecx, 3);
- //~^ ERROR cannot find macro `quote_meta_item!` in this scope
- let x = quote_path!(ecx, 3);
- //~^ ERROR cannot find macro `quote_path!` in this scope
-}
+++ /dev/null
-error: cannot find macro `quote_path!` in this scope
- --> $DIR/gated-quote.rs:55:13
- |
-LL | let x = quote_path!(ecx, 3);
- | ^^^^^^^^^^
-
-error: cannot find macro `quote_meta_item!` in this scope
- --> $DIR/gated-quote.rs:53:13
- |
-LL | let x = quote_meta_item!(ecx, 3);
- | ^^^^^^^^^^^^^^^
-
-error: cannot find macro `quote_block!` in this scope
- --> $DIR/gated-quote.rs:51:13
- |
-LL | let x = quote_block!(ecx, 3);
- | ^^^^^^^^^^^
-
-error: cannot find macro `quote_arg!` in this scope
- --> $DIR/gated-quote.rs:49:13
- |
-LL | let x = quote_arg!(ecx, 3);
- | ^^^^^^^^^
-
-error: cannot find macro `quote_attr!` in this scope
- --> $DIR/gated-quote.rs:47:13
- |
-LL | let x = quote_attr!(ecx, 3);
- | ^^^^^^^^^^
-
-error: cannot find macro `quote_stmt!` in this scope
- --> $DIR/gated-quote.rs:45:13
- |
-LL | let x = quote_stmt!(ecx, 3);
- | ^^^^^^^^^^
-
-error: cannot find macro `quote_arm!` in this scope
- --> $DIR/gated-quote.rs:43:13
- |
-LL | let x = quote_arm!(ecx, 3);
- | ^^^^^^^^^
-
-error: cannot find macro `quote_pat!` in this scope
- --> $DIR/gated-quote.rs:41:13
- |
-LL | let x = quote_pat!(ecx, 3);
- | ^^^^^^^^^
-
-error: cannot find macro `quote_item!` in this scope
- --> $DIR/gated-quote.rs:39:13
- |
-LL | let x = quote_item!(ecx, 3);
- | ^^^^^^^^^^
-
-error: cannot find macro `quote_method!` in this scope
- --> $DIR/gated-quote.rs:37:13
- |
-LL | let x = quote_method!(ecx, 3);
- | ^^^^^^^^^^^^
-
-error: cannot find macro `quote_ty!` in this scope
- --> $DIR/gated-quote.rs:35:13
- |
-LL | let x = quote_ty!(ecx, 3);
- | ^^^^^^^^
-
-error: cannot find macro `quote_expr!` in this scope
- --> $DIR/gated-quote.rs:33:13
- |
-LL | let x = quote_expr!(ecx, 3);
- | ^^^^^^^^^^
-
-error: cannot find macro `quote_tokens!` in this scope
- --> $DIR/gated-quote.rs:31:13
- |
-LL | let x = quote_tokens!(ecx, 3);
- | ^^^^^^^^^^^^
-
-error: aborting due to 13 previous errors
-
+++ /dev/null
-// This is a regression test against an ICE that used to occur
-// on malformed attributes for a custom MultiModifier.
-
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-
-#![feature(plugin)]
-#![plugin(macro_crate_test)]
-
-#[noop_attribute("hi", rank = a)] //~ ERROR expected unsuffixed literal or identifier, found a
-fn knight() { }
-
-#[noop_attribute("/user", data= = "<user")] //~ ERROR literal or identifier
-fn nite() { }
-
-fn main() {}
+++ /dev/null
-error: expected unsuffixed literal or identifier, found a
- --> $DIR/issue-48941.rs:10:24
- |
-LL | #[noop_attribute("hi", rank = a)] //~ ERROR expected unsuffixed literal or identifier, found a
- | ^^^^
-
-error: expected unsuffixed literal or identifier, found =
- --> $DIR/issue-48941.rs:13:27
- |
-LL | #[noop_attribute("/user", data= = "<user")] //~ ERROR literal or identifier
- | ^^^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// aux-build:macro_crate_test.rs
-
-#[macro_use] #[no_link]
-extern crate macro_crate_test;
-
-fn main() {
- macro_crate_test::foo(); //~ ERROR cannot find function `foo` in module `macro_crate_test`
-}
+++ /dev/null
-error[E0425]: cannot find function `foo` in module `macro_crate_test`
- --> $DIR/macro-crate-doesnt-resolve.rs:7:23
- |
-LL | macro_crate_test::foo(); //~ ERROR cannot find function `foo` in module `macro_crate_test`
- | ^^^ not found in `macro_crate_test`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
+++ /dev/null
-// aux-build:macro_crate_test.rs
-
-#[macro_use] #[no_link]
-extern crate macro_crate_test;
-
-fn main() {
- unexported_macro!();
- //~^ ERROR cannot find macro `unexported_macro!` in this scope
-}
+++ /dev/null
-error: cannot find macro `unexported_macro!` in this scope
- --> $DIR/macro-crate-unexported-macro.rs:7:5
- |
-LL | unexported_macro!();
- | ^^^^^^^^^^^^^^^^ help: you could try the macro: `exported_macro`
-
-error: aborting due to previous error
-
-// aux-build:macro_crate_test.rs
+// aux-build:attr_plugin_test.rs
// ignore-cross-compile
//
-// macro_crate_test will not compile on a cross-compiled target because
+// attr_plugin_test will not compile on a cross-compiled target because
// libsyntax is not compiled for it.
#![deny(plugin_as_library)]
#![allow(unused_extern_crates)]
-extern crate macro_crate_test; //~ ERROR compiler plugin used as an ordinary library
+extern crate attr_plugin_test; //~ ERROR compiler plugin used as an ordinary library
fn main() { }
error: compiler plugin used as an ordinary library
--> $DIR/plugin-as-extern-crate.rs:10:1
|
-LL | extern crate macro_crate_test; //~ ERROR compiler plugin used as an ordinary library
+LL | extern crate attr_plugin_test; //~ ERROR compiler plugin used as an ordinary library
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: lint level defined here
+++ /dev/null
-// aux-build:macro_crate_test.rs
-// ignore-stage1
-// ignore-cross-compile
-//
-// macro_crate_test will not compile on a cross-compiled target because
-// libsyntax is not compiled for it.
-
-#![deny(plugin_as_library)]
-#![feature(plugin)]
-#![plugin(macro_crate_test)]
-
-extern crate macro_crate_test; //~ ERROR compiler plugin used as an ordinary library
-
-fn main() {
- assert_eq!(1, make_a_1!());
- macro_crate_test::foo();
-}
+++ /dev/null
-error: compiler plugin used as an ordinary library
- --> $DIR/plugin-plus-extern-crate.rs:12:1
- |
-LL | extern crate macro_crate_test; //~ ERROR compiler plugin used as an ordinary library
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: lint level defined here
- --> $DIR/plugin-plus-extern-crate.rs:8:9
- |
-LL | #![deny(plugin_as_library)]
- | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// ignore-cross-compile
-
-#![feature(quote, rustc_private)]
-
-extern crate syntax;
-extern crate syntax_pos;
-
-use syntax::ast;
-use syntax::source_map::FilePathMapping;
-use syntax::print::pprust;
-use syntax::symbol::Symbol;
-use syntax_pos::DUMMY_SP;
-
-fn main() {
- let ps = syntax::parse::ParseSess::new(FilePathMapping::empty());
- let mut resolver = syntax::ext::base::DummyResolver;
- let mut cx = syntax::ext::base::ExtCtxt::new(
- &ps,
- syntax::ext::expand::ExpansionConfig::default("qquote".to_string()),
- &mut resolver);
- let cx = &mut cx;
-
- assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
-
- let expr = quote_expr!(&cx, 2 - $abcd + 7); //~ ERROR cannot find value `abcd` in this scope
- assert_eq!(pprust::expr_to_string(&*expr), "2 - $abcd + 7");
-}
+++ /dev/null
-error[E0425]: cannot find value `abcd` in this scope
- --> $DIR/qquote.rs:25:38
- |
-LL | let expr = quote_expr!(&cx, 2 - $abcd + 7); //~ ERROR cannot find value `abcd` in this scope
- | ^^^^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
--> $DIR/auto-ref-slice-plus-ref.rs:7:7
|
LL | a.test_mut(); //~ ERROR no method named `test_mut` found
- | ^^^^^^^^
+ | ^^^^^^^^ help: did you mean: `get_mut`
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `test_mut`, perhaps you need to implement it:
candidate #1: `MyIter`
- = help: did you mean `get_mut`?
error[E0599]: no method named `test` found for type `std::vec::Vec<{integer}>` in the current scope
--> $DIR/auto-ref-slice-plus-ref.rs:8:7
--- /dev/null
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:7:10
+ |
+LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs + rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:8:10
+ |
+LL | fn add<A: Add<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs + rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:13:10
+ |
+LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs - rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:14:10
+ |
+LL | fn sub<A: Sub<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs - rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:19:10
+ |
+LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs * rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:20:10
+ |
+LL | fn mul<A: Mul<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs * rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:25:10
+ |
+LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs / rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:26:10
+ |
+LL | fn div<A: Div<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs / rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:31:10
+ |
+LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs % rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:32:10
+ |
+LL | fn rem<A: Rem<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs % rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:37:10
+ |
+LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs & rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:38:10
+ |
+LL | fn bitand<A: BitAnd<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs & rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:43:10
+ |
+LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs | rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:44:10
+ |
+LL | fn bitor<A: BitOr<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs | rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:49:10
+ |
+LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs ^ rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:50:10
+ |
+LL | fn bitxor<A: BitXor<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs ^ rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:55:10
+ |
+LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs << rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:56:10
+ |
+LL | fn shl<A: Shl<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs << rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `lhs`
+ --> $DIR/binop-consume-args.rs:61:10
+ |
+LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `lhs` has type `A`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs >> rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+ | ^^^ value used here after move
+
+error[E0382]: use of moved value: `rhs`
+ --> $DIR/binop-consume-args.rs:62:10
+ |
+LL | fn shr<A: Shr<B, Output=()>, B>(lhs: A, rhs: B) {
+ | - --- move occurs because `rhs` has type `B`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | lhs >> rhs;
+ | --- value moved here
+LL | drop(lhs); //~ ERROR use of moved value: `lhs`
+LL | drop(rhs); //~ ERROR use of moved value: `rhs`
+ | ^^^ value used here after move
+
+error: aborting due to 20 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
error[E0382]: use of moved value: `x`
--> $DIR/binop-move-semantics.rs:8:5
|
+LL | fn double_move<T: Add<Output=()>>(x: T) {
+ | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
LL | x
| - value moved here
LL | +
LL | x; //~ ERROR: use of moved value
| ^ value used here after move
- |
- = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/binop-move-semantics.rs:14:5
|
+LL | fn move_then_borrow<T: Add<Output=()> + Clone>(x: T) {
+ | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
LL | x
| - value moved here
LL | +
LL | x.clone(); //~ ERROR: use of moved value
| ^ value borrowed here after move
- |
- = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/binop-move-semantics.rs:21:5
--> $DIR/issue-3563.rs:3:17
|
LL | || self.b()
- | ^
- |
- = help: did you mean `a`?
+ | ^ help: did you mean: `a`
error: aborting due to previous error
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-asm.rs:27:17
|
+LL | let x = &mut 0isize;
+ | - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
+LL | unsafe {
LL | asm!("nop" : : "r"(x));
| - value moved here
LL | }
LL | let z = x; //[ast]~ ERROR use of moved value: `x`
| ^ value used here after move
- |
- = note: move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
error[E0503]: cannot use `x` because it was mutably borrowed
--> $DIR/borrowck-asm.rs:35:32
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-asm.rs:86:40
|
+LL | let x = &mut 2;
+ | - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
+LL | unsafe {
LL | asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value
| - ^ value used here after move
| |
| value moved here
- |
- = note: move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
error: aborting due to 7 previous errors
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-asm.rs:27:17
|
+LL | let x = &mut 0isize;
+ | - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
+LL | unsafe {
LL | asm!("nop" : : "r"(x));
| - value moved here
LL | }
LL | let z = x; //[ast]~ ERROR use of moved value: `x`
| ^ value used here after move
- |
- = note: move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
error[E0503]: cannot use `x` because it was mutably borrowed
--> $DIR/borrowck-asm.rs:35:32
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-asm.rs:86:40
|
+LL | let x = &mut 2;
+ | - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
+LL | unsafe {
LL | asm!("nop" : : "r"(x), "r"(x) ); //[ast]~ ERROR use of moved value
| - ^ value used here after move
| |
| value moved here
- |
- = note: move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
error: aborting due to 7 previous errors
--- /dev/null
+error[E0382]: use of moved value: `b`
+ --> $DIR/borrowck-consume-unsize-vec.rs:8:13
+ |
+LL | fn foo(b: Box<[i32;5]>) {
+ | - move occurs because `b` has type `std::boxed::Box<[i32; 5]>`, which does not implement the `Copy` trait
+LL | consume(b);
+ | - value moved here
+LL | consume(b); //~ ERROR use of moved value
+ | ^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
error[E0382]: use of moved value: `b`
--> $DIR/borrowck-consume-upcast-box.rs:10:13
|
+LL | fn foo(b: Box<Foo+Send>) {
+ | - move occurs because `b` has type `std::boxed::Box<dyn Foo + std::marker::Send>`, which does not implement the `Copy` trait
LL | consume(b);
| - value moved here
LL | consume(b); //~ ERROR use of moved value
| ^ value used here after move
- |
- = note: move occurs because `b` has type `std::boxed::Box<dyn Foo + std::marker::Send>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `my_str`
--> $DIR/borrowck-drop-from-guard.rs:11:23
|
+LL | let my_str = "hello".to_owned();
+ | ------ move occurs because `my_str` has type `std::string::String`, which does not implement the `Copy` trait
+LL | match Some(42) {
LL | Some(_) if { drop(my_str); false } => {}
| ------ value moved here
LL | Some(_) => {}
LL | None => { foo(my_str); } //~ ERROR [E0382]
| ^^^^^^ value used here after move
- |
- = note: move occurs because `my_str` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `src`
--> $DIR/borrowck-issue-48962.rs:16:5
|
+LL | let mut src = &mut node;
+ | ------- move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait
LL | {src};
| --- value moved here
LL | src.next = None; //~ ERROR use of moved value: `src` [E0382]
| ^^^^^^^^ value used here after move
- |
- = note: move occurs because `src` has type `&mut Node`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `src`
--> $DIR/borrowck-issue-48962.rs:22:5
|
+LL | let mut src = &mut (22, 44);
+ | ------- move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait
LL | {src};
| --- value moved here
LL | src.0 = 66; //~ ERROR use of moved value: `src` [E0382]
| ^^^^^^^^^^ value used here after move
- |
- = note: move occurs because `src` has type `&mut (i32, i32)`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors
error[E0382]: borrow of moved value: `x`
--> $DIR/borrowck-loan-in-overloaded-op.rs:21:20
|
+LL | let x = Foo(box 3);
+ | - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
LL | let _y = {x} + x.clone(); // the `{x}` forces a move to occur
| - ^ value borrowed here after move
| |
| value moved here
- |
- = note: move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `t`
--> $DIR/borrowck-move-moved-value-into-closure.rs:14:12
|
+LL | let t: Box<_> = box 3;
+ | - move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+LL |
LL | call_f(move|| { *t + 1 });
| ------ - variable moved due to use in closure
| |
| ^^^^^^ - use occurs due to use in closure
| |
| value used here after move
- |
- = note: move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `t`
--> $DIR/borrowck-move-moved-value-into-closure.rs:14:12
|
+LL | let t: Box<_> = box 3;
+ | - move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+LL |
LL | call_f(move|| { *t + 1 });
| ------ - variable moved due to use in closure
| |
| ^^^^^^ - use occurs due to use in closure
| |
| value used here after move
- |
- = note: move occurs because `t` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `x1`
--> $DIR/borrowck-multiple-captures.rs:25:19
|
+LL | let x1: Box<_> = box 1;
+ | -- move occurs because `x1` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
LL | drop(x1);
| -- value moved here
...
| ^^^^^^ value used here after move
LL | drop(x1); //~ ERROR capture of moved value: `x1`
| -- use occurs due to use in closure
- |
- = note: move occurs because `x1` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x2`
--> $DIR/borrowck-multiple-captures.rs:25:19
|
+LL | let x2: Box<_> = box 2;
+ | -- move occurs because `x2` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
LL | drop(x2);
| -- value moved here
LL | thread::spawn(move|| {
LL | drop(x1); //~ ERROR capture of moved value: `x1`
LL | drop(x2); //~ ERROR capture of moved value: `x2`
| -- use occurs due to use in closure
- |
- = note: move occurs because `x2` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-multiple-captures.rs:36:14
error[E0382]: use of moved value: `x`
--> $DIR/borrowck-multiple-captures.rs:44:19
|
+LL | let x: Box<_> = box 1;
+ | - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
LL | drop(x);
| - value moved here
LL | thread::spawn(move|| {
| ^^^^^^ value used here after move
LL | drop(x); //~ ERROR capture of moved value: `x`
| - use occurs due to use in closure
- |
- = note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
error: aborting due to 8 previous errors
error[E0382]: use of moved value: `s`
--> $DIR/borrowck-overloaded-call.rs:75:5
|
+LL | let s = SFnOnce {
+ | - move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait
+...
LL | s(" world".to_string());
| - value moved here
LL | s(" world".to_string()); //~ ERROR use of moved value: `s`
| ^ value used here after move
- |
- = note: move occurs because `s` has type `SFnOnce`, which does not implement the `Copy` trait
error: aborting due to 3 previous errors
error[E0382]: use of moved value: `s`
--> $DIR/borrowck-overloaded-index-move-index.rs:53:7
|
+LL | let mut s = "hello".to_string();
+ | ----- move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+...
LL | println!("{}", f[s]);
| - value moved here
...
LL | f[s] = 10;
| ^ value used here after move
- |
- = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to 3 previous errors
error[E0382]: assign of moved value: `t`
--> $DIR/borrowck-partial-reinit-1.rs:27:5
|
+LL | let mut t = Test2 { b: None };
+ | ----- move occurs because `t` has type `Test2`, which does not implement the `Copy` trait
+LL | let u = Test;
LL | drop(t);
| - value moved here
LL | t.b = Some(u);
| ^^^ value assigned here after move
- |
- = note: move occurs because `t` has type `Test2`, which does not implement the `Copy` trait
error[E0382]: assign of moved value: `t`
--> $DIR/borrowck-partial-reinit-1.rs:33:5
|
+LL | let mut t = Test3(None);
+ | ----- move occurs because `t` has type `Test3`, which does not implement the `Copy` trait
+LL | let u = Test;
LL | drop(t);
| - value moved here
LL | t.0 = Some(u);
| ^^^ value assigned here after move
- |
- = note: move occurs because `t` has type `Test3`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors
error[E0382]: assign of moved value: `t`
--> $DIR/borrowck-partial-reinit-2.rs:15:5
|
+LL | let mut t = Test { a: 1, b: None};
+ | ----- move occurs because `t` has type `Test`, which does not implement the `Copy` trait
LL | let mut u = Test { a: 2, b: Some(Box::new(t))};
| - value moved here
LL | t.b = Some(Box::new(u));
| ^^^ value assigned here after move
- |
- = note: move occurs because `t` has type `Test`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `x` (Mir)
--> $DIR/borrowck-reinit.rs:8:16
|
+LL | let mut x = Box::new(0);
+ | ----- move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+...
LL | drop(x);
| - value moved here
LL | let _ = (1,x); //~ ERROR use of moved value: `x` (Ast)
| ^ value used here after move
- |
- = note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors
error[E0382]: use of moved value: `f`
--> $DIR/borrowck-unboxed-closures.rs:12:5
|
+LL | fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
+ | - - move occurs because `f` has type `F`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
LL | f(1, 2);
| - value moved here
LL | f(1, 2); //~ ERROR use of moved value
| ^ value used here after move
- |
- = note: move occurs because `f` has type `F`, which does not implement the `Copy` trait
error: aborting due to 3 previous errors
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move-assign.rs:17:21
|
+LL | let mut u = U { a: A };
+ | ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait
LL | let a = u.a;
| --- value moved here
LL | let a = u.a; //~ ERROR use of moved value: `u.a`
| ^^^ value used here after move
- |
- = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:26:21
|
+LL | let mut u = Unn { n1: NonCopy };
+ | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
LL | let a = u.n1;
| ---- value moved here
LL | let a = u.n1; //~ ERROR use of moved value: `u.n1`
| ^^^^ value used here after move
- |
- = note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:31:21
|
+LL | let mut u = Unn { n1: NonCopy };
+ | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
LL | let a = u.n1;
| ---- value moved here
LL | let a = u; //~ ERROR use of partially moved value: `u`
| ^ value used here after move
- |
- = note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:36:21
|
+LL | let mut u = Unn { n1: NonCopy };
+ | ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
LL | let a = u.n1;
| ---- value moved here
LL | let a = u.n2; //~ ERROR use of moved value: `u.n2`
| ^^^^ value used here after move
- |
- = note: move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:63:21
|
+LL | let mut u = Ucn { c: Copy };
+ | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
LL | let a = u.n;
| --- value moved here
LL | let a = u.n; //~ ERROR use of moved value: `u.n`
| ^^^ value used here after move
- |
- = note: move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:68:21
|
+LL | let mut u = Ucn { c: Copy };
+ | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
LL | let a = u.n;
| --- value moved here
LL | let a = u.c; //~ ERROR use of moved value: `u.c`
| ^^^ value used here after move
- |
- = note: move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `u`
--> $DIR/borrowck-union-move.rs:83:21
|
+LL | let mut u = Ucn { c: Copy };
+ | ----- move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
LL | let a = u.n;
| --- value moved here
LL | let a = u; //~ ERROR use of partially moved value: `u`
| ^ value used here after move
- |
- = note: move occurs because `u` has type `Ucn`, which does not implement the `Copy` trait
error: aborting due to 6 previous errors
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:23:9
|
+LL | let mut t: Tuple = (S(0), 0);
+ | ----- move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
LL | drop(t);
| - value moved here
LL | t.0 = S(1);
| ^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
error[E0382]: assign to part of moved value: `u`
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:34:9
|
+LL | let mut u: Tpair = Tpair(S(0), 0);
+ | ----- move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
LL | drop(u);
| - value moved here
LL | u.0 = S(1);
| ^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
error[E0382]: assign to part of moved value: `v`
--> $DIR/issue-54499-field-mutation-of-moved-out-with-mut.rs:45:9
|
+LL | let mut v: Spair = Spair { x: S(0), y: 0 };
+ | ----- move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
LL | drop(v);
| - value moved here
LL | v.x = S(1);
| ^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
error: aborting due to 3 previous errors
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:23:9
|
+LL | let t: Tuple = (S(0), 0);
+ | - move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
LL | drop(t);
| - value moved here
LL | t.0 = S(1);
| ^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `t` has type `(S, i32)`, which does not implement the `Copy` trait
error[E0594]: cannot assign to `t.1`, as `t` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:27:9
error[E0382]: assign to part of moved value: `u`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:38:9
|
+LL | let u: Tpair = Tpair(S(0), 0);
+ | - move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
LL | drop(u);
| - value moved here
LL | u.0 = S(1);
| ^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `u` has type `Tpair`, which does not implement the `Copy` trait
error[E0594]: cannot assign to `u.1`, as `u` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:42:9
error[E0382]: assign to part of moved value: `v`
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:53:9
|
+LL | let v: Spair = Spair { x: S(0), y: 0 };
+ | - move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
LL | drop(v);
| - value moved here
LL | v.x = S(1);
| ^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `v` has type `Spair`, which does not implement the `Copy` trait
error[E0594]: cannot assign to `v.y`, as `v` is not declared as mutable
--> $DIR/issue-54499-field-mutation-of-moved-out.rs:57:9
error[E0382]: use of moved value: `*f`
--> $DIR/two-phase-nonrecv-autoref.rs:69:11
|
+LL | fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
+ | - consider adding a `Copy` constraint to this type argument
LL | f(f(10));
| - ^ value used here after move
| |
error[E0382]: use of moved value: `*f`
--> $DIR/two-phase-nonrecv-autoref.rs:69:11
|
+LL | fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
+ | - consider adding a `Copy` constraint to this type argument
LL | f(f(10));
| - ^ value used here after move
| |
// gate-test-const_raw_ptr_to_usize_cast
fn main() {
- const X: u32 = main as u32; //~ ERROR casting pointers to integers in constants is unstable
+ const X: u32 = unsafe {
+ main as u32 //~ ERROR casting pointers to integers in constants is unstable
+ };
const Y: u32 = 0;
- const Z: u32 = &Y as *const u32 as u32; //~ ERROR is unstable
+ const Z: u32 = unsafe {
+ &Y as *const u32 as u32 //~ ERROR is unstable
+ };
}
error[E0658]: casting pointers to integers in constants is unstable (see issue #51910)
- --> $DIR/cast-ptr-to-int-const.rs:4:20
+ --> $DIR/cast-ptr-to-int-const.rs:5:9
|
-LL | const X: u32 = main as u32; //~ ERROR casting pointers to integers in constants is unstable
- | ^^^^^^^^^^^
+LL | main as u32 //~ ERROR casting pointers to integers in constants is unstable
+ | ^^^^^^^^^^^
|
= help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable
error[E0658]: casting pointers to integers in constants is unstable (see issue #51910)
- --> $DIR/cast-ptr-to-int-const.rs:6:20
+ --> $DIR/cast-ptr-to-int-const.rs:9:9
|
-LL | const Z: u32 = &Y as *const u32 as u32; //~ ERROR is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^
+LL | &Y as *const u32 as u32 //~ ERROR is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable
error[E0382]: borrow of moved value: `some_vec`
--> $DIR/tab_3.rs:7:20
|
+LL | let some_vec = vec!["hi"];
+ | -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait
LL | some_vec.into_iter();
| -------- value moved here
LL | {
LL | println!("{:?}", some_vec); //~ ERROR use of moved
| ^^^^^^^^ value borrowed here after move
- |
- = note: move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait
error: aborting due to previous error
fn main() {}
// unconst and bad, will thus error in miri
-const X: bool = &1 as *const i32 == &2 as *const i32; //~ ERROR any use of this value will cause
+const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
// unconst and fine
-const X2: bool = 42 as *const i32 == 43 as *const i32;
+const X2: bool = unsafe { 42 as *const i32 == 43 as *const i32 };
// unconst and fine
-const Y: usize = 42usize as *const i32 as usize + 1;
+const Y: usize = unsafe { 42usize as *const i32 as usize + 1 };
// unconst and bad, will thus error in miri
-const Y2: usize = &1 as *const i32 as usize + 1; //~ ERROR any use of this value will cause
+const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
// unconst and fine
const Z: i32 = unsafe { *(&1 as *const i32) };
// unconst and bad, will thus error in miri
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:6:1
|
-LL | const X: bool = &1 as *const i32 == &2 as *const i32; //~ ERROR any use of this value will cause
- | ^^^^^^^^^^^^^^^^------------------------------------^
- | |
- | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+LL | const X: bool = unsafe { &1 as *const i32 == &2 as *const i32 }; //~ ERROR any use of this
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^------------------------------------^^^
+ | |
+ | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
|
= note: #[deny(const_err)] on by default
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:12:1
|
-LL | const Y2: usize = &1 as *const i32 as usize + 1; //~ ERROR any use of this value will cause
- | ^^^^^^^^^^^^^^^^^^-----------------------------^
- | |
- | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
+LL | const Y2: usize = unsafe { &1 as *const i32 as usize + 1 }; //~ ERROR any use of this
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------------------^^^
+ | |
+ | "pointer arithmetic or comparison" needs an rfc before being allowed inside constants
error: any use of this value will cause an error
--> $DIR/const_raw_ptr_ops.rs:16:1
const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
//~^ ERROR it is undefined behavior to use this value
+union Transmute {
+ uninit: (),
+ out: NonZeroU8,
+}
+const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out };
+//~^ ERROR it is undefined behavior to use this value
+
// Also test other uses of rustc_layout_scalar_valid_range_start
#[rustc_layout_scalar_valid_range_start(10)]
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:21:1
+ --> $DIR/ub-nonnull.rs:20:1
+ |
+LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/ub-nonnull.rs:28:1
|
LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
error[E0080]: it is undefined behavior to use this value
- --> $DIR/ub-nonnull.rs:27:1
+ --> $DIR/ub-nonnull.rs:34:1
|
LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0080`.
|
LL | intrinsics::size_of::<T>()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires computing layout of `Foo`...
-note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
+ = note: ...which requires computing layout of `Foo`...
+ = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`...
--> $DIR/const-size_of-cycle.rs:6:17
|
--- /dev/null
+// https://github.com/rust-lang/rust/issues/53708
+
+struct S;
+
+fn main() {
+ const C: &S = &S;
+ match C { //~ ERROR non-exhaustive
+ C => {} // this is a common bug around constants and references in patterns
+ }
+}
--- /dev/null
+error[E0004]: non-exhaustive patterns: `&S` not covered
+ --> $DIR/match_ice.rs:7:11
+ |
+LL | match C { //~ ERROR non-exhaustive
+ | ^ pattern `&S` not covered
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0004`.
const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable
- x == y
+ unsafe { x == y }
}
fn main() {}
| ^^^^^^^^^^
error: casting pointers to ints is unstable in const fn
- --> $DIR/min_const_fn.rs:94:42
+ --> $DIR/min_const_fn.rs:94:63
+ |
+LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
+ | ^^^^^^^^^^
+
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:96:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:98:63
+ |
+LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
+ | ^^^^^^^^^^
+
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:96:38
+ --> $DIR/min_const_fn.rs:100:38
|
LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
| ^^^^^^^^^^^^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:98:29
+ --> $DIR/min_const_fn.rs:102:29
|
LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
| ^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:100:44
+ --> $DIR/min_const_fn.rs:104:44
|
LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
| ^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:102:44
+ --> $DIR/min_const_fn.rs:106:44
|
LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
| ^^^^^^
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:104:14
+ --> $DIR/min_const_fn.rs:108:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:109:6
+ --> $DIR/min_const_fn.rs:113:6
|
LL | impl<T: std::fmt::Debug> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:114:6
+ --> $DIR/min_const_fn.rs:118:6
|
LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:119:6
+ --> $DIR/min_const_fn.rs:123:6
|
LL | impl<T: Sync + Sized> Foo<T> {
| ^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:125:24
+ --> $DIR/min_const_fn.rs:129:24
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:127:34
+ --> $DIR/min_const_fn.rs:131:34
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:129:22
+ --> $DIR/min_const_fn.rs:133:22
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^^^^^^^^^^^^^^^^^^^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:130:23
+ --> $DIR/min_const_fn.rs:134:23
|
LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:131:23
+ --> $DIR/min_const_fn.rs:135:23
|
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:132:32
+ --> $DIR/min_const_fn.rs:136:32
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning[E0515]: cannot return reference to temporary value
- --> $DIR/min_const_fn.rs:132:63
+ --> $DIR/min_const_fn.rs:136:63
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^--
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:137:41
+ --> $DIR/min_const_fn.rs:141:41
|
LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:140:21
+ --> $DIR/min_const_fn.rs:144:21
|
LL | const fn no_fn_ptrs(_x: fn()) {}
| ^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:142:27
+ --> $DIR/min_const_fn.rs:146:27
|
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^
-error: aborting due to 34 previous errors
+error: aborting due to 36 previous errors
Some errors occurred: E0493, E0515.
For more information about an error, try `rustc --explain E0493`.
const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn
const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items
const fn foo30(x: *const u32) -> usize { x as usize }
-//~^ ERROR casting pointers to int
+//~^ ERROR casting pointers to ints is unstable
+const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
+//~^ ERROR casting pointers to ints is unstable
const fn foo30_2(x: *mut u32) -> usize { x as usize }
-//~^ ERROR casting pointers to int
+//~^ ERROR casting pointers to ints is unstable
+const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
+//~^ ERROR casting pointers to ints is unstable
const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
//~^ ERROR `if`, `match`, `&&` and `||` are not stable in const fn
const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
| ^^^^^^^^^^
error: casting pointers to ints is unstable in const fn
- --> $DIR/min_const_fn.rs:94:42
+ --> $DIR/min_const_fn.rs:94:63
+ |
+LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } }
+ | ^^^^^^^^^^
+
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:96:42
|
LL | const fn foo30_2(x: *mut u32) -> usize { x as usize }
| ^^^^^^^^^^
+error: casting pointers to ints is unstable in const fn
+ --> $DIR/min_const_fn.rs:98:63
+ |
+LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } }
+ | ^^^^^^^^^^
+
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:96:38
+ --> $DIR/min_const_fn.rs:100:38
|
LL | const fn foo30_4(b: bool) -> usize { if b { 1 } else { 42 } }
| ^^^^^^^^^^^^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:98:29
+ --> $DIR/min_const_fn.rs:102:29
|
LL | const fn foo30_5(b: bool) { while b { } } //~ ERROR not stable in const fn
| ^^^^^^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:100:44
+ --> $DIR/min_const_fn.rs:104:44
|
LL | const fn foo36(a: bool, b: bool) -> bool { a && b }
| ^^^^^^
error: `if`, `match`, `&&` and `||` are not stable in const fn
- --> $DIR/min_const_fn.rs:102:44
+ --> $DIR/min_const_fn.rs:106:44
|
LL | const fn foo37(a: bool, b: bool) -> bool { a || b }
| ^^^^^^
error: mutable references in const fn are unstable
- --> $DIR/min_const_fn.rs:104:14
+ --> $DIR/min_const_fn.rs:108:14
|
LL | const fn inc(x: &mut i32) { *x += 1 }
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:109:6
+ --> $DIR/min_const_fn.rs:113:6
|
LL | impl<T: std::fmt::Debug> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:114:6
+ --> $DIR/min_const_fn.rs:118:6
|
LL | impl<T: std::fmt::Debug + Sized> Foo<T> {
| ^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:119:6
+ --> $DIR/min_const_fn.rs:123:6
|
LL | impl<T: Sync + Sized> Foo<T> {
| ^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:125:24
+ --> $DIR/min_const_fn.rs:129:24
|
LL | const fn no_rpit2() -> AlanTuring<impl std::fmt::Debug> { AlanTuring(0) }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:127:34
+ --> $DIR/min_const_fn.rs:131:34
|
LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:129:22
+ --> $DIR/min_const_fn.rs:133:22
|
LL | const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^^^^^^^^^^^^^^^^^^^
error: `impl Trait` in const fn is unstable
- --> $DIR/min_const_fn.rs:130:23
+ --> $DIR/min_const_fn.rs:134:23
|
LL | const fn no_rpit() -> impl std::fmt::Debug {} //~ ERROR `impl Trait` in const fn is unstable
| ^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:131:23
+ --> $DIR/min_const_fn.rs:135:23
|
LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized`
| ^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:132:32
+ --> $DIR/min_const_fn.rs:136:32
|
LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait bounds other than `Sized` on const fn parameters are unstable
- --> $DIR/min_const_fn.rs:137:41
+ --> $DIR/min_const_fn.rs:141:41
|
LL | const fn really_no_traits_i_mean_it() { (&() as &std::fmt::Debug, ()).1 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:140:21
+ --> $DIR/min_const_fn.rs:144:21
|
LL | const fn no_fn_ptrs(_x: fn()) {}
| ^^
error: function pointers in const fn are unstable
- --> $DIR/min_const_fn.rs:142:27
+ --> $DIR/min_const_fn.rs:146:27
|
LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo }
| ^^^^
-error: aborting due to 34 previous errors
+error: aborting due to 36 previous errors
For more information about this error, try `rustc --explain E0493`.
<Bar as Foo<i16>>
<Bar as Foo<i32>>
<Bar as Foo<i8>>
- <Bar as Foo<u8>>
+ <Bar as Foo<u16>>
and 2 others
error: aborting due to previous error
| ^^^^^^^^^^^^^^^ the trait `Foo<i32>` is not implemented for `bool`
|
= help: the following implementations were found:
+ <bool as Foo<bool>>
+ <bool as Foo<i8>>
<bool as Foo<u16>>
<bool as Foo<u32>>
- <bool as Foo<u64>>
- <bool as Foo<u8>>
and 2 others
note: required by `Foo::bar`
--> $DIR/issue-39802-show-5-trait-impls.rs:2:5
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
- where T: std::convert::From<U>;
+ where U: std::convert::Into<T>;
error: aborting due to 3 previous errors
|
LL | let xe3 = XE::Empty3; //~ ERROR no variant named `Empty3` found for type
| ----^^^^^^
- | |
+ | | |
+ | | help: did you mean: `XEmpty3`
| variant not found in `empty_struct::XE`
- |
- = help: did you mean `XEmpty3`?
error[E0599]: no variant named `Empty3` found for type `empty_struct::XE` in the current scope
--> $DIR/empty-struct-braces-expr.rs:23:19
|
LL | let xe3 = XE::Empty3(); //~ ERROR no variant named `Empty3` found for type
| ----^^^^^^
- | |
+ | | |
+ | | help: did you mean: `XEmpty3`
| variant not found in `empty_struct::XE`
- |
- = help: did you mean `XEmpty3`?
error: aborting due to 8 previous errors
-error[E0214]: parenthesized parameters may only be used with a trait
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/E0214.rs:2:15
|
LL | let v: Vec(&str) = vec!["foo"];
- | ^^^^^^ only traits may use parentheses
+ | ^^^^^^
+ | |
+ | only `Fn` traits may use parentheses
+ | help: use angle brackets instead: `<&str>`
error: aborting due to previous error
static FOO: i32 = 42;
static BAR: i32 = 42;
-static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR issue #53020
+static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR issue #53020
fn main() {
}
error[E0658]: comparing raw pointers inside static (see issue #53020)
- --> $DIR/E0395.rs:6:22
+ --> $DIR/E0395.rs:6:29
|
-LL | static BAZ: bool = { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR issue #53020
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | static BAZ: bool = unsafe { (&FOO as *const i32) == (&BAR as *const i32) }; //~ ERROR issue #53020
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_compare_raw_pointers)] to the crate attributes to enable
--- /dev/null
+// Crate that exports an existential type. Used for testing cross-crate.
+
+#![crate_type="rlib"]
+
+#![feature(existential_type)]
+
+pub existential type Foo: std::fmt::Debug;
+
+pub fn foo() -> Foo {
+ 5
+}
+
--- /dev/null
+// Crate that exports an existential type. Used for testing cross-crate.
+
+#![crate_type="rlib"]
+
+#![feature(existential_type)]
+
+pub trait View {
+ type Tmp: Iterator<Item = u32>;
+
+ fn test(&self) -> Self::Tmp;
+}
+
+pub struct X;
+
+impl View for X {
+ existential type Tmp: Iterator<Item = u32>;
+
+ fn test(&self) -> Self::Tmp {
+ vec![1,2,3].into_iter()
+ }
+}
--- /dev/null
+// aux-build:cross_crate_ice.rs
+// compile-pass
+
+extern crate cross_crate_ice;
+
+struct Bar(cross_crate_ice::Foo);
+
+impl Bar {
+ fn zero(&self) -> &cross_crate_ice::Foo {
+ &self.0
+ }
+}
+
+fn main() {
+ let _ = cross_crate_ice::foo();
+}
--- /dev/null
+// aux-build:cross_crate_ice2.rs
+// compile-pass
+
+extern crate cross_crate_ice2;
+
+use cross_crate_ice2::View;
+
+fn main() {
+ let v = cross_crate_ice2::X;
+ v.test();
+}
--- /dev/null
+fn main() {
+ // Assert `Iterator` methods are feature gated
+ assert!([1, 2, 2, 9].iter().is_sorted());
+ //~^ ERROR: use of unstable library feature 'is_sorted': new API
+ assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
+ //~^ ERROR: use of unstable library feature 'is_sorted': new API
+
+ // Assert `[T]` methods are feature gated
+ assert!([1, 2, 2, 9].is_sorted());
+ //~^ ERROR: use of unstable library feature 'is_sorted': new API
+ assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+ //~^ ERROR: use of unstable library feature 'is_sorted': new API
+}
--- /dev/null
+error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
+ --> $DIR/feature-gate-is_sorted.rs:3:33
+ |
+LL | assert!([1, 2, 2, 9].iter().is_sorted());
+ | ^^^^^^^^^
+ |
+ = help: add #![feature(is_sorted)] to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
+ --> $DIR/feature-gate-is_sorted.rs:5:39
+ |
+LL | assert!(![-2i32, -1, 0, 3].iter().is_sorted_by_key(|n| n.abs()));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(is_sorted)] to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
+ --> $DIR/feature-gate-is_sorted.rs:9:26
+ |
+LL | assert!([1, 2, 2, 9].is_sorted());
+ | ^^^^^^^^^
+ |
+ = help: add #![feature(is_sorted)] to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'is_sorted': new API (see issue #53485)
+ --> $DIR/feature-gate-is_sorted.rs:11:32
+ |
+LL | assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(is_sorted)] to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
error[E0308]: mismatched types
--> $DIR/fully-qualified-type-name2.rs:12:12
|
+LL | fn bar(x: x::Foo) -> y::Foo {
+ | ------ expected `y::Foo` because of return type
LL | return x;
| ^ expected enum `y::Foo`, found enum `x::Foo`
|
error[E0308]: mismatched types
--> $DIR/fully-qualified-type-name4.rs:6:12
|
+LL | fn bar(x: usize) -> Option<usize> {
+ | ------------- expected `std::option::Option<usize>` because of return type
LL | return x;
| ^ expected enum `std::option::Option`, found usize
|
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
+ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
note: ...which requires processing `cycle2::{{impl-Trait}}`...
--> $DIR/auto-trait-leak.rs:23:16
|
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
+ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
= note: ...which again requires processing `cycle1::{{impl-Trait}}`, completing the cycle
note: cycle used when checking item types in top-level module
--> $DIR/auto-trait-leak.rs:3:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
+ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
note: ...which requires processing `cycle2::{{impl-Trait}}`...
--> $DIR/auto-trait-leak.rs:23:16
|
error[E0308]: mismatched types
--> $DIR/equality.rs:15:5
|
+LL | fn two(x: bool) -> impl Foo {
+ | -------- expected because this return type...
+LL | if x {
LL | return 1_i32;
- | ----- expected because of this statement
+ | ----- ...is found to be `i32` here
LL | }
LL | 0_u32
| ^^^^^ expected i32, found u32
-error[E0277]: the trait bound `i32: std::slice::SliceIndex<[{integer}]>` is not satisfied
+error[E0277]: the type `[{integer}]` cannot be indexed by `i32`
--> $DIR/index-help.rs:3:5
|
LL | x[0i32]; //~ ERROR E0277
fn main() {
fn bar<T>(_: T) {}
- [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<[{integer}]>` is not satisfied
+ [0][0u8]; //~ ERROR: the type `[{integer}]` cannot be indexed by `u8`
[0][0]; // should infer to be a usize
-error[E0277]: the trait bound `u8: std::slice::SliceIndex<[{integer}]>` is not satisfied
+error[E0277]: the type `[{integer}]` cannot be indexed by `u8`
--> $DIR/indexing-requires-a-uint.rs:6:5
|
-LL | [0][0u8]; //~ ERROR: the trait bound `u8: std::slice::SliceIndex<[{integer}]>` is not satisfied
+LL | [0][0u8]; //~ ERROR: the type `[{integer}]` cannot be indexed by `u8`
| ^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[{integer}]>` is not implemented for `u8`
let s: String = "abcdef".to_string();
v[3_usize];
v[3];
- v[3u8]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
- v[3i8]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
- v[3u32]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
- v[3i32]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
+ v[3u8]; //~ERROR : the type `[isize]` cannot be indexed by `u8`
+ v[3i8]; //~ERROR : the type `[isize]` cannot be indexed by `i8`
+ v[3u32]; //~ERROR : the type `[isize]` cannot be indexed by `u32`
+ v[3i32]; //~ERROR : the type `[isize]` cannot be indexed by `i32`
s.as_bytes()[3_usize];
s.as_bytes()[3];
- s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
- s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
- s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
- s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
+ s.as_bytes()[3u8]; //~ERROR : the type `[u8]` cannot be indexed by `u8`
+ s.as_bytes()[3i8]; //~ERROR : the type `[u8]` cannot be indexed by `i8`
+ s.as_bytes()[3u32]; //~ERROR : the type `[u8]` cannot be indexed by `u32`
+ s.as_bytes()[3i32]; //~ERROR : the type `[u8]` cannot be indexed by `i32`
}
-error[E0277]: the trait bound `u8: std::slice::SliceIndex<[isize]>` is not satisfied
+error[E0277]: the type `[isize]` cannot be indexed by `u8`
--> $DIR/integral-indexing.rs:6:5
|
-LL | v[3u8]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
+LL | v[3u8]; //~ERROR : the type `[isize]` cannot be indexed by `u8`
| ^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u8`
= note: required because of the requirements on the impl of `std::ops::Index<u8>` for `std::vec::Vec<isize>`
-error[E0277]: the trait bound `i8: std::slice::SliceIndex<[isize]>` is not satisfied
+error[E0277]: the type `[isize]` cannot be indexed by `i8`
--> $DIR/integral-indexing.rs:7:5
|
-LL | v[3i8]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
+LL | v[3i8]; //~ERROR : the type `[isize]` cannot be indexed by `i8`
| ^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i8`
= note: required because of the requirements on the impl of `std::ops::Index<i8>` for `std::vec::Vec<isize>`
-error[E0277]: the trait bound `u32: std::slice::SliceIndex<[isize]>` is not satisfied
+error[E0277]: the type `[isize]` cannot be indexed by `u32`
--> $DIR/integral-indexing.rs:8:5
|
-LL | v[3u32]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
+LL | v[3u32]; //~ERROR : the type `[isize]` cannot be indexed by `u32`
| ^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u32`
= note: required because of the requirements on the impl of `std::ops::Index<u32>` for `std::vec::Vec<isize>`
-error[E0277]: the trait bound `i32: std::slice::SliceIndex<[isize]>` is not satisfied
+error[E0277]: the type `[isize]` cannot be indexed by `i32`
--> $DIR/integral-indexing.rs:9:5
|
-LL | v[3i32]; //~ERROR : std::slice::SliceIndex<[isize]>` is not satisfied
+LL | v[3i32]; //~ERROR : the type `[isize]` cannot be indexed by `i32`
| ^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i32`
= note: required because of the requirements on the impl of `std::ops::Index<i32>` for `std::vec::Vec<isize>`
-error[E0277]: the trait bound `u8: std::slice::SliceIndex<[u8]>` is not satisfied
+error[E0277]: the type `[u8]` cannot be indexed by `u8`
--> $DIR/integral-indexing.rs:12:5
|
-LL | s.as_bytes()[3u8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
+LL | s.as_bytes()[3u8]; //~ERROR : the type `[u8]` cannot be indexed by `u8`
| ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u8`
= note: required because of the requirements on the impl of `std::ops::Index<u8>` for `[u8]`
-error[E0277]: the trait bound `i8: std::slice::SliceIndex<[u8]>` is not satisfied
+error[E0277]: the type `[u8]` cannot be indexed by `i8`
--> $DIR/integral-indexing.rs:13:5
|
-LL | s.as_bytes()[3i8]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
+LL | s.as_bytes()[3i8]; //~ERROR : the type `[u8]` cannot be indexed by `i8`
| ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i8`
= note: required because of the requirements on the impl of `std::ops::Index<i8>` for `[u8]`
-error[E0277]: the trait bound `u32: std::slice::SliceIndex<[u8]>` is not satisfied
+error[E0277]: the type `[u8]` cannot be indexed by `u32`
--> $DIR/integral-indexing.rs:14:5
|
-LL | s.as_bytes()[3u32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
+LL | s.as_bytes()[3u32]; //~ERROR : the type `[u8]` cannot be indexed by `u32`
| ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u32`
= note: required because of the requirements on the impl of `std::ops::Index<u32>` for `[u8]`
-error[E0277]: the trait bound `i32: std::slice::SliceIndex<[u8]>` is not satisfied
+error[E0277]: the type `[u8]` cannot be indexed by `i32`
--> $DIR/integral-indexing.rs:15:5
|
-LL | s.as_bytes()[3i32]; //~ERROR : std::slice::SliceIndex<[u8]>` is not satisfied
+LL | s.as_bytes()[3i32]; //~ERROR : the type `[u8]` cannot be indexed by `i32`
| ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize`
|
= help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i32`
--- /dev/null
+pub struct S;
+mod m { pub struct S; }
+pub use crate::m::S as S2;
error[E0382]: use of moved value: `foo`
--> $DIR/issue-17385.rs:19:11
|
+LL | let foo = X(1);
+ | --- move occurs because `foo` has type `X`, which does not implement the `Copy` trait
LL | drop(foo);
| --- value moved here
LL | match foo { //~ ERROR use of moved value
LL | X(1) => (),
| ^ value used here after move
- |
- = note: move occurs because `foo` has type `X`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `e`
--> $DIR/issue-17385.rs:25:11
|
+LL | let e = Enum::Variant2;
+ | - move occurs because `e` has type `Enum`, which does not implement the `Copy` trait
LL | drop(e);
| - value moved here
LL | match e { //~ ERROR use of moved value
| ^ value used here after move
- |
- = note: move occurs because `e` has type `Enum`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors
-static X: usize = 0 as *const usize as usize;
+static X: usize = unsafe { 0 as *const usize as usize };
//~^ ERROR: casting pointers to integers in statics is unstable
fn main() {
error[E0658]: casting pointers to integers in statics is unstable (see issue #51910)
- --> $DIR/issue-17458.rs:1:19
+ --> $DIR/issue-17458.rs:1:28
|
-LL | static X: usize = 0 as *const usize as usize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | static X: usize = unsafe { 0 as *const usize as usize };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable
fn main() {
const X: u32 = 1;
- const Y: usize = &X as *const u32 as usize; //~ ERROR is unstable
+ const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR is unstable
println!("{}", Y);
}
error[E0658]: casting pointers to integers in constants is unstable (see issue #51910)
- --> $DIR/issue-18294.rs:3:22
+ --> $DIR/issue-18294.rs:3:31
|
-LL | const Y: usize = &X as *const u32 as usize; //~ ERROR is unstable
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR is unstable
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_raw_ptr_to_usize_cast)] to the crate attributes to enable
| ----------------- variant `A` not found here
LL | B = SomeEnum::A,
| ----------^
- | |
+ | | |
+ | | help: did you mean: `B`
| variant not found in `SomeEnum`
- |
- = help: did you mean `B`?
error: aborting due to previous error
fn main() {
let v: Vec(&str) = vec!['1', '2'];
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
+ //~| ERROR mismatched types
}
-error[E0214]: parenthesized parameters may only be used with a trait
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-23589.rs:2:15
|
LL | let v: Vec(&str) = vec!['1', '2'];
- | ^^^^^^ only traits may use parentheses
+ | ^^^^^^
+ | |
+ | only `Fn` traits may use parentheses
+ | help: use angle brackets instead: `<&str>`
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/issue-23589.rs:2:29
+ |
+LL | let v: Vec(&str) = vec!['1', '2'];
+ | ^^^ expected &str, found char
+ |
+ = note: expected type `&str`
+ found type `char`
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0214`.
+Some errors occurred: E0214, E0308.
+For more information about an error, try `rustc --explain E0214`.
error[E0382]: use of moved value: `x`
--> $DIR/issue-24357.rs:6:12
|
+LL | let x = NoCopy;
+ | - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait
LL | let f = move || { let y = x; };
| ------- - variable moved due to use in closure
| |
LL | //~^ NOTE value moved (into closure) here
LL | let z = x;
| ^ value used here after move
- |
- = note: move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait
error: aborting due to previous error
--- /dev/null
+error[E0382]: use of moved value: `t`
+ --> $DIR/issue-25700.rs:13:10
+ |
+LL | let t = S::<()>(None);
+ | - move occurs because `t` has type `S<()>`, which does not implement the `Copy` trait
+LL | drop(t);
+ | - value moved here
+LL | drop(t); //~ ERROR use of moved value
+ | ^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
fn id<T>(t: T) -> T { t }
fn main() {
- const A: bool = id::<u8> as *const () < id::<u16> as *const ();
+ const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
//~^ ERROR comparing raw pointers inside constant
println!("{}", A);
}
error[E0658]: comparing raw pointers inside constant (see issue #53020)
- --> $DIR/issue-25826.rs:3:21
+ --> $DIR/issue-25826.rs:3:30
|
-LL | const A: bool = id::<u8> as *const () < id::<u16> as *const ();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const A: bool = unsafe { id::<u8> as *const () < id::<u16> as *const () };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(const_compare_raw_pointers)] to the crate attributes to enable
error[E0391]: cycle detected when computing layout of `std::option::Option<S>`
|
-note: ...which requires computing layout of `S`...
+ = note: ...which requires computing layout of `S`...
= note: ...which again requires computing layout of `std::option::Option<S>`, completing the cycle
note: cycle used when processing `main`
--> $DIR/issue-26548.rs:9:1
error[E0382]: use of moved value: `b`
--> $DIR/issue-27282-move-match-input-into-guard.rs:18:14
|
+LL | let b = &mut true;
+ | - move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
+...
LL | _ if { (|| { let bar = b; *bar = false; })();
| -- - variable moved due to use in closure
| |
LL | false } => { },
LL | &mut true => { println!("You might think we should get here"); },
| ^^^^ value used here after move
- |
- = note: move occurs because `b` has type `&mut bool`, which does not implement the `Copy` trait
error: aborting due to previous error
| --------^^^^^
| |
| function or associated item not found in `dyn std::ops::BitXor<_>`
- |
- = help: did you mean `bitxor`?
+ | help: did you mean: `bitxor`
error[E0191]: the value of the associated type `Output` (from the trait `std::ops::BitXor`) must be specified
--> $DIR/issue-28344.rs:8:13
| --------^^^^^
| |
| function or associated item not found in `dyn std::ops::BitXor<_>`
- |
- = help: did you mean `bitxor`?
+ | help: did you mean: `bitxor`
error: aborting due to 4 previous errors
| -------- variant `Baz` not found here
...
LL | Foo::Baz(..) => (),
- | -----^^^---- variant not found in `Foo`
- |
- = help: did you mean `Bar`?
+ | -----^^^----
+ | | |
+ | | help: did you mean: `Bar`
+ | variant not found in `Foo`
error: aborting due to previous error
error[E0382]: use of moved value: `s`
--> $DIR/issue-29723.rs:12:13
|
+LL | let s = String::new();
+ | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
+LL | let _s = match 0 {
LL | 0 if { drop(s); false } => String::from("oops"),
| - value moved here
...
LL | s
| ^ value used here after move
- |
- = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
fn main() {
{ fn f<X: ::std::marker()::Send>() {} }
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
{ fn f() -> impl ::std::marker()::Send { } }
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
}
struct X;
impl ::std::marker()::Copy for X {}
-//~^ ERROR parenthesized parameters may only be used with a trait
+//~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995-2.rs:4:28
|
LL | { fn f<X: ::std::marker()::Send>() {} }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995-2.rs:8:35
|
LL | { fn f() -> impl ::std::marker()::Send { } }
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995-2.rs:16:19
|
LL | impl ::std::marker()::Copy for X {}
fn main() {
let x: usize() = 1;
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
let b: ::std::boxed()::Box<_> = Box::new(1);
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
let p = ::std::str::()::from_utf8(b"foo").unwrap();
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
let p = ::std::str::from_utf8::()(b"foo").unwrap();
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
let o : Box<::std::marker()::Send> = Box::new(1);
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
let o : Box<Send + ::std::marker()::Sync> = Box::new(1);
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
}
fn foo<X:Default>() {
let d : X() = Default::default();
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
//~| WARN previously accepted
}
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995.rs:4:17
|
LL | let x: usize() = 1;
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995.rs:8:24
|
LL | let b: ::std::boxed()::Box<_> = Box::new(1);
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
- --> $DIR/issue-32995.rs:12:23
+error: parenthesized type parameters may only be used with a `Fn` trait
+ --> $DIR/issue-32995.rs:12:25
|
LL | let p = ::std::str::()::from_utf8(b"foo").unwrap();
- | ^^^^
+ | ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
- --> $DIR/issue-32995.rs:16:34
+error: parenthesized type parameters may only be used with a `Fn` trait
+ --> $DIR/issue-32995.rs:16:36
|
LL | let p = ::std::str::from_utf8::()(b"foo").unwrap();
- | ^^^^
+ | ^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995.rs:20:30
|
LL | let o : Box<::std::marker()::Send> = Box::new(1);
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995.rs:24:37
|
LL | let o : Box<Send + ::std::marker()::Sync> = Box::new(1);
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #42238 <https://github.com/rust-lang/rust/issues/42238>
-error: parenthesized parameters may only be used with a trait
+error: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/issue-32995.rs:30:14
|
LL | let d : X() = Default::default();
--- /dev/null
+#![feature(nll)]
+
+pub trait Foo {
+ fn zero(self) -> Self;
+}
+
+impl Foo for u32 {
+ fn zero(self) -> u32 { 0u32 }
+}
+
+pub mod bar {
+ pub use Foo;
+ pub fn bar<T: Foo>(x: T) -> T {
+ x.zero()
+ }
+}
+
+mod baz {
+ use bar;
+ use Foo;
+ pub fn baz<T: Foo>(x: T) -> T {
+ if 0 == 1 {
+ bar::bar(x.zero())
+ } else {
+ x.zero()
+ };
+ x.zero()
+ //~^ ERROR use of moved value
+ }
+}
+
+fn main() {
+ let _ = baz::baz(0u32);
+}
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/issue-34721.rs:27:9
+ |
+LL | pub fn baz<T: Foo>(x: T) -> T {
+ | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | if 0 == 1 {
+LL | bar::bar(x.zero())
+ | - value moved here
+LL | } else {
+LL | x.zero()
+ | - value moved here
+LL | };
+LL | x.zero()
+ | ^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
error[E0382]: borrow of moved value: `s`
--> $DIR/issue-42796.rs:18:20
|
+LL | let s = "Hello!".to_owned();
+ | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
LL | let mut s_copy = s;
| - value moved here
...
LL | println!("{}", s); //~ ERROR use of moved value
| ^ value borrowed here after move
- |
- = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which requires computing layout of `Foo`...
-note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
+ = note: ...which requires computing layout of `Foo`...
+ = note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}`...
--> $DIR/issue-44415.rs:6:17
|
--> $DIR/result-deref-err.rs:4:28
|
LL | let _result = &Err(41).deref_err();
- | ^^^^^^^^^
+ | ^^^^^^^^^ help: did you mean: `deref_ok`
|
= note: the method `deref_err` exists but the following trait bounds were not satisfied:
`{integer} : std::ops::Deref`
- = help: did you mean `deref_ok`?
error: aborting due to previous error
--- /dev/null
+struct Foo { bar: f64, baz: i64, bat: i64 }
+
+fn main() {
+ let _ = Foo { bar: .5, baz: 42 };
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR missing field `bat` in initializer of `Foo`
+ let bar = 1.5f32;
+ let _ = Foo { bar.into(), bat: -1, . };
+ //~^ ERROR expected one of
+ //~| ERROR missing fields `bar`, `baz` in initializer of `Foo`
+ //~| ERROR expected identifier, found `.`
+}
--- /dev/null
+error: float literals must have an integer part
+ --> $DIR/issue-52496.rs:4:24
+ |
+LL | let _ = Foo { bar: .5, baz: 42 };
+ | ^^ help: must have an integer part: `0.5`
+
+error: expected one of `,` or `}`, found `.`
+ --> $DIR/issue-52496.rs:8:22
+ |
+LL | let _ = Foo { bar.into(), bat: -1, . };
+ | --- ^ expected one of `,` or `}` here
+ | |
+ | while parsing this struct
+
+error: expected identifier, found `.`
+ --> $DIR/issue-52496.rs:8:40
+ |
+LL | let _ = Foo { bar.into(), bat: -1, . };
+ | --- ^ expected identifier
+ | |
+ | while parsing this struct
+
+error[E0063]: missing field `bat` in initializer of `Foo`
+ --> $DIR/issue-52496.rs:4:13
+ |
+LL | let _ = Foo { bar: .5, baz: 42 };
+ | ^^^ missing `bat`
+
+error[E0063]: missing fields `bar`, `baz` in initializer of `Foo`
+ --> $DIR/issue-52496.rs:8:13
+ |
+LL | let _ = Foo { bar.into(), bat: -1, . };
+ | ^^^ missing `bar`, `baz`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0063`.
--- /dev/null
+// compile-pass
+
+// This test checks that the `remove extra angle brackets` error doesn't happen for some
+// potential edge-cases..
+
+struct X {
+ len: u32,
+}
+
+fn main() {
+ let x = X { len: 3 };
+
+ let _ = x.len > (3);
+
+ let _ = x.len >> (3);
+}
--- /dev/null
+// run-rustfix
+
+// This test checks that the following error is emitted and the suggestion works:
+//
+// ```
+// let _ = Vec::<usize>>>::new();
+// ^^ help: remove extra angle brackets
+// ```
+
+fn main() {
+ let _ = Vec::<usize>::new();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = Vec::<usize>::new();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = Vec::<usize>::new();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = Vec::<usize>::new();
+ //~^ ERROR unmatched angle bracket
+}
--- /dev/null
+// run-rustfix
+
+// This test checks that the following error is emitted and the suggestion works:
+//
+// ```
+// let _ = Vec::<usize>>>::new();
+// ^^ help: remove extra angle brackets
+// ```
+
+fn main() {
+ let _ = Vec::<usize>>>>>::new();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = Vec::<usize>>>>::new();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = Vec::<usize>>>::new();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = Vec::<usize>>::new();
+ //~^ ERROR unmatched angle bracket
+}
--- /dev/null
+error: unmatched angle brackets
+ --> $DIR/issue-54521-2.rs:11:25
+ |
+LL | let _ = Vec::<usize>>>>>::new();
+ | ^^^^ help: remove extra angle brackets
+
+error: unmatched angle brackets
+ --> $DIR/issue-54521-2.rs:14:25
+ |
+LL | let _ = Vec::<usize>>>>::new();
+ | ^^^ help: remove extra angle brackets
+
+error: unmatched angle brackets
+ --> $DIR/issue-54521-2.rs:17:25
+ |
+LL | let _ = Vec::<usize>>>::new();
+ | ^^ help: remove extra angle brackets
+
+error: unmatched angle bracket
+ --> $DIR/issue-54521-2.rs:20:25
+ |
+LL | let _ = Vec::<usize>>::new();
+ | ^ help: remove extra angle bracket
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// run-rustfix
+
+// This test checks that the following error is emitted and the suggestion works:
+//
+// ```
+// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+// ^^ help: remove extra angle brackets
+// ```
+
+fn main() {
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>();
+ //~^ ERROR unmatched angle bracket
+}
--- /dev/null
+// run-rustfix
+
+// This test checks that the following error is emitted and the suggestion works:
+//
+// ```
+// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+// ^^ help: remove extra angle brackets
+// ```
+
+fn main() {
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>>();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+ //~^ ERROR unmatched angle bracket
+
+ let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>();
+ //~^ ERROR unmatched angle bracket
+}
--- /dev/null
+error: unmatched angle brackets
+ --> $DIR/issue-54521.rs:11:60
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>>();
+ | ^^^^ help: remove extra angle brackets
+
+error: unmatched angle brackets
+ --> $DIR/issue-54521.rs:14:60
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>>();
+ | ^^^ help: remove extra angle brackets
+
+error: unmatched angle brackets
+ --> $DIR/issue-54521.rs:17:60
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+ | ^^ help: remove extra angle brackets
+
+error: unmatched angle bracket
+ --> $DIR/issue-54521.rs:20:60
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>();
+ | ^ help: remove extra angle bracket
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// run-pass
+
+pub trait Stage: Sync {}
+
+pub enum Enum {
+ A,
+ B,
+}
+
+impl Stage for Enum {}
+
+pub static ARRAY: [(&Stage, &str); 1] = [
+ (&Enum::A, ""),
+];
+
+fn main() {}
--- /dev/null
+// run-pass
+
+#![feature(trait_alias)]
+
+mod alpha {
+ pub trait A {}
+ pub trait C = A;
+}
+
+#[allow(unused_imports)]
+use alpha::C;
+
+fn main() {}
--- /dev/null
+// aux-build:issue-56943.rs
+
+extern crate issue_56943;
+
+fn main() {
+ let _: issue_56943::S = issue_56943::S2;
+ //~^ ERROR mismatched types [E0308]
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-56943.rs:6:29
+ |
+LL | let _: issue_56943::S = issue_56943::S2;
+ | ^^^^^^^^^^^^^^^ expected struct `issue_56943::S`, found struct `issue_56943::S2`
+ |
+ = note: expected type `issue_56943::S`
+ found type `issue_56943::S2`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+
+#![allow(warnings)]
+
+// This test checks that the following error is emitted when a `=` character is used to initialize
+// a struct field when a `:` is expected.
+//
+// ```
+// error: struct fields are initialized with a colon
+// --> $DIR/issue-57684.rs:12:20
+// |
+// LL | let _ = X { f1 = 5 };
+// | ^ help: replace equals symbol with a colon: `:`
+// ```
+
+struct X {
+ f1: i32,
+}
+
+struct Y {
+ f1: i32,
+ f2: i32,
+ f3: i32,
+}
+
+fn main() {
+ let _ = X { f1: 5 };
+ //~^ ERROR expected `:`, found `=`
+
+ let f3 = 3;
+ let _ = Y {
+ f1: 5,
+ //~^ ERROR expected `:`, found `=`
+ f2: 4,
+ f3,
+ };
+}
--- /dev/null
+// run-rustfix
+
+#![allow(warnings)]
+
+// This test checks that the following error is emitted when a `=` character is used to initialize
+// a struct field when a `:` is expected.
+//
+// ```
+// error: struct fields are initialized with a colon
+// --> $DIR/issue-57684.rs:12:20
+// |
+// LL | let _ = X { f1 = 5 };
+// | ^ help: replace equals symbol with a colon: `:`
+// ```
+
+struct X {
+ f1: i32,
+}
+
+struct Y {
+ f1: i32,
+ f2: i32,
+ f3: i32,
+}
+
+fn main() {
+ let _ = X { f1 = 5 };
+ //~^ ERROR expected `:`, found `=`
+
+ let f3 = 3;
+ let _ = Y {
+ f1 = 5,
+ //~^ ERROR expected `:`, found `=`
+ f2: 4,
+ f3,
+ };
+}
--- /dev/null
+error: expected `:`, found `=`
+ --> $DIR/issue-57684.rs:27:20
+ |
+LL | let _ = X { f1 = 5 };
+ | -^
+ | |
+ | help: replace equals symbol with a colon: `:`
+
+error: expected `:`, found `=`
+ --> $DIR/issue-57684.rs:32:12
+ |
+LL | f1 = 5,
+ | -^
+ | |
+ | help: replace equals symbol with a colon: `:`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#![allow(warnings)]
+
+// This tests that the `help: consider dereferencing the boxed value` suggestion isn't made
+// because the box doesn't deref to the type of the arm.
+
+enum S {
+ A { a: usize },
+ B { b: usize },
+}
+
+fn main() {
+ let x = Box::new(3u32);
+ let y = match x {
+ S::A { a } | S::B { b: a } => a,
+ //~^ ERROR mismatched types [E0308]
+ //~^^ ERROR mismatched types [E0308]
+ };
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-57741-1.rs:14:9
+ |
+LL | let y = match x {
+ | - this match expression has type `std::boxed::Box<u32>`
+LL | S::A { a } | S::B { b: a } => a,
+ | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+ |
+ = note: expected type `std::boxed::Box<u32>`
+ found type `S`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-57741-1.rs:14:22
+ |
+LL | let y = match x {
+ | - this match expression has type `std::boxed::Box<u32>`
+LL | S::A { a } | S::B { b: a } => a,
+ | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+ |
+ = note: expected type `std::boxed::Box<u32>`
+ found type `S`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+
+#![allow(warnings)]
+
+// This tests that the `help: consider dereferencing the boxed value` suggestion is made and works.
+
+enum S {
+ A { a: usize },
+ B { b: usize },
+}
+
+enum T {
+ A(usize),
+ B(usize),
+}
+
+fn main() {
+ let x = Box::new(T::A(3));
+ let y = match *x {
+ T::A(a) | T::B(a) => a,
+ //~^ ERROR mismatched types [E0308]
+ //~^^ ERROR mismatched types [E0308]
+ };
+
+ let x = Box::new(S::A { a: 3 });
+ let y = match *x {
+ S::A { a } | S::B { b: a } => a,
+ //~^ ERROR mismatched types [E0308]
+ //~^^ ERROR mismatched types [E0308]
+ };
+}
--- /dev/null
+// run-rustfix
+
+#![allow(warnings)]
+
+// This tests that the `help: consider dereferencing the boxed value` suggestion is made and works.
+
+enum S {
+ A { a: usize },
+ B { b: usize },
+}
+
+enum T {
+ A(usize),
+ B(usize),
+}
+
+fn main() {
+ let x = Box::new(T::A(3));
+ let y = match x {
+ T::A(a) | T::B(a) => a,
+ //~^ ERROR mismatched types [E0308]
+ //~^^ ERROR mismatched types [E0308]
+ };
+
+ let x = Box::new(S::A { a: 3 });
+ let y = match x {
+ S::A { a } | S::B { b: a } => a,
+ //~^ ERROR mismatched types [E0308]
+ //~^^ ERROR mismatched types [E0308]
+ };
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-57741.rs:20:9
+ |
+LL | let y = match x {
+ | -
+ | |
+ | this match expression has type `std::boxed::Box<T>`
+ | help: consider dereferencing the boxed value: `*x`
+LL | T::A(a) | T::B(a) => a,
+ | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T`
+ |
+ = note: expected type `std::boxed::Box<T>`
+ found type `T`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-57741.rs:20:19
+ |
+LL | let y = match x {
+ | -
+ | |
+ | this match expression has type `std::boxed::Box<T>`
+ | help: consider dereferencing the boxed value: `*x`
+LL | T::A(a) | T::B(a) => a,
+ | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T`
+ |
+ = note: expected type `std::boxed::Box<T>`
+ found type `T`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-57741.rs:27:9
+ |
+LL | let y = match x {
+ | -
+ | |
+ | this match expression has type `std::boxed::Box<S>`
+ | help: consider dereferencing the boxed value: `*x`
+LL | S::A { a } | S::B { b: a } => a,
+ | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+ |
+ = note: expected type `std::boxed::Box<S>`
+ found type `S`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-57741.rs:27:22
+ |
+LL | let y = match x {
+ | -
+ | |
+ | this match expression has type `std::boxed::Box<S>`
+ | help: consider dereferencing the boxed value: `*x`
+LL | S::A { a } | S::B { b: a } => a,
+ | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S`
+ |
+ = note: expected type `std::boxed::Box<S>`
+ found type `S`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// ignore-tidy-linelength
+
+trait Foo {}
+
+impl Foo for dyn Send {}
+
+impl Foo for dyn Send + Send {}
+//~^ ERROR conflicting implementations
+//~| hard error
+
+impl Foo for dyn Send + Sync {}
+
+impl Foo for dyn Sync + Send {}
+//~^ ERROR conflicting implementations
+//~| hard error
+
+impl Foo for dyn Send + Sync + Send {}
+//~^ ERROR conflicting implementations
+//~| hard error
+
+fn main() {}
--- /dev/null
+error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + 'static)`: (E0119)
+ --> $DIR/lint-incoherent-auto-trait-objects.rs:7:1
+ |
+LL | impl Foo for dyn Send {}
+ | --------------------- first implementation here
+LL |
+LL | impl Foo for dyn Send + Send {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + 'static)`
+ |
+ = note: #[deny(order_dependent_trait_objects)] on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+
+error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+ --> $DIR/lint-incoherent-auto-trait-objects.rs:13:1
+ |
+LL | impl Foo for dyn Send + Sync {}
+ | ---------------------------- first implementation here
+LL |
+LL | impl Foo for dyn Sync + Send {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+
+error: conflicting implementations of trait `Foo` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`: (E0119)
+ --> $DIR/lint-incoherent-auto-trait-objects.rs:17:1
+ |
+LL | impl Foo for dyn Sync + Send {}
+ | ---------------------------- first implementation here
+...
+LL | impl Foo for dyn Send + Sync + Send {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
+ |
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
+
+error: aborting due to 3 previous errors
+
--> $DIR/liveness-forgot-ret.rs:3:19
|
LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; }
- | - ^^^^^ expected isize, found () - expected because of this statement
+ | - ^^^^^ expected isize, found ()
| |
| this function's body doesn't return
|
error[E0382]: use of moved value: `x`
--> $DIR/liveness-move-call-arg.rs:9:14
|
+LL | let x: Box<isize> = box 25;
+ | - move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+LL | loop {
LL | take(x); //~ ERROR use of moved value: `x`
| ^ value moved here, in previous iteration of loop
- |
- = note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `y`
--> $DIR/liveness-move-in-loop.rs:11:25
|
+LL | let y: Box<isize> = box 42;
+ | - move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+...
LL | x = y; //~ ERROR use of moved value
| ^ value moved here, in previous iteration of loop
- |
- = note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `y`
--> $DIR/liveness-move-in-while.rs:7:24
|
+LL | let y: Box<isize> = box 42;
+ | - move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
+...
LL | println!("{}", y); //~ ERROR use of moved value: `y`
| ^ value borrowed here after move
LL | while true { while true { while true { x = y; x.clone(); } } }
| - value moved here, in previous iteration of loop
- |
- = note: move occurs because `y` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `x`
--> $DIR/liveness-use-after-move.rs:6:20
|
+LL | let x: Box<_> = box 5;
+ | - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
LL | let y = x;
| - value moved here
LL | println!("{}", *x); //~ ERROR use of moved value: `*x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `message`
--> $DIR/liveness-use-after-send.rs:16:20
|
+LL | fn test00_start(ch: Chan<Box<isize>>, message: Box<isize>, _count: Box<isize>) {
+ | ------- move occurs because `message` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
LL | send(ch, message);
| ------- value moved here
LL | println!("{}", message); //~ ERROR use of moved value: `message`
| ^^^^^^^ value borrowed here after move
- |
- = note: move occurs because `message` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to previous error
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/move-guard-same-consts.rs:20:24
+ |
+LL | let x: Box<_> = box 1;
+ | - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+...
+LL | (1, 2) if take(x) => (),
+ | - value moved here
+LL | (1, 2) if take(x) => (), //~ ERROR use of moved value: `x`
+ | ^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/move-in-guard-1.rs:10:24
+ |
+LL | let x: Box<_> = box 1;
+ | - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+...
+LL | (1, _) if take(x) => (),
+ | - value moved here
+LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
+ | ^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
error[E0382]: use of moved value: `x`
--> $DIR/move-in-guard-2.rs:10:24
|
+LL | let x: Box<_> = box 1;
+ | - move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
+...
LL | (_, 2) if take(x) => (), //~ ERROR use of moved value: `x`
| ^ value moved here, in previous iteration of loop
- |
- = note: move occurs because `x` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `a`
--> $DIR/move-into-dead-array-2.rs:14:5
|
+LL | fn foo(mut a: [D; 4], i: usize) {
+ | ----- move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait
LL | drop(a);
| - value moved here
LL | a[i] = d(); //~ ERROR use of moved value: `a`
| ^^^^ value used here after move
- |
- = note: move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-access-to-field.rs:11:12
|
+LL | let x = vec!["hi".to_string()];
+ | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
LL | consume(x.into_iter().next().unwrap());
| - value moved here
LL | touch(&x[0]); //~ ERROR use of moved value: `x`
| ^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-capture-clause-bad.rs:8:20
|
+LL | let x = "Hello world!".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | thread::spawn(move|| {
| ------ value moved into closure here
LL | println!("{}", x);
LL | });
LL | println!("{}", x); //~ ERROR use of moved value
| ^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:11:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let _y = Foo { f:x };
| - value moved here
LL | //~^ NOTE value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:20:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let _y = Foo { f:(((x))) };
| ------- value moved here
LL | //~^ NOTE value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:12:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let _y = Foo { f:x };
| - value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:18:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let _y = (x, 3);
| - value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:35:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+...
LL | x
| - value moved here
...
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `y`
--> $DIR/moves-based-on-type-exprs.rs:36:11
|
+LL | let y = "ho".to_string();
+ | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
+...
LL | y
| - value moved here
...
LL | touch(&y); //~ ERROR use of moved value: `y`
| ^^ value borrowed here after move
- |
- = note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:46:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+...
LL | true => x,
| - value moved here
...
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `y`
--> $DIR/moves-based-on-type-exprs.rs:47:11
|
+LL | let y = "ho".to_string();
+ | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
+...
LL | false => y
| - value moved here
...
LL | touch(&y); //~ ERROR use of moved value: `y`
| ^^ value borrowed here after move
- |
- = note: move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:58:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+...
LL | _ if guard(x) => 10,
| - value moved here
...
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:65:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let _y = [x];
| - value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:71:11
|
+LL | let x = "hi".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let _y = vec![x];
| - value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:77:11
|
+LL | let x = vec!["hi".to_string()];
+ | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
LL | let _y = x.into_iter().next().unwrap();
| - value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/moves-based-on-type-exprs.rs:83:11
|
+LL | let x = vec!["hi".to_string()];
+ | - move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
LL | let _y = [x.into_iter().next().unwrap(); 1];
| - value moved here
LL | touch(&x); //~ ERROR use of moved value: `x`
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::vec::Vec<std::string::String>`, which does not implement the `Copy` trait
error: aborting due to 11 previous errors
error[E0382]: borrow of moved value: `f`
--> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5
|
+LL | fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) {
+ | - ----- move occurs because `f` has type `F`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
LL | let mut r = R {c: Box::new(f)};
| - value moved here
LL | f(&mut r, false) //~ ERROR use of moved value
| ^ value borrowed here after move
- |
- = note: move occurs because `f` has type `F`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors
error[E0382]: use of moved value: `x` (Mir)
--> $DIR/moves-based-on-type-tuple.rs:6:13
|
+LL | fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
+ | - move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
LL | box (x, x)
| - ^ value used here after move
| |
| value moved here
- |
- = note: move occurs because `x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
error: aborting due to 2 previous errors
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-access-spans.rs:37:5
|
+LL | fn closure_imm_capture_moved(mut x: String) {
+ | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let r = x;
| - value moved here
LL | || x.len(); //~ ERROR
| ^^ - borrow occurs due to use in closure
| |
| value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-access-spans.rs:42:5
|
+LL | fn closure_mut_capture_moved(mut x: String) {
+ | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let r = x;
| - value moved here
LL | || x = String::new(); //~ ERROR
| ^^ - borrow occurs due to use in closure
| |
| value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-access-spans.rs:47:5
|
+LL | fn closure_unique_capture_moved(x: &mut String) {
+ | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
LL | let r = x;
| - value moved here
LL | || *x = String::new(); //~ ERROR
| ^^ - borrow occurs due to use in closure
| |
| value borrowed here after move
- |
- = note: move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/closure-access-spans.rs:52:5
|
+LL | fn closure_move_capture_moved(x: &mut String) {
+ | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
LL | let r = x;
| - value moved here
LL | || x; //~ ERROR
| ^^ - use occurs due to use in closure
| |
| value used here after move
- |
- = note: move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait
error: aborting due to 9 previous errors
error[E0382]: use of moved value: `x`
--> $DIR/closure-move-spans.rs:7:13
|
+LL | fn move_after_move(x: String) {
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | || x;
| -- - variable moved due to use in closure
| |
| value moved into closure here
LL | let y = x; //~ ERROR
| ^ value used here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-move-spans.rs:12:13
|
+LL | fn borrow_after_move(x: String) {
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | || x;
| -- - variable moved due to use in closure
| |
| value moved into closure here
LL | let y = &x; //~ ERROR
| ^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/closure-move-spans.rs:17:13
|
+LL | fn borrow_mut_after_move(mut x: String) {
+ | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | || x;
| -- - variable moved due to use in closure
| |
| value moved into closure here
LL | let y = &mut x; //~ ERROR
| ^^^^^^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to 3 previous errors
error[E0382]: use of moved value: `x`
--> $DIR/closures-in-loops.rs:8:9
|
+LL | fn repreated_move(x: String) {
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+LL | for i in 0..10 {
LL | || x; //~ ERROR
| ^^ - use occurs due to use in closure
| |
| value moved into closure here, in previous iteration of loop
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> $DIR/closures-in-loops.rs:15:16
error[E0382]: assign of moved value: `d`
--> $DIR/issue-21232-partial-init-and-erroneous-use.rs:43:5
|
+LL | let mut d = D { x: 0, s: S{ y: 0, z: 0 } };
+ | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
LL | drop(d);
| - value moved here
LL | d.x = 10;
| ^^^^^^^^ value assigned here after move
- |
- = note: move occurs because `d` has type `D`, which does not implement the `Copy` trait
error[E0381]: assign to part of possibly uninitialized variable: `d`
--> $DIR/issue-21232-partial-init-and-erroneous-use.rs:49:5
error[E0382]: assign to part of moved value: `d`
--> $DIR/issue-21232-partial-init-and-erroneous-use.rs:62:5
|
+LL | let mut d = D { x: 0, s: S{ y: 0, z: 0} };
+ | ----- move occurs because `d` has type `D`, which does not implement the `Copy` trait
LL | drop(d);
| - value moved here
LL | d.s.y = 20;
| ^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `d` has type `D`, which does not implement the `Copy` trait
error: aborting due to 6 previous errors
--> $DIR/issue-21232-partial-init-and-use.rs:113:5
|
LL | let mut s: S<B> = S::new(); drop(s);
- | - value moved here
+ | ----- - value moved here
+ | |
+ | move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
LL | s.x = 10; s.y = Box::new(20);
| ^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-21232-partial-init-and-use.rs:120:5
|
LL | let mut t: T = (0, Box::new(0)); drop(t);
- | - value moved here
+ | ----- - value moved here
+ | |
+ | move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
LL | t.0 = 10; t.1 = Box::new(20);
| ^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
error[E0381]: assign to part of possibly uninitialized variable: `s`
--> $DIR/issue-21232-partial-init-and-use.rs:127:5
--> $DIR/issue-21232-partial-init-and-use.rs:141:5
|
LL | let mut s: S<B> = S::new(); drop(s);
- | - value moved here
+ | ----- - value moved here
+ | |
+ | move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
LL | s.x = 10;
| ^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `s` has type `S<std::boxed::Box<u32>>`, which does not implement the `Copy` trait
error[E0382]: assign to part of moved value: `t`
--> $DIR/issue-21232-partial-init-and-use.rs:148:5
|
LL | let mut t: T = (0, Box::new(0)); drop(t);
- | - value moved here
+ | ----- - value moved here
+ | |
+ | move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
LL | t.0 = 10;
| ^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `t` has type `(u32, std::boxed::Box<u32>)`, which does not implement the `Copy` trait
error[E0381]: assign to part of possibly uninitialized variable: `s`
--> $DIR/issue-21232-partial-init-and-use.rs:155:5
error[E0382]: assign to part of moved value: `c`
--> $DIR/issue-21232-partial-init-and-use.rs:259:13
|
+LL | let mut c = (1, "".to_owned());
+ | ----- move occurs because `c` has type `(i32, std::string::String)`, which does not implement the `Copy` trait
+LL | match c {
LL | c2 => {
| -- value moved here
LL | c.0 = 2; //~ ERROR assign to part of moved value
| ^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `c` has type `(i32, std::string::String)`, which does not implement the `Copy` trait
error[E0382]: assign to part of moved value: `c`
--> $DIR/issue-21232-partial-init-and-use.rs:269:13
|
+LL | let mut c = (1, (1, "".to_owned()));
+ | ----- move occurs because `c` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait
+LL | match c {
LL | c2 => {
| -- value moved here
LL | (c.1).0 = 2; //~ ERROR assign to part of moved value
| ^^^^^^^^^^^ value partially assigned here after move
- |
- = note: move occurs because `c` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait
error[E0382]: assign to part of moved value: `c.1`
--> $DIR/issue-21232-partial-init-and-use.rs:277:13
error[E0382]: use of moved value: `range`
--> $DIR/issue-51512.rs:7:13
|
+LL | let range = 0..1;
+ | ----- move occurs because `range` has type `std::ops::Range<i32>`, which does not implement the `Copy` trait
LL | let r = range;
| ----- value moved here
LL | let x = range.start;
| ^^^^^^^^^^^ value used here after move
- |
- = note: move occurs because `range` has type `std::ops::Range<i32>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `a.b`
--> $DIR/issue-52669.rs:15:5
|
+LL | fn bar(mut a: A) -> B {
+ | ----- move occurs because `a` has type `A`, which does not implement the `Copy` trait
+LL | a.b = B;
LL | foo(a);
| - value moved here
LL | a.b.clone()
| ^^^ value borrowed here after move
- |
- = note: move occurs because `a` has type `A`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `arc_v`
--> $DIR/no-capture-arc.rs:14:18
|
+LL | let arc_v = Arc::new(v);
+ | ----- move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
+LL |
LL | thread::spawn(move|| {
| ------ value moved into closure here
LL | assert_eq!((*arc_v)[3], 4);
...
LL | assert_eq!((*arc_v)[2], 3);
| ^^^^^ value borrowed here after move
- |
- = note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `arc_v`
--> $DIR/no-reuse-move-arc.rs:12:18
|
+LL | let arc_v = Arc::new(v);
+ | ----- move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
+LL |
LL | thread::spawn(move|| {
| ------ value moved into closure here
LL | assert_eq!((*arc_v)[3], 4);
...
LL | assert_eq!((*arc_v)[2], 3); //~ ERROR use of moved value: `arc_v`
| ^^^^^ value borrowed here after move
- |
- = note: move occurs because `arc_v` has type `std::sync::Arc<std::vec::Vec<i32>>`, which does not implement the `Copy` trait
error: aborting due to previous error
-error[E0277]: the trait bound `i32: std::slice::SliceIndex<[i32]>` is not satisfied
+error[E0277]: the type `[i32]` cannot be indexed by `i32`
--> $DIR/slice-index.rs:11:5
|
LL | x[1i32]; //~ ERROR E0277
= help: the trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32`
= note: required because of the requirements on the impl of `std::ops::Index<i32>` for `[i32]`
-error[E0277]: the trait bound `std::ops::RangeTo<i32>: std::slice::SliceIndex<[i32]>` is not satisfied
+error[E0277]: the type `[i32]` cannot be indexed by `std::ops::RangeTo<i32>`
--> $DIR/slice-index.rs:12:5
|
LL | x[..1i32]; //~ ERROR E0277
--- /dev/null
+error[E0382]: use of moved value: `blk`
+ --> $DIR/once-cant-call-twice-on-heap.rs:9:5
+ |
+LL | fn foo<F:FnOnce()>(blk: F) {
+ | - --- move occurs because `blk` has type `F`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
+LL | blk();
+ | --- value moved here
+LL | blk(); //~ ERROR use of moved value
+ | ^^^ value used here after move
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
+++ /dev/null
-struct Session {
- opts: u8,
-}
-
-fn main() {
- let sess: &Session = &Session { opts: 0 };
- (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session`
-
- let x = [0u32];
- (x as [u32; 1]).0; //~ ERROR no field `0` on type `[u32; 1]`
-}
+++ /dev/null
-error[E0609]: no field `opts` on type `*const Session`
- --> $DIR/parenthesised-deref-suggestion.rs:7:30
- |
-LL | (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session`
- | ^^^^
-help: `(sess as *const Session)` is a raw pointer; try dereferencing it
- |
-LL | (*(sess as *const Session)).opts; //~ ERROR no field `opts` on type `*const Session`
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0609]: no field `0` on type `[u32; 1]`
- --> $DIR/parenthesised-deref-suggestion.rs:10:21
- |
-LL | (x as [u32; 1]).0; //~ ERROR no field `0` on type `[u32; 1]`
- | ----------------^
- | |
- | help: instead of using tuple indexing, use array indexing: `(x as [u32; 1])[0]`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0609`.
--- /dev/null
+struct Session {
+ opts: u8,
+}
+
+fn main() {
+ let sess: &Session = &Session { opts: 0 };
+ (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session`
+
+ let x = [0u32];
+ (x as [u32; 1]).0; //~ ERROR no field `0` on type `[u32; 1]`
+}
--- /dev/null
+error[E0609]: no field `opts` on type `*const Session`
+ --> $DIR/parenthesized-deref-suggestion.rs:7:30
+ |
+LL | (sess as *const Session).opts; //~ ERROR no field `opts` on type `*const Session`
+ | ^^^^
+help: `(sess as *const Session)` is a raw pointer; try dereferencing it
+ |
+LL | (*(sess as *const Session)).opts; //~ ERROR no field `opts` on type `*const Session`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0609]: no field `0` on type `[u32; 1]`
+ --> $DIR/parenthesized-deref-suggestion.rs:10:21
+ |
+LL | (x as [u32; 1]).0; //~ ERROR no field `0` on type `[u32; 1]`
+ | ----------------^
+ | |
+ | help: instead of using tuple indexing, use array indexing: `(x as [u32; 1])[0]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
--> $DIR/doc-before-eof.rs:3:1
|
LL | /// hi //~ERROR expected item after doc comment
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this doc comment doesn't document anything
error: aborting due to previous error
--> $DIR/doc-before-extern-rbrace.rs:2:5
|
LL | /// hi
- | ^^^^^^
+ | ^^^^^^ this doc comment doesn't document anything
error: aborting due to previous error
--> $DIR/doc-before-mod-rbrace.rs:4:5
|
LL | /// document
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ this doc comment doesn't document anything
error: aborting due to previous error
const
mut //~ ERROR: const globals cannot be mutable
-//~^ HELP did you mean to declare a static?
+//~^^ HELP you might want to declare a static instead
FOO: usize = 3;
fn main() {
error: const globals cannot be mutable
--> $DIR/issue-17718-const-mut.rs:2:1
|
+LL | const
+ | ----- help: you might want to declare a static instead: `static`
LL | mut //~ ERROR: const globals cannot be mutable
- | ^^^
- |
- = help: did you mean to declare a static?
+ | ^^^ cannot be mutable
error: aborting due to previous error
// This test needs to the last one appearing in this file as it kills the parser
static c: char =
- 'nope' //~ ERROR: character literal may only contain one codepoint: 'nope'
+ 'nope' //~ ERROR: character literal may only contain one codepoint
;
-error: character literal may only contain one codepoint: 'nope'
+error: character literal may only contain one codepoint
--> $DIR/lex-bad-char-literals-2.rs:3:5
|
-LL | 'nope' //~ ERROR: character literal may only contain one codepoint: 'nope'
+LL | 'nope' //~ ERROR: character literal may only contain one codepoint
| ^^^^^^
-error: aborting due to previous error
+error[E0601]: `main` function not found in crate `lex_bad_char_literals_2`
+ |
+ = note: consider adding a `main` function to `$DIR/lex-bad-char-literals-2.rs`
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0601`.
-// This test needs to the last one appearing in this file as it kills the parser
-static c: char =
- '●●' //~ ERROR: character literal may only contain one codepoint
- //~| ERROR: mismatched types
-;
+static c: char = '●●';
+//~^ ERROR: character literal may only contain one codepoint
-fn main() {}
+fn main() {
+ let ch: &str = '●●';
+ //~^ ERROR: character literal may only contain one codepoint
+}
error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-3.rs:3:5
+ --> $DIR/lex-bad-char-literals-3.rs:1:18
|
-LL | '●●' //~ ERROR: character literal may only contain one codepoint
- | ^^^^
+LL | static c: char = '●●';
+ | ^^^^
help: if you meant to write a `str` literal, use double quotes
|
-LL | "●●" //~ ERROR: character literal may only contain one codepoint
- | ^^^^
+LL | static c: char = "●●";
+ | ^^^^
-error[E0308]: mismatched types
- --> $DIR/lex-bad-char-literals-3.rs:3:5
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-3.rs:5:20
|
-LL | '●●' //~ ERROR: character literal may only contain one codepoint
- | ^^^^ expected char, found reference
+LL | let ch: &str = '●●';
+ | ^^^^
+help: if you meant to write a `str` literal, use double quotes
|
- = note: expected type `char`
- found type `&'static str`
+LL | let ch: &str = "●●";
+ | ^^^^
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
//
// This test needs to the last one appearing in this file as it kills the parser
static c: char =
- '● //~ ERROR: character literal may only contain one codepoint: '●
+ '● //~ ERROR: character literal may only contain one codepoint
;
error: character literal may only contain one codepoint: '●
--> $DIR/lex-bad-char-literals-4.rs:4:5
|
-LL | '● //~ ERROR: character literal may only contain one codepoint: '●
+LL | '● //~ ERROR: character literal may only contain one codepoint
| ^^
error: aborting due to previous error
-//
-// This test needs to the last one appearing in this file as it kills the parser
-static c: char =
- '\x10\x10' //~ ERROR: character literal may only contain one codepoint
- //~| ERROR: mismatched types
-;
+static c: char = '\x10\x10';
+//~^ ERROR: character literal may only contain one codepoint
-fn main() {}
+fn main() {
+ let ch: &str = '\x10\x10';
+ //~^ ERROR: character literal may only contain one codepoint
+}
error: character literal may only contain one codepoint
- --> $DIR/lex-bad-char-literals-5.rs:4:5
+ --> $DIR/lex-bad-char-literals-5.rs:1:18
|
-LL | '/x10/x10' //~ ERROR: character literal may only contain one codepoint
- | ^^^^^^^^^^
+LL | static c: char = '/x10/x10';
+ | ^^^^^^^^^^
help: if you meant to write a `str` literal, use double quotes
|
-LL | "/x10/x10" //~ ERROR: character literal may only contain one codepoint
- | ^^^^^^^^^^
+LL | static c: char = "/x10/x10";
+ | ^^^^^^^^^^
-error[E0308]: mismatched types
- --> $DIR/lex-bad-char-literals-5.rs:4:5
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-5.rs:5:20
|
-LL | '/x10/x10' //~ ERROR: character literal may only contain one codepoint
- | ^^^^^^^^^^ expected char, found reference
+LL | let ch: &str = '/x10/x10';
+ | ^^^^^^^^^^
+help: if you meant to write a `str` literal, use double quotes
|
- = note: expected type `char`
- found type `&'static str`
+LL | let ch: &str = "/x10/x10";
+ | ^^^^^^^^^^
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn main() {
+ let x: &str = 'ab';
+ //~^ ERROR: character literal may only contain one codepoint
+ let y: char = 'cd';
+ //~^ ERROR: character literal may only contain one codepoint
+ let z = 'ef';
+ //~^ ERROR: character literal may only contain one codepoint
+
+ if x == y {}
+ //~^ ERROR: can't compare `&str` with `char`
+ if y == z {} // no error here
+ if x == z {}
+ //~^ ERROR: can't compare `&str` with `char`
+
+ let a: usize = "";
+ //~^ ERROR: mismatched types
+}
--- /dev/null
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-6.rs:2:19
+ |
+LL | let x: &str = 'ab';
+ | ^^^^
+
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-6.rs:4:19
+ |
+LL | let y: char = 'cd';
+ | ^^^^
+
+error: character literal may only contain one codepoint
+ --> $DIR/lex-bad-char-literals-6.rs:6:13
+ |
+LL | let z = 'ef';
+ | ^^^^
+
+error[E0277]: can't compare `&str` with `char`
+ --> $DIR/lex-bad-char-literals-6.rs:9:10
+ |
+LL | if x == y {}
+ | ^^ no implementation for `&str == char`
+ |
+ = help: the trait `std::cmp::PartialEq<char>` is not implemented for `&str`
+
+error[E0308]: mismatched types
+ --> $DIR/lex-bad-char-literals-6.rs:15:20
+ |
+LL | let a: usize = "";
+ | ^^ expected usize, found reference
+ |
+ = note: expected type `usize`
+ found type `&'static str`
+
+error[E0277]: can't compare `&str` with `char`
+ --> $DIR/lex-bad-char-literals-6.rs:12:10
+ |
+LL | if x == z {}
+ | ^^ no implementation for `&str == char`
+ |
+ = help: the trait `std::cmp::PartialEq<char>` is not implemented for `&str`
+
+error: aborting due to 6 previous errors
+
+Some errors occurred: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
}
let a = S { foo: (), bar: () };
- let b = S { foo: () with a };
+ let b = S { foo: () with a, bar: () };
//~^ ERROR expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
- //~| ERROR missing field `bar` in initializer of `main::S`
}
error: expected one of `,`, `.`, `?`, `}`, or an operator, found `with`
--> $DIR/removed-syntax-with-1.rs:8:25
|
-LL | let b = S { foo: () with a };
- | ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator here
+LL | let b = S { foo: () with a, bar: () };
+ | - ^^^^ expected one of `,`, `.`, `?`, `}`, or an operator here
+ | |
+ | while parsing this struct
-error[E0063]: missing field `bar` in initializer of `main::S`
- --> $DIR/removed-syntax-with-1.rs:8:13
- |
-LL | let b = S { foo: () with a };
- | ^ missing `bar`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0063`.
let a = S { foo: (), bar: () };
let b = S { foo: (), with a };
//~^ ERROR expected one of `,` or `}`, found `a`
- //~| ERROR cannot find value `with` in this scope
- //~| ERROR struct `main::S` has no field named `with`
+ //~| ERROR missing field `bar` in initializer of `main::S`
}
--> $DIR/removed-syntax-with-2.rs:8:31
|
LL | let b = S { foo: (), with a };
- | ^ expected one of `,` or `}` here
+ | - ^ expected one of `,` or `}` here
+ | |
+ | while parsing this struct
-error[E0425]: cannot find value `with` in this scope
- --> $DIR/removed-syntax-with-2.rs:8:26
+error[E0063]: missing field `bar` in initializer of `main::S`
+ --> $DIR/removed-syntax-with-2.rs:8:13
|
LL | let b = S { foo: (), with a };
- | ^^^^ not found in this scope
+ | ^ missing `bar`
-error[E0560]: struct `main::S` has no field named `with`
- --> $DIR/removed-syntax-with-2.rs:8:26
- |
-LL | let b = S { foo: (), with a };
- | ^^^^ `main::S` does not have this field
- |
- = note: available fields are: `foo`, `bar`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors occurred: E0425, E0560.
-For more information about an error, try `rustc --explain E0425`.
+For more information about this error, try `rustc --explain E0063`.
struct Rgb(u8, u8, u8);
fn main() {
- let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
- //~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
+ let _ = Rgb { 0, 1, 2 };
+ //~^ ERROR expected identifier, found `0`
+ //~| ERROR expected identifier, found `1`
+ //~| ERROR expected identifier, found `2`
+ //~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
}
error: expected identifier, found `0`
--> $DIR/struct-field-numeric-shorthand.rs:4:19
|
-LL | let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
+LL | let _ = Rgb { 0, 1, 2 };
| --- ^ expected identifier
| |
| while parsing this struct
+error: expected identifier, found `1`
+ --> $DIR/struct-field-numeric-shorthand.rs:4:22
+ |
+LL | let _ = Rgb { 0, 1, 2 };
+ | --- ^ expected identifier
+ | |
+ | while parsing this struct
+
+error: expected identifier, found `2`
+ --> $DIR/struct-field-numeric-shorthand.rs:4:25
+ |
+LL | let _ = Rgb { 0, 1, 2 };
+ | --- ^ expected identifier
+ | |
+ | while parsing this struct
+
error[E0063]: missing fields `0`, `1`, `2` in initializer of `Rgb`
--> $DIR/struct-field-numeric-shorthand.rs:4:13
|
-LL | let _ = Rgb { 0, 1, 2 }; //~ ERROR expected identifier, found `0`
+LL | let _ = Rgb { 0, 1, 2 };
| ^^^ missing `0`, `1`, `2`
-error: aborting due to 2 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0063`.
error: field expressions may not have generic arguments
- --> $DIR/type-parameters-in-field-exprs.rs:13:8
+ --> $DIR/type-parameters-in-field-exprs.rs:13:10
|
LL | f.x::<isize>;
- | ^^^^^^^^^
+ | ^^^^^^^
error: field expressions may not have generic arguments
- --> $DIR/type-parameters-in-field-exprs.rs:15:8
+ --> $DIR/type-parameters-in-field-exprs.rs:15:10
|
LL | f.x::<>;
- | ^^^^
+ | ^^
error: field expressions may not have generic arguments
- --> $DIR/type-parameters-in-field-exprs.rs:17:8
+ --> $DIR/type-parameters-in-field-exprs.rs:17:10
|
LL | f.x::();
- | ^^^^
+ | ^^
error: aborting due to 3 previous errors
--- /dev/null
+fn unrelated() -> Result<(), std::string::ParseError> { // #57664
+ let x = 0;
+
+ match x {
+ 1 => {
+ let property_value_as_string = "a".parse()?;
+ }
+ 2 => {
+ let value: &bool = unsafe { &42 };
+ //~^ ERROR mismatched types
+ }
+ };
+
+ Ok(())
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return-2.rs:9:41
+ |
+LL | let value: &bool = unsafe { &42 };
+ | ^^^ expected bool, found integer
+ |
+ = note: expected type `&bool`
+ found type `&{integer}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+fn foo() -> impl std::fmt::Display {
+ if false {
+ return 0i32;
+ }
+ 1u32
+ //~^ ERROR mismatched types
+}
+
+fn bar() -> impl std::fmt::Display {
+ if false {
+ return 0i32;
+ } else {
+ return 1u32;
+ //~^ ERROR mismatched types
+ }
+}
+
+fn baz() -> impl std::fmt::Display {
+ if false {
+ //~^ ERROR mismatched types
+ return 0i32;
+ } else {
+ 1u32
+ }
+}
+
+fn qux() -> impl std::fmt::Display {
+ if false {
+ 0i32
+ } else {
+ 1u32
+ //~^ ERROR if and else have incompatible types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:5:5
+ |
+LL | fn foo() -> impl std::fmt::Display {
+ | ---------------------- expected because this return type...
+LL | if false {
+LL | return 0i32;
+ | ---- ...is found to be `i32` here
+LL | }
+LL | 1u32
+ | ^^^^ expected i32, found u32
+ |
+ = note: expected type `i32`
+ found type `u32`
+
+error[E0308]: mismatched types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
+ |
+LL | fn bar() -> impl std::fmt::Display {
+ | ---------------------- expected because this return type...
+LL | if false {
+LL | return 0i32;
+ | ---- ...is found to be `i32` here
+LL | } else {
+LL | return 1u32;
+ | ^^^^ expected i32, found u32
+ |
+ = note: expected type `i32`
+ found type `u32`
+
+error[E0308]: mismatched types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:19:5
+ |
+LL | fn baz() -> impl std::fmt::Display {
+ | ---------------------- expected because this return type...
+LL | / if false {
+LL | | //~^ ERROR mismatched types
+LL | | return 0i32;
+ | | ---- ...is found to be `i32` here
+LL | | } else {
+LL | | 1u32
+LL | | }
+ | |_____^ expected i32, found u32
+ |
+ = note: expected type `i32`
+ found type `u32`
+
+error[E0308]: if and else have incompatible types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
+ |
+LL | / if false {
+LL | | 0i32
+ | | ---- expected because of this
+LL | | } else {
+LL | | 1u32
+ | | ^^^^ expected i32, found u32
+LL | | //~^ ERROR if and else have incompatible types
+LL | | }
+ | |_____- if and else have incompatible types
+ |
+ = note: expected type `i32`
+ found type `u32`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
// Private types and traits are not allowed in interfaces of associated types.
// This test also ensures that the checks are performed even inside private modules.
-#![feature(associated_type_defaults)]
+#![feature(associated_type_defaults, existential_type)]
mod m {
struct Priv;
type Alias4 = Priv;
//~^ ERROR private type `m::Priv` in public interface
+
+ type Exist;
+ fn infer_exist() -> Self::Exist;
}
impl PubTr for u8 {
type Alias1 = Priv;
//~^ ERROR private type `m::Priv` in public interface
+
+ existential type Exist: PrivTr;
+ //~^ ERROR private trait `m::PrivTr` in public interface
+ fn infer_exist() -> Self::Exist { Priv }
}
}
LL | | //~| WARN this was previously accepted
LL | | //~| WARN private type `m::Priv` in public interface
... |
-LL | | //~^ ERROR private type `m::Priv` in public interface
+LL | | fn infer_exist() -> Self::Exist;
LL | | }
| |_____^
|
LL | | //~| WARN this was previously accepted
LL | | //~| WARN private type `m::Priv` in public interface
... |
-LL | | //~^ ERROR private type `m::Priv` in public interface
+LL | | fn infer_exist() -> Self::Exist;
LL | | }
| |_____^
|
| ^^^^^^^^^^^^^^^^^^^ can't leak private type
error[E0446]: private type `m::Priv` in public interface
- --> $DIR/private-in-public-assoc-ty.rs:28:9
+ --> $DIR/private-in-public-assoc-ty.rs:31:9
|
LL | struct Priv;
| - `m::Priv` declared as private
LL | type Alias1 = Priv;
| ^^^^^^^^^^^^^^^^^^^ can't leak private type
-error: aborting due to 2 previous errors
+error[E0445]: private trait `m::PrivTr` in public interface
+ --> $DIR/private-in-public-assoc-ty.rs:34:9
+ |
+LL | trait PrivTr {}
+ | - `m::PrivTr` declared as private
+...
+LL | existential type Exist: PrivTr;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait
+
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0446`.
+Some errors occurred: E0445, E0446.
+For more information about an error, try `rustc --explain E0445`.
Priv
}
+pub trait Trait {
+ type Pub: Default;
+ fn method() -> Self::Pub;
+}
+
+impl Trait for u8 {
+ existential type Pub: Default;
+ fn method() -> Self::Pub { Priv }
+}
+
fn main() {}
error[E0308]: mismatched types
--> $DIR/span-preservation.rs:19:29
|
+LL | fn b(x: Option<isize>) -> usize {
+ | ----- expected `usize` because of return type
+LL | match x {
LL | Some(x) => { return x }, //~ ERROR mismatched types
| ^ expected usize, found isize
+++ /dev/null
-#![feature(quote)]
-fn main() {
- macro_rules! foo {
- ($bar:expr) => {
- quote_expr!(cx, $bar)
- //~^ ERROR quote! with interpolated token
- //~| ERROR failed to resolve: maybe a missing `extern crate syntax;`?
- //~| ERROR failed to resolve: maybe a missing `extern crate syntax;`?
- //~| ERROR cannot find value `cx` in this scope
- //~| ERROR cannot find function `new_parser_from_tts` in this scope
- }
- }
- foo!(bar);
-}
+++ /dev/null
-error: quote! with interpolated token
- --> $DIR/quote-with-interpolated.rs:5:29
- |
-LL | quote_expr!(cx, $bar)
- | ^^^^
-...
-LL | foo!(bar);
- | ---------- in this macro invocation
-
-error[E0433]: failed to resolve: maybe a missing `extern crate syntax;`?
- --> $DIR/quote-with-interpolated.rs:5:13
- |
-LL | quote_expr!(cx, $bar)
- | ^^^^^^^^^^^^^^^^^^^^^ maybe a missing `extern crate syntax;`?
-
-error[E0433]: failed to resolve: maybe a missing `extern crate syntax;`?
- --> $DIR/quote-with-interpolated.rs:5:29
- |
-LL | quote_expr!(cx, $bar)
- | ^^^^ maybe a missing `extern crate syntax;`?
-
-error[E0425]: cannot find value `cx` in this scope
- --> $DIR/quote-with-interpolated.rs:5:25
- |
-LL | quote_expr!(cx, $bar)
- | ^^ not found in this scope
-...
-LL | foo!(bar);
- | ---------- in this macro invocation
-
-error[E0425]: cannot find function `new_parser_from_tts` in this scope
- --> $DIR/quote-with-interpolated.rs:5:13
- |
-LL | quote_expr!(cx, $bar)
- | ^^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to 5 previous errors
-
-Some errors occurred: E0425, E0433.
-For more information about an error, try `rustc --explain E0425`.
error[E0382]: use of moved value: `x`
--> $DIR/ref-suggestion.rs:4:5
|
+LL | let x = vec![1];
+ | - move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
LL | let y = x;
| - value moved here
LL | x; //~ ERROR use of moved value
| ^ value used here after move
- |
- = note: move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/ref-suggestion.rs:8:5
|
+LL | let x = vec![1];
+ | - move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
LL | let mut y = x;
| - value moved here
LL | x; //~ ERROR use of moved value
| ^ value used here after move
- |
- = note: move occurs because `x` has type `std::vec::Vec<i32>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/ref-suggestion.rs:16:5
error[E0308]: mismatched types
--> $DIR/return-from-diverging.rs:4:12
|
+LL | fn fail() -> ! {
+ | - expected `!` because of return type
LL | return "wow"; //~ ERROR mismatched types
| ^^^^^ expected !, found reference
|
error[E0382]: use of moved value: `a`
--> $DIR/dbg-macro-move-semantics.rs:9:18
|
+LL | let a = NoCopy(0);
+ | - move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait
LL | let _ = dbg!(a);
| ------- value moved here
LL | let _ = dbg!(a); //~ ERROR use of moved value
| ^ value used here after move
|
- = note: move occurs because `a` has type `NoCopy`, which does not implement the `Copy` trait
= 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
--- /dev/null
+// Test that the simd_bitmask intrinsic produces ok-ish error
+// messages when misused.
+
+#![feature(repr_simd, platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct u32x2(pub u32, pub u32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x8(
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x16(
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x32(
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+);
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct u8x64(
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+ pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8,
+);
+
+extern "platform-intrinsic" {
+ fn simd_bitmask<T, U>(x: T) -> U;
+}
+
+fn main() {
+ let m2 = u32x2(0, 0);
+ let m4 = u32x4(0, 0, 0, 0);
+ let m8 = u8x8(0, 0, 0, 0, 0, 0, 0, 0);
+ let m16 = u8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ let m32 = u8x32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ let m64 = u8x64(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ unsafe {
+ let _: u8 = simd_bitmask(m2);
+ let _: u8 = simd_bitmask(m4);
+ let _: u8 = simd_bitmask(m8);
+ let _: u16 = simd_bitmask(m16);
+ let _: u32 = simd_bitmask(m32);
+ let _: u64 = simd_bitmask(m64);
+
+ let _: u16 = simd_bitmask(m2);
+ //~^ ERROR bitmask `u16`, expected `u8`
+
+ let _: u16 = simd_bitmask(m8);
+ //~^ ERROR bitmask `u16`, expected `u8`
+
+ let _: u32 = simd_bitmask(m16);
+ //~^ ERROR bitmask `u32`, expected `u16`
+
+ let _: u64 = simd_bitmask(m32);
+ //~^ ERROR bitmask `u64`, expected `u32`
+
+ let _: u128 = simd_bitmask(m64);
+ //~^ ERROR bitmask `u128`, expected `u64`
+
+ }
+}
--- /dev/null
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+ --> $DIR/simd-intrinsic-generic-bitmask.rs:74:22
+ |
+LL | let _: u16 = simd_bitmask(m2);
+ | ^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u16`, expected `u8`
+ --> $DIR/simd-intrinsic-generic-bitmask.rs:77:22
+ |
+LL | let _: u16 = simd_bitmask(m8);
+ | ^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u32`, expected `u16`
+ --> $DIR/simd-intrinsic-generic-bitmask.rs:80:22
+ |
+LL | let _: u32 = simd_bitmask(m16);
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u64`, expected `u32`
+ --> $DIR/simd-intrinsic-generic-bitmask.rs:83:22
+ |
+LL | let _: u64 = simd_bitmask(m32);
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: bitmask `u128`, expected `u64`
+ --> $DIR/simd-intrinsic-generic-bitmask.rs:86:23
+ |
+LL | let _: u128 = simd_bitmask(m64);
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0511`.
error: generic arguments in macro path
- --> $DIR/macro-ty-params.rs:10:8
+ --> $DIR/macro-ty-params.rs:10:10
|
LL | foo::<T>!(); //~ ERROR generic arguments in macro path
- | ^^^^^
+ | ^^^
error: generic arguments in macro path
- --> $DIR/macro-ty-params.rs:11:8
+ --> $DIR/macro-ty-params.rs:11:10
|
LL | foo::<>!(); //~ ERROR generic arguments in macro path
- | ^^^^
+ | ^^
error: unexpected generic arguments in path
--> $DIR/macro-ty-params.rs:12:8
// run-rustfix
fn main() {
- println!("●●");
- //~^ ERROR character literal may only contain one codepoint
+ println!("{}", "●●"); //~ ERROR character literal may only contain one codepoint
+ //~^ ERROR format argument must be a string literal
}
// run-rustfix
fn main() {
- println!('●●');
- //~^ ERROR character literal may only contain one codepoint
+ println!('●●'); //~ ERROR character literal may only contain one codepoint
+ //~^ ERROR format argument must be a string literal
}
error: character literal may only contain one codepoint
--> $DIR/str-as-char.rs:4:14
|
-LL | println!('●●');
+LL | println!('●●'); //~ ERROR character literal may only contain one codepoint
| ^^^^
help: if you meant to write a `str` literal, use double quotes
|
-LL | println!("●●");
+LL | println!("●●"); //~ ERROR character literal may only contain one codepoint
| ^^^^
-error: aborting due to previous error
+error: format argument must be a string literal
+ --> $DIR/str-as-char.rs:4:14
+ |
+LL | println!('●●'); //~ ERROR character literal may only contain one codepoint
+ | ^^^^
+help: you might be missing a string literal to format with
+ |
+LL | println!("{}", '●●'); //~ ERROR character literal may only contain one codepoint
+ | ^^^^^
+
+error: aborting due to 2 previous errors
pub fn main() {
let s: &str = "hello";
- let c: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}`
+ let _: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}`
+ let _ = s.get(4); //~ ERROR the type `str` cannot be indexed by `{integer}`
+ let _ = s.get_unchecked(4); //~ ERROR the type `str` cannot be indexed by `{integer}`
+ let _: u8 = s['c']; //~ ERROR the type `str` cannot be indexed by `char`
}
error[E0277]: the type `str` cannot be indexed by `{integer}`
--> $DIR/str-idx.rs:3:17
|
-LL | let c: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}`
- | ^^^^ `str` cannot be indexed by `{integer}`
+LL | let _: u8 = s[4]; //~ ERROR the type `str` cannot be indexed by `{integer}`
+ | ^^^^ string indices are ranges of `usize`
|
- = help: the trait `std::ops::Index<{integer}>` is not implemented for `str`
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `{integer}`
= note: you can use `.chars().nth()` or `.bytes().nth()`
see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>
+ = note: required because of the requirements on the impl of `std::ops::Index<{integer}>` for `str`
-error: aborting due to previous error
+error[E0277]: the type `str` cannot be indexed by `{integer}`
+ --> $DIR/str-idx.rs:4:15
+ |
+LL | let _ = s.get(4); //~ ERROR the type `str` cannot be indexed by `{integer}`
+ | ^^^ string indices are ranges of `usize`
+ |
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `{integer}`
+ = note: you can use `.chars().nth()` or `.bytes().nth()`
+ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>
+
+error[E0277]: the type `str` cannot be indexed by `{integer}`
+ --> $DIR/str-idx.rs:5:15
+ |
+LL | let _ = s.get_unchecked(4); //~ ERROR the type `str` cannot be indexed by `{integer}`
+ | ^^^^^^^^^^^^^ string indices are ranges of `usize`
+ |
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `{integer}`
+ = note: you can use `.chars().nth()` or `.bytes().nth()`
+ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>
+
+error[E0277]: the type `str` cannot be indexed by `char`
+ --> $DIR/str-idx.rs:6:17
+ |
+LL | let _: u8 = s['c']; //~ ERROR the type `str` cannot be indexed by `char`
+ | ^^^^^^ string indices are ranges of `usize`
+ |
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `char`
+ = note: required because of the requirements on the impl of `std::ops::Index<char>` for `str`
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0277`.
//~^ ERROR the size for values of type
//~| ERROR the size for values of type
s[1usize] = bot();
- //~^ ERROR the type `str` cannot be mutably indexed by `usize`
+ //~^ ERROR the type `str` cannot be indexed by `usize`
+ s.get_mut(1);
+ //~^ ERROR the type `str` cannot be indexed by `{integer}`
+ s.get_unchecked_mut(1);
+ //~^ ERROR the type `str` cannot be indexed by `{integer}`
+ s['c'];
+ //~^ ERROR the type `str` cannot be indexed by `char`
}
pub fn main() {}
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: the left-hand-side of an assignment must have a statically known size
-error[E0277]: the type `str` cannot be mutably indexed by `usize`
+error[E0277]: the type `str` cannot be indexed by `usize`
--> $DIR/str-mut-idx.rs:7:5
|
LL | s[1usize] = bot();
- | ^^^^^^^^^ `str` cannot be mutably indexed by `usize`
+ | ^^^^^^^^^ string indices are ranges of `usize`
|
- = help: the trait `std::ops::IndexMut<usize>` is not implemented for `str`
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `usize`
+ = note: required because of the requirements on the impl of `std::ops::Index<usize>` for `str`
+
+error[E0277]: the type `str` cannot be indexed by `{integer}`
+ --> $DIR/str-mut-idx.rs:9:7
+ |
+LL | s.get_mut(1);
+ | ^^^^^^^ string indices are ranges of `usize`
+ |
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `{integer}`
= note: you can use `.chars().nth()` or `.bytes().nth()`
see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>
-error: aborting due to 3 previous errors
+error[E0277]: the type `str` cannot be indexed by `{integer}`
+ --> $DIR/str-mut-idx.rs:11:7
+ |
+LL | s.get_unchecked_mut(1);
+ | ^^^^^^^^^^^^^^^^^ string indices are ranges of `usize`
+ |
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `{integer}`
+ = note: you can use `.chars().nth()` or `.bytes().nth()`
+ see chapter in The Book <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>
+
+error[E0277]: the type `str` cannot be indexed by `char`
+ --> $DIR/str-mut-idx.rs:13:5
+ |
+LL | s['c'];
+ | ^^^^^^ string indices are ranges of `usize`
+ |
+ = help: the trait `std::slice::SliceIndex<str>` is not implemented for `char`
+ = note: required because of the requirements on the impl of `std::ops::Index<char>` for `str`
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+fn main() {
+ let _: usize = .3;
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+ let _: usize = .42f32;
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+ let _: usize = .5f64;
+ //~^ ERROR float literals must have an integer part
+ //~| ERROR mismatched types
+}
--- /dev/null
+error: float literals must have an integer part
+ --> $DIR/recover-invalid-float.rs:2:20
+ |
+LL | let _: usize = .3;
+ | ^^ help: must have an integer part: `0.3`
+
+error: float literals must have an integer part
+ --> $DIR/recover-invalid-float.rs:5:20
+ |
+LL | let _: usize = .42f32;
+ | ^^^^^^ help: must have an integer part: `0.42f32`
+
+error: float literals must have an integer part
+ --> $DIR/recover-invalid-float.rs:8:20
+ |
+LL | let _: usize = .5f64;
+ | ^^^^^ help: must have an integer part: `0.5f64`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-invalid-float.rs:2:20
+ |
+LL | let _: usize = .3;
+ | ^^ expected usize, found floating-point number
+ |
+ = note: expected type `usize`
+ found type `{float}`
+
+error[E0308]: mismatched types
+ --> $DIR/recover-invalid-float.rs:5:20
+ |
+LL | let _: usize = .42f32;
+ | ^^^^^^ expected usize, found f32
+
+error[E0308]: mismatched types
+ --> $DIR/recover-invalid-float.rs:8:20
+ |
+LL | let _: usize = .5f64;
+ | ^^^^^ expected usize, found f64
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
| ----------- method `bat` not found for this
...
LL | f.bat(1.0); //~ ERROR no method named
- | ^^^
- |
- = help: did you mean `bar`?
+ | ^^^ help: did you mean: `bar`
error[E0599]: no method named `is_emtpy` found for type `std::string::String` in the current scope
--> $DIR/suggest-methods.rs:21:15
|
LL | let _ = s.is_emtpy(); //~ ERROR no method named
- | ^^^^^^^^
- |
- = help: did you mean `is_empty`?
+ | ^^^^^^^^ help: did you mean: `is_empty`
error[E0599]: no method named `count_eos` found for type `u32` in the current scope
--> $DIR/suggest-methods.rs:25:19
|
LL | let _ = 63u32.count_eos(); //~ ERROR no method named
- | ^^^^^^^^^
- |
- = help: did you mean `count_zeros`?
+ | ^^^^^^^^^ help: did you mean: `count_zeros`
error[E0599]: no method named `count_o` found for type `u32` in the current scope
--> $DIR/suggest-methods.rs:28:19
--- /dev/null
+struct RGB { r: f64, g: f64, b: f64 }
+
+fn main() {
+ let (r, g, c): (f32, f32, f32) = (0., 0., 0.);
+ let _ = RGB { r, g, c };
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR struct `RGB` has no field named `c`
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:19
+ |
+LL | let _ = RGB { r, g, c };
+ | ^ expected f64, found f32
+help: you can cast an `f32` to `f64` in a lossless way
+ |
+LL | let _ = RGB { r: r.into(), g, c };
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:22
+ |
+LL | let _ = RGB { r, g, c };
+ | ^ expected f64, found f32
+help: you can cast an `f32` to `f64` in a lossless way
+ |
+LL | let _ = RGB { r, g: g.into(), c };
+ | ^^^^^^^^^^^
+
+error[E0560]: struct `RGB` has no field named `c`
+ --> $DIR/type-mismatch-struct-field-shorthand-2.rs:5:25
+ |
+LL | let _ = RGB { r, g, c };
+ | ^ help: a field with a similar name exists: `b`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0308, E0560.
+For more information about an error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+struct RGB { r: f64, g: f64, b: f64 }
+
+fn main() {
+ let (r, g, b): (f32, f32, f32) = (0., 0., 0.);
+ let _ = RGB { r: r.into(), g: g.into(), b: b.into() };
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+}
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+struct RGB { r: f64, g: f64, b: f64 }
+
+fn main() {
+ let (r, g, b): (f32, f32, f32) = (0., 0., 0.);
+ let _ = RGB { r, g, b };
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-struct-field-shorthand.rs:8:19
+ |
+LL | let _ = RGB { r, g, b };
+ | ^ expected f64, found f32
+help: you can cast an `f32` to `f64` in a lossless way
+ |
+LL | let _ = RGB { r: r.into(), g, b };
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-struct-field-shorthand.rs:8:22
+ |
+LL | let _ = RGB { r, g, b };
+ | ^ expected f64, found f32
+help: you can cast an `f32` to `f64` in a lossless way
+ |
+LL | let _ = RGB { r, g: g.into(), b };
+ | ^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> $DIR/type-mismatch-struct-field-shorthand.rs:8:25
+ |
+LL | let _ = RGB { r, g, b };
+ | ^ expected f64, found f32
+help: you can cast an `f32` to `f64` in a lossless way
+ |
+LL | let _ = RGB { r, g, b: b.into() };
+ | ^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--> $DIR/tail-typeck.rs:3:26
|
LL | fn f() -> isize { return g(); }
- | ^^^ expected isize, found usize
+ | ----- ^^^ expected isize, found usize
+ | |
+ | expected `isize` because of return type
error: aborting due to previous error
--- /dev/null
+#![feature(trait_alias)]
+
+pub trait SendSync = Send + Sync;
--- /dev/null
+// aux-build:trait_alias.rs
+
+#![feature(trait_alias)]
+
+extern crate trait_alias;
+
+use std::rc::Rc;
+use trait_alias::SendSync;
+
+fn use_alias<T: SendSync>() {}
+
+fn main() {
+ use_alias::<u32>();
+ use_alias::<Rc<u32>>();
+ //~^ ERROR `std::rc::Rc<u32>` cannot be sent between threads safely [E0277]
+ //~^^ ERROR `std::rc::Rc<u32>` cannot be shared between threads safely [E0277]
+}
--- /dev/null
+error[E0277]: `std::rc::Rc<u32>` cannot be sent between threads safely
+ --> $DIR/trait-alias-cross-crate.rs:14:5
+ |
+LL | use_alias::<Rc<u32>>();
+ | ^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<u32>` cannot be sent between threads safely
+ |
+ = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc<u32>`
+note: required by `use_alias`
+ --> $DIR/trait-alias-cross-crate.rs:10:1
+ |
+LL | fn use_alias<T: SendSync>() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: `std::rc::Rc<u32>` cannot be shared between threads safely
+ --> $DIR/trait-alias-cross-crate.rs:14:5
+ |
+LL | use_alias::<Rc<u32>>();
+ | ^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<u32>` cannot be shared between threads safely
+ |
+ = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc<u32>`
+note: required by `use_alias`
+ --> $DIR/trait-alias-cross-crate.rs:10:1
+ |
+LL | fn use_alias<T: SendSync>() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
// compile-pass
-#![feature(get_type_id)]
#![allow(dead_code)]
mod foo {
pub use self::bar::T;
fn f() {
let error = ::std::thread::spawn(|| {}).join().unwrap_err();
- error.get_type_id(); // Regression test for #21670
+ error.type_id(); // Regression test for #21670
}
error[E0382]: use of moved value: `k`
--> $DIR/try-block-bad-lifetime.rs:31:26
|
+LL | let k = &mut i;
+ | - move occurs because `k` has type `&mut i32`, which does not implement the `Copy` trait
+LL | let mut j: Result<(), &mut i32> = try {
LL | Err(k) ?;
| - value moved here
...
LL | ::std::mem::drop(k); //~ ERROR use of moved value: `k`
| ^ value used here after move
- |
- = note: move occurs because `k` has type `&mut i32`, which does not implement the `Copy` trait
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/try-block-bad-lifetime.rs:32:9
|
= help: the following implementations were found:
<i32 as std::convert::From<bool>>
+ <i32 as std::convert::From<core::num::NonZeroI32>>
<i32 as std::convert::From<i16>>
<i32 as std::convert::From<i8>>
- <i32 as std::convert::From<u16>>
- <i32 as std::convert::From<u8>>
+ and 2 others
= note: required by `std::convert::From::from`
error[E0271]: type mismatch resolving `<std::result::Result<i32, i32> as std::ops::Try>::Ok == &str`
error[E0382]: borrow of moved value: `x`
--> $DIR/try-block-maybe-bad-lifetime.rs:28:24
|
+LL | let x = String::new();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
+...
LL | ::std::mem::drop(x);
| - value moved here
LL | };
LL | println!("{}", x); //~ ERROR borrow of moved value: `x`
| ^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error[E0506]: cannot assign to `i` because it is borrowed
--> $DIR/try-block-maybe-bad-lifetime.rs:40:9
--- /dev/null
+//extern crate has_assoc_type;
+
+//fn ice(x: Box<dyn has_assoc_type::Foo<Assoc=()>>) {
+fn ice(x: Box<dyn Iterator<Item=()>>) {
+ *x //~ ERROR mismatched types [E0308]
+}
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-57673-ice-on-deref-of-boxed-trait.rs:5:5
+ |
+LL | fn ice(x: Box<dyn Iterator<Item=()>>) {
+ | - possibly return type missing here?
+LL | *x //~ ERROR mismatched types [E0308]
+ | ^^ expected (), found trait std::iter::Iterator
+ |
+ = note: expected type `()`
+ found type `(dyn std::iter::Iterator<Item=()> + 'static)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
fn bar() {
let x: Box<Bar()> = panic!();
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
+ //~| ERROR wrong number of type arguments: expected 1, found 0
}
fn main() { }
-error[E0214]: parenthesized parameters may only be used with a trait
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/unboxed-closure-sugar-used-on-struct-1.rs:8:19
|
LL | let x: Box<Bar()> = panic!();
- | ^^ only traits may use parentheses
+ | ^^ only `Fn` traits may use parentheses
-error: aborting due to previous error
+error[E0107]: wrong number of type arguments: expected 1, found 0
+ --> $DIR/unboxed-closure-sugar-used-on-struct-1.rs:8:16
+ |
+LL | let x: Box<Bar()> = panic!();
+ | ^^^^^ expected 1 type argument
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0214`.
+Some errors occurred: E0107, E0214.
+For more information about an error, try `rustc --explain E0107`.
let b = Bar::<isize, usize>::new(); // OK
let b = Bar::(isize, usize)::new(); // OK too (for the parser)
- //~^ ERROR parenthesized parameters may only be used with a trait
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
}
fn main() {}
-error[E0214]: parenthesized parameters may only be used with a trait
- --> $DIR/unboxed-closure-sugar-used-on-struct-3.rs:14:16
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
+ --> $DIR/unboxed-closure-sugar-used-on-struct-3.rs:14:18
|
LL | let b = Bar::(isize, usize)::new(); // OK too (for the parser)
- | ^^^^^^^^^^^^^^^^ only traits may use parentheses
+ | ^^^^^^^^^^^^^^
+ | |
+ | only `Fn` traits may use parentheses
+ | help: use angle brackets instead: `<isize, usize>`
error: aborting due to previous error
}
fn foo(b: Box<Bar()>) {
- //~^ ERROR parenthesized parameters may only be used with a trait
- //~| ERROR the type placeholder `_` is not allowed within types on item signatures
+ //~^ ERROR parenthesized type parameters may only be used with a `Fn` trait
+ //~| ERROR wrong number of type arguments: expected 1, found 0
}
fn main() { }
-error[E0214]: parenthesized parameters may only be used with a trait
+error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/unboxed-closure-sugar-used-on-struct.rs:7:18
|
LL | fn foo(b: Box<Bar()>) {
- | ^^ only traits may use parentheses
+ | ^^ only `Fn` traits may use parentheses
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+error[E0107]: wrong number of type arguments: expected 1, found 0
--> $DIR/unboxed-closure-sugar-used-on-struct.rs:7:15
|
LL | fn foo(b: Box<Bar()>) {
- | ^^^^^ not allowed in type signatures
+ | ^^^^^ expected 1 type argument
error: aborting due to 2 previous errors
-Some errors occurred: E0121, E0214.
-For more information about an error, try `rustc --explain E0121`.
+Some errors occurred: E0107, E0214.
+For more information about an error, try `rustc --explain E0107`.
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:22:13
|
+LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
LL | let a = u.x.0;
| ----- value moved here
LL | let b = u.y; //~ ERROR use of moved value: `u.y`
| ^^^ value used here after move
- |
- = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
--> $DIR/union-borrow-move-parent-sibling.rs:28:13
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:35:13
|
+LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
LL | let a = (u.x.0).0;
| --------- value moved here
LL | let b = u.y; //~ ERROR use of moved value: `u.y`
| ^^^ value used here after move
- |
- = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `*u.y`)
--> $DIR/union-borrow-move-parent-sibling.rs:41:13
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:48:13
|
+LL | let u = U { x: ((Vec::new(), Vec::new()), Vec::new()) };
+ | - move occurs because `u` has type `U`, which does not implement the `Copy` trait
LL | let a = *u.y;
| ---- value moved here
LL | let b = u.x; //~ ERROR use of moved value: `u.x`
| ^^^ value used here after move
- |
- = note: move occurs because `u` has type `U`, which does not implement the `Copy` trait
error: aborting due to 6 previous errors
error[E0382]: borrow of moved value: `x`
--> $DIR/unop-move-semantics.rs:8:5
|
+LL | fn move_then_borrow<T: Not<Output=T> + Clone>(x: T) {
+ | - - move occurs because `x` has type `T`, which does not implement the `Copy` trait
+ | |
+ | consider adding a `Copy` constraint to this type argument
LL | !x;
| - value moved here
LL |
LL | x.clone(); //~ ERROR: use of moved value
| ^ value borrowed here after move
- |
- = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait
error[E0505]: cannot move out of `x` because it is borrowed
--> $DIR/unop-move-semantics.rs:15:6
error[E0382]: borrow of moved value: `y`
--> $DIR/borrow-after-move.rs:22:24
|
+LL | let y = *x;
+ | - move occurs because `y` has type `str`, which does not implement the `Copy` trait
LL | drop_unsized(y);
| - value moved here
...
LL | println!("{}", &y);
| ^^ value borrowed here after move
- |
- = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/borrow-after-move.rs:30:24
error[E0382]: borrow of moved value: `y`
--> $DIR/borrow-after-move.rs:32:24
|
+LL | let y = *x;
+ | - move occurs because `y` has type `str`, which does not implement the `Copy` trait
LL | y.foo();
| - value moved here
...
LL | println!("{}", &y);
| ^^ value borrowed here after move
- |
- = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/borrow-after-move.rs:39:24
error[E0382]: use of moved value: `y`
--> $DIR/double-move.rs:20:22
|
+LL | let y = *x;
+ | - move occurs because `y` has type `str`, which does not implement the `Copy` trait
LL | drop_unsized(y);
| - value moved here
LL | drop_unsized(y); //~ERROR use of moved value
| ^ value used here after move
- |
- = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/double-move.rs:26:22
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:32:18
|
+LL | let x = "hello".to_owned().into_boxed_str();
+ | - move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait
LL | drop_unsized(x);
| - value moved here
LL | let _y = *x; //~ERROR use of moved value
| ^^ value used here after move
- |
- = note: move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `y`
--> $DIR/double-move.rs:39:9
|
+LL | let y = *x;
+ | - move occurs because `y` has type `str`, which does not implement the `Copy` trait
LL | y.foo();
| - value moved here
LL | y.foo(); //~ERROR use of moved value
| ^ value used here after move
- |
- = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:45:9
error[E0382]: borrow of moved value: `x`
--> $DIR/use-after-move-based-on-type.rs:4:20
|
+LL | let x = "Hello!".to_string();
+ | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
LL | let _y = x;
| - value moved here
LL | println!("{}", x); //~ ERROR use of moved value
| ^ value borrowed here after move
- |
- = note: move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `n`
--> $DIR/use-after-move-implicity-coerced-object.rs:28:13
|
+LL | let n: Box<_> = box Number { n: 42 };
+ | - move occurs because `n` has type `std::boxed::Box<Number>`, which does not implement the `Copy` trait
+LL | let mut l: Box<_> = box List { list: Vec::new() };
LL | l.push(n);
| - value moved here
LL | let x = n.to_string();
| ^ value borrowed here after move
- |
- = note: move occurs because `n` has type `std::boxed::Box<Number>`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `self`
--> $DIR/use-after-move-self-based-on-type.rs:12:16
|
+LL | pub fn foo(self) -> isize {
+ | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
LL | self.bar();
| ---- value moved here
LL | return self.x; //~ ERROR use of moved value: `self.x`
| ^^^^^^ value used here after move
- |
- = note: move occurs because `self` has type `S`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: use of moved value: `self`
--> $DIR/use-after-move-self.rs:10:16
|
+LL | pub fn foo(self) -> isize {
+ | ---- move occurs because `self` has type `S`, which does not implement the `Copy` trait
LL | self.bar();
| ---- value moved here
LL | return *self.x; //~ ERROR use of moved value: `*self.x`
| ^^^^^^^ value used here after move
- |
- = note: move occurs because `self` has type `S`, which does not implement the `Copy` trait
error: aborting due to previous error
error[E0382]: borrow of moved value: `start`
--> $DIR/walk-struct-literal-with.rs:16:20
|
+LL | let start = Mine{test:"Foo".to_string(), other_val:0};
+ | ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait
LL | let end = Mine{other_val:1, ..start.make_string_bar()};
| ----- value moved here
LL | println!("{}", start.test); //~ ERROR use of moved value: `start.test`
| ^^^^^^^^^^ value borrowed here after move
- |
- = note: move occurs because `start` has type `Mine`, which does not implement the `Copy` trait
error: aborting due to previous error
--> $DIR/wrong-ret-type.rs:2:49
|
LL | fn mk_int() -> usize { let i: isize = 3; return i; }
- | ^ expected usize, found isize
+ | ----- ^ expected usize, found isize
+ | |
+ | expected `usize` because of return type
error: aborting due to previous error
"wasm32-unknown-unknown",
"x86_64-apple-darwin",
"x86_64-apple-ios",
+ "x86_64-fortanix-unknown-sgx",
"x86_64-fuchsia",
"x86_64-linux-android",
"x86_64-pc-windows-gnu",
-Subproject commit 2b4a5f1f0bb6e13759e88ea9512527b0beba154f
+Subproject commit 907c0febe7045fa02dff2a35c5e36d3bd59ea50d
-Subproject commit 1b89724b4889aef631b40d52c0943bdc28e04d1d
+Subproject commit f1753522d8f3bb2d218266b4760f7a99f027f5ca
-Subproject commit 97f4cff8e904c268569d37922a27835209deff5d
+Subproject commit 1cd85d2a2767b37f9869b719a74e3da99087c31a
-Subproject commit ae0d89a08d091ba1563b571739768a09d4cd3d69
+Subproject commit c9d25b667af766e8fe6d3b6168a5f99a0e4d722a
"sspi",
"synchapi",
"sysinfoapi",
+ "threadpoollegacyapiset",
"timezoneapi",
"userenv",
"winbase",