Stabilize `std::hint::unreachable_unchecked`.
Closes #43751.
#### `[rust]`:
- `debuginfo = true` - Build a compiler with debuginfo. Makes building rustc slower, but then you can use a debugger to debug `rustc`.
- `debuginfo-lines = true` - An alternative to `debuginfo = true` that doesn't let you use a debugger, but doesn't make building rustc slower and still gives you line numbers in backtraces.
+- `debuginfo-tools = true` - Build the extended tools with debuginfo.
- `debug-assertions = true` - Makes the log output of `debug!` work.
- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust, but makes the stage1 compiler x100 slower.
### Building
[building]: #building
+A default configuration shall use around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB.
+
Dependencies
- [build dependencies](README.md#building-from-source)
- `gdb` 6.2.0 minimum, 7.1 or later recommended for test builds
# standard library.
#debuginfo-only-std = false
+# Enable debuginfo for the extended tools: cargo, rls, rustfmt
+# Adding debuginfo makes them several times larger.
+#debuginfo-tools = false
+
# Whether or not jemalloc is built and enabled
#use-jemalloc = true
name = "alloc_jemalloc"
version = "0.0.0"
dependencies = [
- "alloc_system 0.0.0",
"build_helper 0.1.0",
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
"libc 0.0.0",
[[package]]
name = "arena"
version = "0.0.0"
+dependencies = [
+ "rustc_data_structures 0.0.0",
+]
[[package]]
name = "arrayvec"
[[package]]
name = "backtrace"
-version = "0.3.5"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "build-manifest"
version = "0.1.0"
dependencies = [
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "cargo"
-version = "0.27.0"
+version = "0.28.0"
dependencies = [
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crates-io 0.16.0",
"crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "cc"
-version = "1.0.9"
+version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "clippy"
-version = "0.0.193"
+version = "0.0.195"
dependencies = [
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy-mini-macro-test 0.2.0",
- "clippy_lints 0.0.193",
+ "clippy_lints 0.0.195",
"compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "clippy_lints"
version = "0.0.193"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "clippy_lints"
+version = "0.0.195"
dependencies = [
"if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "cmake"
-version = "0.1.29"
+version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "compiler_builtins"
version = "0.0.0"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"core 0.0.0",
]
version = "0.0.0"
dependencies = [
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
name = "crates-io"
version = "0.16.0"
dependencies = [
- "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
dependencies = [
"commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "curl"
-version = "0.4.11"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)",
- "schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "socket2 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "curl-sys"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "elasticlunr-rs"
-version = "1.0.0"
+version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "env_logger"
-version = "0.5.6"
+version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "filetime"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "find_all_refs_no_cfg_test"
version = "0.1.0"
"libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
dependencies = [
"futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
- "curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
+ "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
dependencies = [
"phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "mdbook"
-version = "0.1.5"
+version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "elasticlunr-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"handlebars 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "socket2 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl"
-version = "0.10.5"
+version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "openssl-sys"
-version = "0.9.27"
+version = "0.9.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "proc-macro2"
-version = "0.3.1"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
name = "profiler_builtins"
version = "0.0.0"
dependencies = [
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
]
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)",
dependencies = [
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
-version = "0.5.3"
+version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "remove_dir_all"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
name = "rls"
version = "0.126.0"
dependencies = [
- "cargo 0.27.0",
+ "cargo 0.28.0",
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy_lints 0.0.193",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clippy_lints 0.0.193 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfmt-nightly 0.4.2",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
dependencies = [
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.0"
dependencies = [
"clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.0.0"
dependencies = [
"arena 0.0.0",
- "backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
-version = "98.0.0"
+version = "103.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "98.0.0"
+version = "103.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_errors"
-version = "98.0.0"
+version = "103.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-serialize"
-version = "98.0.0"
+version = "103.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-ap-syntax"
-version = "98.0.0"
+version = "103.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-syntax_pos"
-version = "98.0.0"
+version = "103.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
]
dependencies = [
"ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"arena 0.0.0",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"build_helper 0.1.0",
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_cratesio_shim 0.0.0",
]
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
]
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
]
version = "0.0.0"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"alloc 0.0.0",
"alloc_system 0.0.0",
"build_helper 0.1.0",
- "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"compiler_builtins 0.0.0",
"core 0.0.0",
]
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "schannel"
-version = "0.1.11"
+version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "serde"
-version = "1.0.37"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
-version = "1.0.37"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
-version = "0.23.0"
+version = "0.23.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
-version = "1.0.13"
+version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "socket2"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
"precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "strum"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "strum_macros"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "syn"
version = "0.11.11"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tar"
-version = "0.4.14"
+version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "xattr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tempfile"
-version = "3.0.0"
+version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
name = "tidy"
version = "0.1.0"
dependencies = [
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "toml"
-version = "0.4.5"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "vcpkg"
-version = "0.2.2"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
[[package]]
name = "xattr"
-version = "0.1.11"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4"
-"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"
+"checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e"
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
"checksum cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "be1057b8462184f634c3a208ee35b0f935cfd94b694b26deadccd98732088d7b"
"checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3"
-"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc"
+"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873"
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
-"checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
+"checksum clippy_lints 0.0.193 (registry+https://github.com/rust-lang/crates.io-index)" = "ecc6358b7e2e0c99c24ea88edc43c5fe1638f186255adb92d2302ae71027560f"
+"checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c"
"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
"checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2"
"checksum compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "608d9d3ccc45b63bf337d2ff5e65def5a5a52c187122232509f6b72707f61b1b"
"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4"
-"checksum curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b70fd6394677d3c0e239ff4be6f2b3176e171ffd1c23ffdc541e78dea2b8bb5e"
-"checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961"
+"checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0"
+"checksum curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f7738d877ec81040305d5bb91976ac594f564f5e455dc02a29a23c1d00fe6f"
"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71"
"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
-"checksum elasticlunr-rs 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "19ab5f8db0ffb76b5d87454566ceb502c3650e29057c053f93e884d3b884e344"
+"checksum elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4511b63d69dd5d31e8e29aed2c132c413f87acea8035d0584801feaab9dd1f0f"
"checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834"
"checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
-"checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad"
+"checksum env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "be27f8ea102a7182093a80d98f0b78623b580eda8791cbe8e2345fe6e57567a6"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
"checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f"
+"checksum filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08530a39af0bd442c40aabb9e854f442a83bd2403feb1ed58fbe982dec2385f3"
"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43"
"checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "326d0861da5681a13c19a00952a56c254dd04f00eb944e506fdb36e93ae6f1ca"
+"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364"
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
"checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113"
-"checksum openssl 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1636c9f1d78af9cbcc50e523bfff4a30274108aad5e86761afd4d31e4e184fa7"
+"checksum openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)" = "63246f69962e8d5ef865f82a65241d6483c8a2905a1801e2f7feb5d187d51320"
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
-"checksum openssl-sys 0.9.27 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdc5c4a02e69ce65046f1763a0181107038e02176233acb0b3351d7cc588f9"
+"checksum openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)" = "0bbd90640b148b46305c1691eed6039b5c8509bed16991e3562a01eeb76902a3"
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
"checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd"
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
-"checksum proc-macro2 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "388d7ea47318c5ccdeb9ba6312cee7d3f65dd2804be8580a170fce410d50b786"
+"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
-"checksum regex-syntax 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b2550876c31dc914696a6c2e01cbce8afba79a93c8ae979d2fe051c0230b3756"
-"checksum remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfc5b3ce5d5ea144bb04ebd093a9e14e9765bcfec866aecda9b6dec43b3d1e24"
+"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
+"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rls-analysis 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4b9a3a3f2345854e39768e6425d1c893855da217183d1c0b3ff6f1664b6b6d"
"checksum rls-blacklist 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "156cee9c1750b2e97d404dd0506c4780b7a2d615164f49874013807fb3cbfe5e"
"checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510"
"checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb"
-"checksum rustc-ap-rustc_cratesio_shim 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b576584b70d2b0c5f8a82c98a3eb39ef95eaf9187b90ad8858a149a55e94e85"
-"checksum rustc-ap-rustc_data_structures 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be7c3367229e1497a65c754188842cc02f5e50e93cced2168f621c170cd08ee5"
-"checksum rustc-ap-rustc_errors 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6440cf26fe79acf54d9d0991835a2eabec4b7039da153889a16f50bda5a7ef"
-"checksum rustc-ap-serialize 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3854db2139a75e4d1898289c08dcd8487bec318975877c6268551afccab8844b"
-"checksum rustc-ap-syntax 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1852c80f5195a3da20023205bd1202254bf0282b9ffbaaa029a6beed31db3d"
-"checksum rustc-ap-syntax_pos 98.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc60c04eccec0304b3684584b696669b2cfdfbeacee615bb5a9f431aafa64ab9"
+"checksum rustc-ap-rustc_cratesio_shim 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "463834ac5ea777cb56c073586675fac37292f8425aafb3757efca7e6a76545aa"
+"checksum rustc-ap-rustc_data_structures 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d256eeab1b8639c2a1fd341e54f3613f8150bc262e4ec9361a29bbcb162906d"
+"checksum rustc-ap-rustc_errors 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf6dd73033bb512845a6df347174c65ad430c92ecd35527e24d8bb186f5664ee"
+"checksum rustc-ap-serialize 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "356d338dbe538c7d6428296872d5d68da8f091e34eb89bca3b3f245ed0785e5e"
+"checksum rustc-ap-syntax 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f02edede4ba70963a7dac2308876f03f76f9edd48a035e5abc8fa37c57a77c8"
+"checksum rustc-ap-syntax_pos 103.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad8e50d4c38121fa8ded3ffbf94926ec74c95f24316c3b80de84fbfb42c005cf"
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
-"checksum schannel 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fbaffce35eb61c5b00846e73128b0cd62717e7c0ec46abbec132370d013975b4"
+"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d3bcee660dcde8f52c3765dd9ca5ee36b4bf35470a738eb0bd5a8752b0389645"
-"checksum serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "f1711ab8b208541fa8de00425f6a577d90f27bb60724d2bb5fd911314af9668f"
-"checksum serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89b340a48245bc03ddba31d0ff1709c118df90edc6adabaca4aac77aea181cce"
+"checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248"
+"checksum serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "fb88f3c93214390ed9ef3ad15ce303c36684a915a97a30883ac6ca261bf67dc7"
+"checksum serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d30c4596450fd7bbda79ef15559683f9a79ac0193ea819db90000d7e1cae794"
"checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"
-"checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74"
+"checksum serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7bf1cbb1387028a13739cb018ee0d9b3db534f22ca3c84a5904f7eadfde14e75"
"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
-"checksum socket2 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "71ebbe82fcdd697244ba7fe6e05e63b5c45910c3927e28469a04947494ff48d8"
+"checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39cb4173bcbd1319da31faa5468a7e3870683d7a237150b0b0aaafd546f6ad12"
"checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7"
"checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
+"checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545"
+"checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
"checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b"
"checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac"
"checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
-"checksum tar 0.4.14 (registry+https://github.com/rust-lang/crates.io-index)" = "1605d3388ceb50252952ffebab4b5dc43017ead7e4481b175961c283bb951195"
+"checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-"checksum tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "439d9a7c00f98b1b5ee730039bf5b1f9203d508690e3c76b509e7ad59f8f7c99"
+"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c"
"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561"
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
-"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e"
+"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9"
"checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3"
"checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c"
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
-"checksum vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9e0a7d8bed3178a8fb112199d466eeca9ed09a14ba8ad67718179b4fd5487d0b"
+"checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767"
-"checksum xattr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "5f04de8a1346489a2f9e9bd8526b73d135ec554227b17568456e86aa35b6f3fc"
+"checksum xattr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb373b92de38a4301d66bec009929b4fb83120ea1c4a401be89dbe0b9777443"
"checksum xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df591c3504d014dd791d998123ed00a476c7e26dc6b2e873cb55c6ac9e59fa"
"checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992"
eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset,
self.name, builder.config.exclude);
}
- let build = builder.build;
- let hosts = &build.hosts;
+ let hosts = &builder.hosts;
// Determine the targets participating in this rule.
let targets = if self.only_hosts {
- if !build.config.run_host_only {
+ if !builder.config.run_host_only {
return; // don't run anything
} else {
- &build.hosts
+ &builder.hosts
}
} else {
- &build.targets
+ &builder.targets
};
for host in hosts {
tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient,
tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
native::Llvm, tool::Rustfmt, tool::Miri, native::Lld),
- Kind::Check => describe!(check::Std, check::Test, check::Rustc),
+ Kind::Check => describe!(check::Std, check::Test, check::Rustc, check::CodegenBackend,
+ check::Rustdoc),
Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass,
test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind,
test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo,
test::TheBook, test::UnstableBook,
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme,
// Run run-make last, since these won't pass without make on Windows
- test::RunMake),
+ test::RunMake, test::RustdocUi),
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc,
pub fn sysroot_codegen_backends(&self, compiler: Compiler) -> PathBuf {
self.sysroot_libdir(compiler, compiler.host)
- .with_file_name(self.build.config.rust_codegen_backends_dir.clone())
+ .with_file_name(self.config.rust_codegen_backends_dir.clone())
}
/// Returns the compiler's libdir where it stores the dynamic libraries that
/// Windows.
pub fn rustc_libdir(&self, compiler: Compiler) -> PathBuf {
if compiler.is_snapshot(self) {
- self.build.rustc_snapshot_libdir()
+ self.rustc_snapshot_libdir()
} else {
self.sysroot(compiler).join(libdir(&compiler.host))
}
let compiler = self.compiler(self.top_stage, host);
cmd.env("RUSTC_STAGE", compiler.stage.to_string())
.env("RUSTC_SYSROOT", self.sysroot(compiler))
- .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.build.build))
- .env("CFG_RELEASE_CHANNEL", &self.build.config.channel)
+ .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build))
+ .env("CFG_RELEASE_CHANNEL", &self.config.channel)
.env("RUSTDOC_REAL", self.rustdoc(host))
- .env("RUSTDOC_CRATE_VERSION", self.build.rust_version())
+ .env("RUSTDOC_CRATE_VERSION", self.rust_version())
.env("RUSTC_BOOTSTRAP", "1");
- if let Some(linker) = self.build.linker(host) {
+ if let Some(linker) = self.linker(host) {
cmd.env("RUSTC_TARGET_LINKER", linker);
}
cmd
.arg("--target")
.arg(target);
+ // Set a flag for `check` so that certain build scripts can do less work
+ // (e.g. not building/requiring LLVM).
+ if cmd == "check" {
+ cargo.env("RUST_CHECK", "1");
+ }
+
// If we were invoked from `make` then that's already got a jobserver
// set up for us so no need to tell Cargo about jobs all over again.
if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() {
.env("TEST_MIRI", self.config.test_miri.to_string())
.env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
- if let Some(host_linker) = self.build.linker(compiler.host) {
+ if let Some(host_linker) = self.linker(compiler.host) {
cargo.env("RUSTC_HOST_LINKER", host_linker);
}
- if let Some(target_linker) = self.build.linker(target) {
+ if let Some(target_linker) = self.linker(target) {
cargo.env("RUSTC_TARGET_LINKER", target_linker);
}
if let Some(ref error_format) = self.config.rustc_error_format {
cargo.env("RUSTC_ERROR_FORMAT", error_format);
}
if cmd != "build" && cmd != "check" {
- cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.build.build)));
+ cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build)));
}
- if mode != Mode::Tool {
- // Tools don't get debuginfo right now, e.g. cargo and rls don't
- // get compiled with debuginfo.
- // Adding debuginfo increases their sizes by a factor of 3-4.
+ if mode == Mode::Tool {
+ // Tools like cargo and rls don't get debuginfo by default right now, but this can be
+ // enabled in the config. Adding debuginfo makes them several times larger.
+ if self.config.rust_debuginfo_tools {
+ cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string());
+ cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string());
+ }
+ } else {
cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string());
cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string());
cargo.env("RUSTC_FORCE_UNSTABLE", "1");
//
// If LLVM support is disabled we need to use the snapshot compiler to compile
// build scripts, as the new compiler doesn't support executables.
- if mode == Mode::Libstd || !self.build.config.llvm_enabled {
+ if mode == Mode::Libstd || !self.config.llvm_enabled {
cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc)
.env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
} else {
}
}
- if mode == Mode::Libstd && self.config.extended && compiler.is_final_stage(self) {
+ if cmd == "build" && mode == Mode::Libstd
+ && self.config.extended && compiler.is_final_stage(self)
+ {
cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string());
}
// For `cargo doc` invocations, make rustdoc print the Rust version into the docs
- cargo.env("RUSTDOC_CRATE_VERSION", self.build.rust_version());
+ cargo.env("RUSTDOC_CRATE_VERSION", self.rust_version());
// Environment variables *required* throughout the build
//
cargo.env("CFG_COMPILER_HOST_TRIPLE", target);
// Set this for all builds to make sure doc builds also get it.
- cargo.env("CFG_RELEASE_CHANNEL", &self.build.config.channel);
+ cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
// This one's a bit tricky. As of the time of this writing the compiler
// links to the `winapi` crate on crates.io. This crate provides raw
cargo
}
- /// Ensure that a given step is built, returning it's output. This will
+ /// Ensure that a given step is built, returning its output. This will
/// cache the step, so it is safe (and good!) to call this as often as
/// needed to ensure that all dependencies are built.
pub fn ensure<S: Step>(&'a self, step: S) -> S::Output {
panic!(out);
}
if let Some(out) = self.cache.get(&step) {
- self.build.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
+ self.verbose(&format!("{}c {:?}", " ".repeat(stack.len()), step));
{
let mut graph = self.graph.borrow_mut();
return out;
}
- self.build.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
+ self.verbose(&format!("{}> {:?}", " ".repeat(stack.len()), step));
stack.push(Box::new(step.clone()));
}
self.parent.set(prev_parent);
- if self.build.config.print_step_timings && dur > Duration::from_millis(100) {
+ if self.config.print_step_timings && dur > Duration::from_millis(100) {
println!("[TIMING] {:?} -- {}.{:03}",
step,
dur.as_secs(),
let cur_step = stack.pop().expect("step stack empty");
assert_eq!(cur_step.downcast_ref(), Some(&step));
}
- self.build.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
+ self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step));
self.cache.put(step, out.clone());
out
}
let mut cfg = cc::Build::new();
cfg.cargo_metadata(false).opt_level(2).warnings(false).debug(false)
.target(&target).host(&build.build);
- if target.contains("msvc") {
- cfg.static_crt(true);
+ match build.crt_static(target) {
+ Some(a) => { cfg.static_crt(a); }
+ None => {
+ if target.contains("msvc") {
+ cfg.static_crt(true);
+ }
+ if target.contains("musl") {
+ cfg.static_flag(true);
+ }
+ }
}
let config = build.config.target_config.get(&target);
cc2ar(compiler.path(), &target)
};
- build.verbose(&format!("CC_{} = {:?}", &target, compiler.path()));
build.cc.insert(target, compiler);
+ build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
+ build.verbose(&format!("CFLAGS_{} = {:?}", &target, build.cflags(target)));
if let Some(ar) = ar {
build.verbose(&format!("AR_{} = {:?}", &target, ar));
build.ar.insert(target, ar);
//! Implementation of compiling the compiler and standard library, in "check" mode.
-use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, add_to_sysroot};
+use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot};
use builder::{RunConfig, Builder, ShouldRun, Step};
-use {Build, Compiler, Mode};
-use cache::Interned;
+use tool::{self, prepare_tool_cargo};
+use {Compiler, Mode};
+use cache::{INTERNER, Interned};
use std::path::PathBuf;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
}
fn run(self, builder: &Builder) {
- let build = builder.build;
let target = self.target;
- let compiler = builder.compiler(0, build.build);
+ let compiler = builder.compiler(0, builder.config.build);
+
+ let out_dir = builder.stage_out(compiler, Mode::Libstd);
+ builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
- let out_dir = build.stage_out(compiler, Mode::Libstd);
- build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check");
std_cargo(builder, &compiler, target, &mut cargo);
- let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
+ let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
println!("Checking std artifacts ({} -> {})", &compiler.host, target);
- run_cargo(build,
+ run_cargo(builder,
&mut cargo,
- &libstd_stamp(build, compiler, target),
+ &libstd_stamp(builder, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
- add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target));
+ add_to_sysroot(&builder, &libdir, &libstd_stamp(builder, compiler, target));
}
}
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
- let build = builder.build;
- let compiler = builder.compiler(0, build.build);
+ let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
let stage_out = builder.stage_out(compiler, Mode::Librustc);
- build.clear_if_dirty(&stage_out, &libstd_stamp(build, compiler, target));
- build.clear_if_dirty(&stage_out, &libtest_stamp(build, compiler, target));
+ builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target));
+ builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
- rustc_cargo(build, &mut cargo);
+ rustc_cargo(builder, &mut cargo);
- let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
+ let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
println!("Checking compiler artifacts ({} -> {})", &compiler.host, target);
- run_cargo(build,
+ run_cargo(builder,
&mut cargo,
- &librustc_stamp(build, compiler, target),
+ &librustc_stamp(builder, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
- add_to_sysroot(&build, &libdir, &librustc_stamp(build, compiler, target));
+ add_to_sysroot(&builder, &libdir, &librustc_stamp(builder, compiler, target));
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct CodegenBackend {
+ pub target: Interned<String>,
+ pub backend: Interned<String>,
+}
+
+impl Step for CodegenBackend {
+ type Output = ();
+ const ONLY_HOSTS: bool = true;
+ const DEFAULT: bool = true;
+
+ fn should_run(run: ShouldRun) -> ShouldRun {
+ run.all_krates("rustc_trans")
+ }
+
+ fn make_run(run: RunConfig) {
+ let backend = run.builder.config.rust_codegen_backends.get(0);
+ let backend = backend.cloned().unwrap_or_else(|| {
+ INTERNER.intern_str("llvm")
+ });
+ run.builder.ensure(CodegenBackend {
+ target: run.target,
+ backend,
+ });
+ }
+
+ fn run(self, builder: &Builder) {
+ let compiler = builder.compiler(0, builder.config.build);
+ let target = self.target;
+ let backend = self.backend;
+
+ let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check");
+ let features = builder.rustc_features().to_string();
+ cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_trans/Cargo.toml"));
+ rustc_cargo_env(builder, &mut cargo);
+
+ // We won't build LLVM if it's not available, as it shouldn't affect `check`.
+
+ let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
+ run_cargo(builder,
+ cargo.arg("--features").arg(features),
+ &codegen_backend_stamp(builder, compiler, target, backend),
+ true);
}
}
}
fn run(self, builder: &Builder) {
- let build = builder.build;
+ let compiler = builder.compiler(0, builder.config.build);
let target = self.target;
- let compiler = builder.compiler(0, build.build);
- let out_dir = build.stage_out(compiler, Mode::Libtest);
- build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
+ let out_dir = builder.stage_out(compiler, Mode::Libtest);
+ builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
+
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check");
- test_cargo(build, &compiler, target, &mut cargo);
+ test_cargo(builder, &compiler, target, &mut cargo);
- let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
+ let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
println!("Checking test artifacts ({} -> {})", &compiler.host, target);
- run_cargo(build,
+ run_cargo(builder,
&mut cargo,
- &libtest_stamp(build, compiler, target),
+ &libtest_stamp(builder, compiler, target),
true);
let libdir = builder.sysroot_libdir(compiler, target);
- add_to_sysroot(&build, &libdir, &libtest_stamp(build, compiler, target));
+ add_to_sysroot(builder, &libdir, &libtest_stamp(builder, compiler, target));
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Rustdoc {
+ pub target: Interned<String>,
+}
+
+impl Step for Rustdoc {
+ type Output = ();
+ const ONLY_HOSTS: bool = true;
+ const DEFAULT: bool = true;
+
+ fn should_run(run: ShouldRun) -> ShouldRun {
+ run.path("src/tools/rustdoc")
+ }
+
+ fn make_run(run: RunConfig) {
+ run.builder.ensure(Rustdoc {
+ target: run.target,
+ });
+ }
+
+ fn run(self, builder: &Builder) {
+ let compiler = builder.compiler(0, builder.config.build);
+ let target = self.target;
+
+ let mut cargo = prepare_tool_cargo(builder,
+ compiler,
+ target,
+ "check",
+ "src/tools/rustdoc");
+
+ let _folder = builder.fold_output(|| format!("stage{}-rustdoc", compiler.stage));
+ println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target);
+ run_cargo(builder,
+ &mut cargo,
+ &rustdoc_stamp(builder, compiler, target),
+ true);
+
+ let libdir = builder.sysroot_libdir(compiler, target);
+ add_to_sysroot(&builder, &libdir, &rustdoc_stamp(builder, compiler, target));
+
+ builder.ensure(tool::CleanTools {
+ compiler,
+ target,
+ mode: Mode::Tool,
+ });
}
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
-pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
- build.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp")
+pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp")
}
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
-pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
- build.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp")
+pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
-pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
- build.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp")
+pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp")
+}
+
+/// Cargo's output path for librustc_trans in a given stage, compiled by a particular
+/// compiler for the specified target and backend.
+fn codegen_backend_stamp(builder: &Builder,
+ compiler: Compiler,
+ target: Interned<String>,
+ backend: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Librustc, target)
+ .join(format!(".librustc_trans-{}-check.stamp", backend))
+}
+
+/// Cargo's output path for rustdoc in a given stage, compiled by a particular
+/// compiler for the specified target.
+pub fn rustdoc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Tool, target).join(".rustdoc-check.stamp")
}
use serde_json;
use util::{exe, libdir, is_dylib, CiEnv};
-use {Build, Compiler, Mode};
+use {Compiler, Mode};
use native;
use tool;
/// using the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
- let build = builder.build;
let target = self.target;
let compiler = self.compiler;
builder.ensure(StartupObjects { compiler, target });
- if build.force_use_stage1(compiler, target) {
- let from = builder.compiler(1, build.build);
+ if builder.force_use_stage1(compiler, target) {
+ let from = builder.compiler(1, builder.config.build);
builder.ensure(Std {
compiler: from,
target,
// still contain the musl startup objects.
if target.contains("musl") {
let libdir = builder.sysroot_libdir(compiler, target);
- copy_musl_third_party_objects(build, target, &libdir);
+ copy_musl_third_party_objects(builder, target, &libdir);
}
builder.ensure(StdLink {
if target.contains("musl") {
let libdir = builder.sysroot_libdir(compiler, target);
- copy_musl_third_party_objects(build, target, &libdir);
+ copy_musl_third_party_objects(builder, target, &libdir);
}
- let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
- build.clear_if_dirty(&out_dir, &builder.rustc(compiler));
+ let out_dir = builder.cargo_out(compiler, Mode::Libstd, target);
+ builder.clear_if_dirty(&out_dir, &builder.rustc(compiler));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build");
std_cargo(builder, &compiler, target, &mut cargo);
- let _folder = build.fold_output(|| format!("stage{}-std", compiler.stage));
- build.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage,
+ let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage));
+ builder.info(&format!("Building stage{} std artifacts ({} -> {})", compiler.stage,
&compiler.host, target));
- run_cargo(build,
+ run_cargo(builder,
&mut cargo,
- &libstd_stamp(build, compiler, target),
+ &libstd_stamp(builder, compiler, target),
false);
builder.ensure(StdLink {
- compiler: builder.compiler(compiler.stage, build.build),
+ compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
target,
});
/// with a glibc-targeting toolchain, given we have the appropriate startup
/// files. As those shipped with glibc won't work, copy the ones provided by
/// musl so we have them on linux-gnu hosts.
-fn copy_musl_third_party_objects(build: &Build,
+fn copy_musl_third_party_objects(builder: &Builder,
target: Interned<String>,
into: &Path) {
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
- build.copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
+ builder.copy(&builder.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
}
}
/// Configure cargo to compile the standard library, adding appropriate env vars
/// and such.
-pub fn std_cargo(build: &Builder,
+pub fn std_cargo(builder: &Builder,
compiler: &Compiler,
target: Interned<String>,
cargo: &mut Command) {
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
}
- if build.no_std(target) == Some(true) {
+ if builder.no_std(target) == Some(true) {
// for no-std targets we only compile a few no_std crates
cargo.arg("--features").arg("c mem")
.args(&["-p", "alloc"])
.args(&["-p", "compiler_builtins"])
.args(&["-p", "std_unicode"])
.arg("--manifest-path")
- .arg(build.src.join("src/rustc/compiler_builtins_shim/Cargo.toml"));
+ .arg(builder.src.join("src/rustc/compiler_builtins_shim/Cargo.toml"));
} else {
- let mut features = build.std_features();
+ let mut features = builder.std_features();
// When doing a local rebuild we tell cargo that we're stage1 rather than
// stage0. This works fine if the local rust and being-built rust have the
// same view of what the default allocator is, but fails otherwise. Since
// we don't have a way to express an allocator preference yet, work
// around the issue in the case of a local rebuild with jemalloc disabled.
- if compiler.stage == 0 && build.local_rebuild && !build.config.use_jemalloc {
+ if compiler.stage == 0 && builder.local_rebuild && !builder.config.use_jemalloc {
features.push_str(" force_alloc_system");
}
- if compiler.stage != 0 && build.config.sanitizers {
+ if compiler.stage != 0 && builder.config.sanitizers {
// This variable is used by the sanitizer runtime crates, e.g.
// rustc_lsan, to build the sanitizer runtime from C code
// When this variable is missing, those crates won't compile the C code,
// missing
// We also only build the runtimes when --enable-sanitizers (or its
// config.toml equivalent) is used
- let llvm_config = build.ensure(native::Llvm {
- target: build.config.build,
+ let llvm_config = builder.ensure(native::Llvm {
+ target: builder.config.build,
emscripten: false,
});
cargo.env("LLVM_CONFIG", llvm_config);
cargo.arg("--features").arg(features)
.arg("--manifest-path")
- .arg(build.src.join("src/libstd/Cargo.toml"));
+ .arg(builder.src.join("src/libstd/Cargo.toml"));
- if let Some(target) = build.config.target_config.get(&target) {
+ if let Some(target) = builder.config.target_config.get(&target) {
if let Some(ref jemalloc) = target.jemalloc {
cargo.env("JEMALLOC_OVERRIDE", jemalloc);
}
}
if target.contains("musl") {
- if let Some(p) = build.musl_root(target) {
+ if let Some(p) = builder.musl_root(target) {
cargo.env("MUSL_ROOT", p);
}
}
/// libraries for `target`, and this method will find them in the relevant
/// output directory.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target_compiler = self.target_compiler;
let target = self.target;
- build.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})",
+ builder.info(&format!("Copying stage{} std from stage{} ({} -> {} / {})",
target_compiler.stage,
compiler.stage,
&compiler.host,
target_compiler.host,
target));
let libdir = builder.sysroot_libdir(target_compiler, target);
- add_to_sysroot(&build, &libdir, &libstd_stamp(build, compiler, target));
+ add_to_sysroot(builder, &libdir, &libstd_stamp(builder, compiler, target));
- if build.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
+ if builder.config.sanitizers && compiler.stage != 0 && target == "x86_64-apple-darwin" {
// The sanitizers are only built in stage1 or above, so the dylibs will
// be missing in stage0 and causes panic. See the `std()` function above
// for reason why the sanitizers are not built in stage0.
- copy_apple_sanitizer_dylibs(&build, &build.native_dir(target), "osx", &libdir);
+ copy_apple_sanitizer_dylibs(builder, &builder.native_dir(target), "osx", &libdir);
}
builder.ensure(tool::CleanTools {
}
}
-fn copy_apple_sanitizer_dylibs(build: &Build, native_dir: &Path, platform: &str, into: &Path) {
+fn copy_apple_sanitizer_dylibs(builder: &Builder, native_dir: &Path, platform: &str, into: &Path) {
for &sanitizer in &["asan", "tsan"] {
let filename = format!("libclang_rt.{}_{}_dynamic.dylib", sanitizer, platform);
let mut src_path = native_dir.join(sanitizer);
src_path.push("lib");
src_path.push("darwin");
src_path.push(&filename);
- build.copy(&src_path, &into.join(filename));
+ builder.copy(&src_path, &into.join(filename));
}
}
/// files, so we just use the nightly snapshot compiler to always build them (as
/// no other compilers are guaranteed to be available).
fn run(self, builder: &Builder) {
- let build = builder.build;
let for_compiler = self.compiler;
let target = self.target;
if !target.contains("pc-windows-gnu") {
return
}
- let src_dir = &build.src.join("src/rtstartup");
- let dst_dir = &build.native_dir(target).join("rtstartup");
+ let src_dir = &builder.src.join("src/rtstartup");
+ let dst_dir = &builder.native_dir(target).join("rtstartup");
let sysroot_dir = &builder.sysroot_libdir(for_compiler, target);
t!(fs::create_dir_all(dst_dir));
let src_file = &src_dir.join(file.to_string() + ".rs");
let dst_file = &dst_dir.join(file.to_string() + ".o");
if !up_to_date(src_file, dst_file) {
- let mut cmd = Command::new(&build.initial_rustc);
- build.run(cmd.env("RUSTC_BOOTSTRAP", "1")
+ let mut cmd = Command::new(&builder.initial_rustc);
+ builder.run(cmd.env("RUSTC_BOOTSTRAP", "1")
.arg("--cfg").arg("stage0")
.arg("--target").arg(target)
.arg("--emit=obj")
.arg(src_file));
}
- build.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
+ builder.copy(dst_file, &sysroot_dir.join(file.to_string() + ".o"));
}
for obj in ["crt2.o", "dllcrt2.o"].iter() {
- let src = compiler_file(build,
- build.cc(target),
+ let src = compiler_file(builder,
+ builder.cc(target),
target,
obj);
- build.copy(&src, &sysroot_dir.join(obj));
+ builder.copy(&src, &sysroot_dir.join(obj));
}
}
}
/// the build using the `compiler` targeting the `target` architecture. The
/// artifacts created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
- let build = builder.build;
let target = self.target;
let compiler = self.compiler;
builder.ensure(Std { compiler, target });
- if build.force_use_stage1(compiler, target) {
+ if builder.force_use_stage1(compiler, target) {
builder.ensure(Test {
- compiler: builder.compiler(1, build.build),
+ compiler: builder.compiler(1, builder.config.build),
target,
});
- build.info(&format!("Uplifting stage1 test ({} -> {})", &build.build, target));
+ builder.info(
+ &format!("Uplifting stage1 test ({} -> {})", builder.config.build, target));
builder.ensure(TestLink {
- compiler: builder.compiler(1, build.build),
+ compiler: builder.compiler(1, builder.config.build),
target_compiler: compiler,
target,
});
return;
}
- let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
- build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target));
+ let out_dir = builder.cargo_out(compiler, Mode::Libtest, target);
+ builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build");
- test_cargo(build, &compiler, target, &mut cargo);
+ test_cargo(builder, &compiler, target, &mut cargo);
- let _folder = build.fold_output(|| format!("stage{}-test", compiler.stage));
- build.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage,
+ let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage));
+ builder.info(&format!("Building stage{} test artifacts ({} -> {})", compiler.stage,
&compiler.host, target));
- run_cargo(build,
+ run_cargo(builder,
&mut cargo,
- &libtest_stamp(build, compiler, target),
+ &libtest_stamp(builder, compiler, target),
false);
builder.ensure(TestLink {
- compiler: builder.compiler(compiler.stage, build.build),
+ compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
target,
});
}
/// Same as `std_cargo`, but for libtest
-pub fn test_cargo(build: &Build,
+pub fn test_cargo(builder: &Builder,
_compiler: &Compiler,
_target: Interned<String>,
cargo: &mut Command) {
cargo.env("MACOSX_DEPLOYMENT_TARGET", target);
}
cargo.arg("--manifest-path")
- .arg(build.src.join("src/libtest/Cargo.toml"));
+ .arg(builder.src.join("src/libtest/Cargo.toml"));
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Same as `std_link`, only for libtest
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target_compiler = self.target_compiler;
let target = self.target;
- build.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})",
+ builder.info(&format!("Copying stage{} test from stage{} ({} -> {} / {})",
target_compiler.stage,
compiler.stage,
&compiler.host,
target_compiler.host,
target));
- add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target),
- &libtest_stamp(build, compiler, target));
+ add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target),
+ &libtest_stamp(builder, compiler, target));
builder.ensure(tool::CleanTools {
compiler: target_compiler,
target,
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
builder.ensure(Test { compiler, target });
- if build.force_use_stage1(compiler, target) {
+ if builder.force_use_stage1(compiler, target) {
builder.ensure(Rustc {
- compiler: builder.compiler(1, build.build),
+ compiler: builder.compiler(1, builder.config.build),
target,
});
- build.info(&format!("Uplifting stage1 rustc ({} -> {})", &build.build, target));
+ builder.info(&format!("Uplifting stage1 rustc ({} -> {})",
+ builder.config.build, target));
builder.ensure(RustcLink {
- compiler: builder.compiler(1, build.build),
+ compiler: builder.compiler(1, builder.config.build),
target_compiler: compiler,
target,
});
// Ensure that build scripts have a std to link against.
builder.ensure(Std {
- compiler: builder.compiler(self.compiler.stage, build.build),
- target: build.build,
+ compiler: builder.compiler(self.compiler.stage, builder.config.build),
+ target: builder.config.build,
});
let cargo_out = builder.cargo_out(compiler, Mode::Librustc, target);
- build.clear_if_dirty(&cargo_out, &libstd_stamp(build, compiler, target));
- build.clear_if_dirty(&cargo_out, &libtest_stamp(build, compiler, target));
+ builder.clear_if_dirty(&cargo_out, &libstd_stamp(builder, compiler, target));
+ builder.clear_if_dirty(&cargo_out, &libtest_stamp(builder, compiler, target));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
- rustc_cargo(build, &mut cargo);
+ rustc_cargo(builder, &mut cargo);
- let _folder = build.fold_output(|| format!("stage{}-rustc", compiler.stage));
- build.info(&format!("Building stage{} compiler artifacts ({} -> {})",
+ let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage));
+ builder.info(&format!("Building stage{} compiler artifacts ({} -> {})",
compiler.stage, &compiler.host, target));
- run_cargo(build,
+ run_cargo(builder,
&mut cargo,
- &librustc_stamp(build, compiler, target),
+ &librustc_stamp(builder, compiler, target),
false);
builder.ensure(RustcLink {
- compiler: builder.compiler(compiler.stage, build.build),
+ compiler: builder.compiler(compiler.stage, builder.config.build),
target_compiler: compiler,
target,
});
}
}
-pub fn rustc_cargo(build: &Build, cargo: &mut Command) {
- cargo.arg("--features").arg(build.rustc_features())
+pub fn rustc_cargo(builder: &Builder, cargo: &mut Command) {
+ cargo.arg("--features").arg(builder.rustc_features())
.arg("--manifest-path")
- .arg(build.src.join("src/rustc/Cargo.toml"));
- rustc_cargo_env(build, cargo);
+ .arg(builder.src.join("src/rustc/Cargo.toml"));
+ rustc_cargo_env(builder, cargo);
}
-fn rustc_cargo_env(build: &Build, cargo: &mut Command) {
+pub fn rustc_cargo_env(builder: &Builder, cargo: &mut Command) {
// Set some configuration variables picked up by build scripts and
// the compiler alike
- cargo.env("CFG_RELEASE", build.rust_release())
- .env("CFG_RELEASE_CHANNEL", &build.config.channel)
- .env("CFG_VERSION", build.rust_version())
- .env("CFG_PREFIX", build.config.prefix.clone().unwrap_or_default())
- .env("CFG_CODEGEN_BACKENDS_DIR", &build.config.rust_codegen_backends_dir);
+ cargo.env("CFG_RELEASE", builder.rust_release())
+ .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
+ .env("CFG_VERSION", builder.rust_version())
+ .env("CFG_PREFIX", builder.config.prefix.clone().unwrap_or_default())
+ .env("CFG_CODEGEN_BACKENDS_DIR", &builder.config.rust_codegen_backends_dir);
- let libdir_relative = build.config.libdir_relative().unwrap_or(Path::new("lib"));
+ let libdir_relative = builder.config.libdir_relative().unwrap_or(Path::new("lib"));
cargo.env("CFG_LIBDIR_RELATIVE", libdir_relative);
// If we're not building a compiler with debugging information then remove
// these two env vars which would be set otherwise.
- if build.config.rust_debuginfo_only_std {
+ if builder.config.rust_debuginfo_only_std {
cargo.env_remove("RUSTC_DEBUGINFO");
cargo.env_remove("RUSTC_DEBUGINFO_LINES");
}
- if let Some(ref ver_date) = build.rust_info.commit_date() {
+ if let Some(ref ver_date) = builder.rust_info.commit_date() {
cargo.env("CFG_VER_DATE", ver_date);
}
- if let Some(ref ver_hash) = build.rust_info.sha() {
+ if let Some(ref ver_hash) = builder.rust_info.sha() {
cargo.env("CFG_VER_HASH", ver_hash);
}
- if !build.unstable_features() {
+ if !builder.unstable_features() {
cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1");
}
- if let Some(ref s) = build.config.rustc_default_linker {
+ if let Some(ref s) = builder.config.rustc_default_linker {
cargo.env("CFG_DEFAULT_LINKER", s);
}
- if build.config.rustc_parallel_queries {
+ if builder.config.rustc_parallel_queries {
cargo.env("RUSTC_PARALLEL_QUERIES", "1");
}
}
/// Same as `std_link`, only for librustc
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target_compiler = self.target_compiler;
let target = self.target;
- build.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})",
+ builder.info(&format!("Copying stage{} rustc from stage{} ({} -> {} / {})",
target_compiler.stage,
compiler.stage,
&compiler.host,
target_compiler.host,
target));
- add_to_sysroot(&build, &builder.sysroot_libdir(target_compiler, target),
- &librustc_stamp(build, compiler, target));
+ add_to_sysroot(builder, &builder.sysroot_libdir(target_compiler, target),
+ &librustc_stamp(builder, compiler, target));
builder.ensure(tool::CleanTools {
compiler: target_compiler,
target,
run.builder.ensure(CodegenBackend {
compiler: run.builder.compiler(run.builder.top_stage, run.host),
target: run.target,
- backend
+ backend,
});
}
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
+ let backend = self.backend;
builder.ensure(Rustc { compiler, target });
- if build.force_use_stage1(compiler, target) {
+ if builder.force_use_stage1(compiler, target) {
builder.ensure(CodegenBackend {
- compiler: builder.compiler(1, build.build),
+ compiler: builder.compiler(1, builder.config.build),
target,
- backend: self.backend,
+ backend,
});
return;
}
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build");
- let mut features = build.rustc_features().to_string();
+ let mut features = builder.rustc_features().to_string();
cargo.arg("--manifest-path")
- .arg(build.src.join("src/librustc_trans/Cargo.toml"));
- rustc_cargo_env(build, &mut cargo);
-
- match &*self.backend {
- "llvm" | "emscripten" => {
- // Build LLVM for our target. This will implicitly build the
- // host LLVM if necessary.
- let llvm_config = builder.ensure(native::Llvm {
- target,
- emscripten: self.backend == "emscripten",
- });
-
- if self.backend == "emscripten" {
- features.push_str(" emscripten");
- }
-
- build.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})",
- compiler.stage, &compiler.host, target, self.backend));
+ .arg(builder.src.join("src/librustc_trans/Cargo.toml"));
+ rustc_cargo_env(builder, &mut cargo);
- // Pass down configuration from the LLVM build into the build of
- // librustc_llvm and librustc_trans.
- if build.is_rust_llvm(target) {
- cargo.env("LLVM_RUSTLLVM", "1");
- }
- cargo.env("LLVM_CONFIG", &llvm_config);
- if self.backend != "emscripten" {
- let target_config = build.config.target_config.get(&target);
- if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
- cargo.env("CFG_LLVM_ROOT", s);
- }
- }
- // Building with a static libstdc++ is only supported on linux right now,
- // not for MSVC or macOS
- if build.config.llvm_static_stdcpp &&
- !target.contains("freebsd") &&
- !target.contains("windows") &&
- !target.contains("apple") {
- let file = compiler_file(build,
- build.cxx(target).unwrap(),
- target,
- "libstdc++.a");
- cargo.env("LLVM_STATIC_STDCPP", file);
- }
- if build.config.llvm_link_shared {
- cargo.env("LLVM_LINK_SHARED", "1");
- }
- }
- _ => panic!("unknown backend: {}", self.backend),
- }
+ features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend);
- let tmp_stamp = build.cargo_out(compiler, Mode::Librustc, target)
+ let tmp_stamp = builder.cargo_out(compiler, Mode::Librustc, target)
.join(".tmp.stamp");
- let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
- let files = run_cargo(build,
+ let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
+ let files = run_cargo(builder,
cargo.arg("--features").arg(features),
&tmp_stamp,
false);
codegen_backend.display(),
f.display());
}
- let stamp = codegen_backend_stamp(build, compiler, target, self.backend);
+ let stamp = codegen_backend_stamp(builder, compiler, target, backend);
let codegen_backend = codegen_backend.to_str().unwrap();
t!(t!(File::create(&stamp)).write_all(codegen_backend.as_bytes()));
}
}
+pub fn build_codegen_backend(builder: &Builder,
+ cargo: &mut Command,
+ compiler: &Compiler,
+ target: Interned<String>,
+ backend: Interned<String>) -> String {
+ let mut features = String::new();
+
+ match &*backend {
+ "llvm" | "emscripten" => {
+ // Build LLVM for our target. This will implicitly build the
+ // host LLVM if necessary.
+ let llvm_config = builder.ensure(native::Llvm {
+ target,
+ emscripten: backend == "emscripten",
+ });
+
+ if backend == "emscripten" {
+ features.push_str(" emscripten");
+ }
+
+ builder.info(&format!("Building stage{} codegen artifacts ({} -> {}, {})",
+ compiler.stage, &compiler.host, target, backend));
+
+ // Pass down configuration from the LLVM build into the build of
+ // librustc_llvm and librustc_trans.
+ if builder.is_rust_llvm(target) {
+ cargo.env("LLVM_RUSTLLVM", "1");
+ }
+ cargo.env("LLVM_CONFIG", &llvm_config);
+ if backend != "emscripten" {
+ let target_config = builder.config.target_config.get(&target);
+ if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) {
+ cargo.env("CFG_LLVM_ROOT", s);
+ }
+ }
+ // Building with a static libstdc++ is only supported on linux right now,
+ // not for MSVC or macOS
+ if builder.config.llvm_static_stdcpp &&
+ !target.contains("freebsd") &&
+ !target.contains("windows") &&
+ !target.contains("apple") {
+ let file = compiler_file(builder,
+ builder.cxx(target).unwrap(),
+ target,
+ "libstdc++.a");
+ cargo.env("LLVM_STATIC_STDCPP", file);
+ }
+ if builder.config.llvm_link_shared {
+ cargo.env("LLVM_LINK_SHARED", "1");
+ }
+ }
+ _ => panic!("unknown backend: {}", backend),
+ }
+
+ features
+}
+
/// Creates the `codegen-backends` folder for a compiler that's about to be
/// assembled as a complete compiler.
///
fn copy_codegen_backends_to_sysroot(builder: &Builder,
compiler: Compiler,
target_compiler: Compiler) {
- let build = builder.build;
let target = target_compiler.host;
// Note that this step is different than all the other `*Link` steps in
}
for backend in builder.config.rust_codegen_backends.iter() {
- let stamp = codegen_backend_stamp(build, compiler, target, *backend);
+ let stamp = codegen_backend_stamp(builder, compiler, target, *backend);
let mut dylib = String::new();
t!(t!(File::open(&stamp)).read_to_string(&mut dylib));
let file = Path::new(&dylib);
backend,
&filename[dot..])
};
- build.copy(&file, &dst.join(target_filename));
+ builder.copy(&file, &dst.join(target_filename));
}
}
/// Cargo's output path for the standard library in a given stage, compiled
/// by a particular compiler for the specified target.
-pub fn libstd_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
- build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
+pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp")
}
/// Cargo's output path for libtest in a given stage, compiled by a particular
/// compiler for the specified target.
-pub fn libtest_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
- build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
+pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp")
}
/// Cargo's output path for librustc in a given stage, compiled by a particular
/// compiler for the specified target.
-pub fn librustc_stamp(build: &Build, compiler: Compiler, target: Interned<String>) -> PathBuf {
- build.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
+pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned<String>) -> PathBuf {
+ builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp")
}
-fn codegen_backend_stamp(build: &Build,
+/// Cargo's output path for librustc_trans in a given stage, compiled by a particular
+/// compiler for the specified target and backend.
+fn codegen_backend_stamp(builder: &Builder,
compiler: Compiler,
target: Interned<String>,
backend: Interned<String>) -> PathBuf {
- build.cargo_out(compiler, Mode::Librustc, target)
+ builder.cargo_out(compiler, Mode::Librustc, target)
.join(format!(".librustc_trans-{}.stamp", backend))
}
-fn compiler_file(build: &Build,
+pub fn compiler_file(builder: &Builder,
compiler: &Path,
target: Interned<String>,
file: &str) -> PathBuf {
let mut cmd = Command::new(compiler);
- cmd.args(build.cflags(target));
+ cmd.args(builder.cflags(target));
cmd.arg(format!("-print-file-name={}", file));
let out = output(&mut cmd);
PathBuf::from(out.trim())
/// thinks it is by default, but it's the same as the default for stages
/// 1-3.
fn run(self, builder: &Builder) -> Interned<PathBuf> {
- let build = builder.build;
let compiler = self.compiler;
let sysroot = if compiler.stage == 0 {
- build.out.join(&compiler.host).join("stage0-sysroot")
+ builder.out.join(&compiler.host).join("stage0-sysroot")
} else {
- build.out.join(&compiler.host).join(format!("stage{}", compiler.stage))
+ builder.out.join(&compiler.host).join(format!("stage{}", compiler.stage))
};
let _ = fs::remove_dir_all(&sysroot);
t!(fs::create_dir_all(&sysroot));
/// Prepare a new compiler from the artifacts in `stage`
///
/// This will assemble a compiler in `build/$host/stage$stage`. The compiler
- /// must have been previously produced by the `stage - 1` build.build
+ /// must have been previously produced by the `stage - 1` builder.build
/// compiler.
fn run(self, builder: &Builder) -> Compiler {
- let build = builder.build;
let target_compiler = self.target_compiler;
if target_compiler.stage == 0 {
- assert_eq!(build.build, target_compiler.host,
+ assert_eq!(builder.config.build, target_compiler.host,
"Cannot obtain compiler for non-native build triple at stage 0");
// The stage 0 compiler for the build triple is always pre-built.
return target_compiler;
// FIXME: It may be faster if we build just a stage 1 compiler and then
// use that to bootstrap this compiler forward.
let build_compiler =
- builder.compiler(target_compiler.stage - 1, build.build);
+ builder.compiler(target_compiler.stage - 1, builder.config.build);
// Build the libraries for this compiler to link to (i.e., the libraries
// it uses at runtime). NOTE: Crates the target compiler compiles don't
// link to these. (FIXME: Is that correct? It seems to be correct most
// of the time but I think we do link to these for stage2/bin compilers
// when not performing a full bootstrap).
- if builder.build.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) {
+ if builder.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) {
builder.verbose("skipping compilation of compiler due to --keep-stage");
let compiler = build_compiler;
for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) {
compiler: build_compiler,
target: target_compiler.host,
});
- for &backend in build.config.rust_codegen_backends.iter() {
+ for &backend in builder.config.rust_codegen_backends.iter() {
builder.ensure(CodegenBackend {
compiler: build_compiler,
target: target_compiler.host,
}
}
- let lld_install = if build.config.lld_enabled {
+ let lld_install = if builder.config.lld_enabled {
Some(builder.ensure(native::Lld {
target: target_compiler.host,
}))
let stage = target_compiler.stage;
let host = target_compiler.host;
- build.info(&format!("Assembling stage{} compiler ({})", stage, host));
+ builder.info(&format!("Assembling stage{} compiler ({})", stage, host));
// Link in all dylibs to the libdir
let sysroot = builder.sysroot(target_compiler);
}
// Link the compiler binary itself into place
- let out_dir = build.cargo_out(build_compiler, Mode::Librustc, host);
+ let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host);
let rustc = out_dir.join(exe("rustc", &*host));
let bindir = sysroot.join("bin");
t!(fs::create_dir_all(&bindir));
///
/// For a particular stage this will link the file listed in `stamp` into the
/// `sysroot_dst` provided.
-pub fn add_to_sysroot(build: &Build, sysroot_dst: &Path, stamp: &Path) {
+pub fn add_to_sysroot(builder: &Builder, sysroot_dst: &Path, stamp: &Path) {
t!(fs::create_dir_all(&sysroot_dst));
- for path in build.read_stamp_file(stamp) {
- build.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
+ for path in builder.read_stamp_file(stamp) {
+ builder.copy(&path, &sysroot_dst.join(path.file_name().unwrap()));
}
}
}
}
-pub fn run_cargo(build: &Build, cargo: &mut Command, stamp: &Path, is_check: bool)
+pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: bool)
-> Vec<PathBuf>
{
- if build.config.dry_run {
+ if builder.config.dry_run {
return Vec::new();
}
// files we need to probe for later.
let mut deps = Vec::new();
let mut toplevel = Vec::new();
- let ok = stream_cargo(build, cargo, &mut |msg| {
+ let ok = stream_cargo(builder, cargo, &mut |msg| {
let filenames = match msg {
CargoMessage::CompilerArtifact { filenames, .. } => filenames,
_ => return,
let max = max.unwrap();
let max_path = max_path.unwrap();
if stamp_contents == new_contents && max <= stamp_mtime {
- build.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}",
+ builder.verbose(&format!("not updating {:?}; contents equal and {:?} <= {:?}",
stamp, max, stamp_mtime));
return deps
}
if max > stamp_mtime {
- build.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
+ builder.verbose(&format!("updating {:?} as {:?} changed", stamp, max_path));
} else {
- build.verbose(&format!("updating {:?} as deps changed", stamp));
+ builder.verbose(&format!("updating {:?} as deps changed", stamp));
}
t!(t!(File::create(stamp)).write_all(&new_contents));
deps
}
pub fn stream_cargo(
- build: &Build,
+ builder: &Builder,
cargo: &mut Command,
cb: &mut FnMut(CargoMessage),
) -> bool {
- if build.config.dry_run {
+ if builder.config.dry_run {
return true;
}
// Instruct Cargo to give us json messages on stdout, critically leaving
cargo.arg("--message-format").arg("json")
.stdout(Stdio::piped());
- if stderr_isatty() && build.ci_env == CiEnv::None &&
+ if stderr_isatty() && builder.ci_env == CiEnv::None &&
// if the terminal is reported as dumb, then we don't want to enable color for rustc
env::var_os("TERM").map(|t| t != *"dumb").unwrap_or(true) {
// since we pass message-format=json to cargo, we need to tell the rustc
cargo.env("RUSTC_COLOR", "1");
}
- build.verbose(&format!("running: {:?}", cargo));
+ builder.verbose(&format!("running: {:?}", cargo));
let mut child = match cargo.spawn() {
Ok(child) => child,
Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cargo, e),
pub rust_debuginfo: bool,
pub rust_debuginfo_lines: bool,
pub rust_debuginfo_only_std: bool,
+ pub rust_debuginfo_tools: bool,
pub rust_rpath: bool,
pub rustc_parallel_queries: bool,
pub rustc_default_linker: Option<String>,
debuginfo: Option<bool>,
debuginfo_lines: Option<bool>,
debuginfo_only_std: Option<bool>,
+ debuginfo_tools: Option<bool>,
experimental_parallel_queries: Option<bool>,
debug_jemalloc: Option<bool>,
use_jemalloc: Option<bool>,
let mut llvm_assertions = None;
let mut debuginfo_lines = None;
let mut debuginfo_only_std = None;
+ let mut debuginfo_tools = None;
let mut debug = None;
let mut debug_jemalloc = None;
let mut debuginfo = None;
debuginfo = rust.debuginfo;
debuginfo_lines = rust.debuginfo_lines;
debuginfo_only_std = rust.debuginfo_only_std;
+ debuginfo_tools = rust.debuginfo_tools;
optimize = rust.optimize;
ignore_git = rust.ignore_git;
debug_jemalloc = rust.debug_jemalloc;
};
config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default);
config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default);
+ config.rust_debuginfo_tools = debuginfo_tools.unwrap_or(false);
let default = debug == Some(true);
config.debug_jemalloc = debug_jemalloc.unwrap_or(default);
o("debuginfo", "rust.debuginfo", "build with debugger metadata")
o("debuginfo-lines", "rust.debuginfo-lines", "build with line number debugger metadata")
o("debuginfo-only-std", "rust.debuginfo-only-std", "build only libstd with debugging information")
+o("debuginfo-tools", "rust.debuginfo-tools", "build extended tools with debugging information")
o("debug-jemalloc", "rust.debug-jemalloc", "build jemalloc with --enable-debug --enable-fill")
v("save-toolstates", "rust.save-toolstates", "save build and test status of external tools into this file")
use build_helper::output;
-use {Build, Compiler, Mode};
+use {Compiler, Mode};
use channel;
use util::{libdir, is_dylib, exe};
use builder::{Builder, RunConfig, ShouldRun, Step};
use cache::{INTERNER, Interned};
use time;
-pub fn pkgname(build: &Build, component: &str) -> String {
+pub fn pkgname(builder: &Builder, component: &str) -> String {
if component == "cargo" {
- format!("{}-{}", component, build.cargo_package_vers())
+ format!("{}-{}", component, builder.cargo_package_vers())
} else if component == "rls" {
- format!("{}-{}", component, build.rls_package_vers())
+ format!("{}-{}", component, builder.rls_package_vers())
} else if component == "rustfmt" {
- format!("{}-{}", component, build.rustfmt_package_vers())
+ format!("{}-{}", component, builder.rustfmt_package_vers())
} else {
assert!(component.starts_with("rust"));
- format!("{}-{}", component, build.rust_package_vers())
+ format!("{}-{}", component, builder.rust_package_vers())
}
}
-fn distdir(build: &Build) -> PathBuf {
- build.out.join("dist")
+fn distdir(builder: &Builder) -> PathBuf {
+ builder.out.join("dist")
}
-pub fn tmpdir(build: &Build) -> PathBuf {
- build.out.join("tmp/dist")
+pub fn tmpdir(builder: &Builder) -> PathBuf {
+ builder.out.join("tmp/dist")
}
fn rust_installer(builder: &Builder) -> Command {
/// Builds the `rust-docs` installer component.
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let host = self.host;
- let name = pkgname(build, "rust-docs");
+ let name = pkgname(builder, "rust-docs");
- build.info(&format!("Dist docs ({})", host));
- if !build.config.docs {
- build.info(&format!("\tskipping - docs disabled"));
- return distdir(build).join(format!("{}-{}.tar.gz", name, host));
+ builder.info(&format!("Dist docs ({})", host));
+ if !builder.config.docs {
+ builder.info(&format!("\tskipping - docs disabled"));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
}
builder.default_doc(None);
- let image = tmpdir(build).join(format!("{}-{}-image", name, host));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
let _ = fs::remove_dir_all(&image);
let dst = image.join("share/doc/rust/html");
t!(fs::create_dir_all(&dst));
- let src = build.doc_out(host);
- build.cp_r(&src, &dst);
+ let src = builder.doc_out(host);
+ builder.cp_r(&src, &dst);
let mut cmd = rust_installer(builder);
cmd.arg("generate")
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=Rust-documentation-is-installed.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg(format!("--package-name={}-{}", name, host))
.arg("--component-name=rust-docs")
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--bulk-dirs=share/doc/rust/html");
- build.run(&mut cmd);
- build.remove_dir(&image);
+ builder.run(&mut cmd);
+ builder.remove_dir(&image);
- distdir(build).join(format!("{}-{}.tar.gz", name, host))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, host))
}
}
/// Builds the `rustc-docs` installer component.
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let host = self.host;
- let name = pkgname(build, "rustc-docs");
+ let name = pkgname(builder, "rustc-docs");
- build.info(&format!("Dist compiler docs ({})", host));
- if !build.config.compiler_docs {
- build.info(&format!("\tskipping - compiler docs disabled"));
- return distdir(build).join(format!("{}-{}.tar.gz", name, host));
+ builder.info(&format!("Dist compiler docs ({})", host));
+ if !builder.config.compiler_docs {
+ builder.info(&format!("\tskipping - compiler docs disabled"));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
}
builder.default_doc(None);
- let image = tmpdir(build).join(format!("{}-{}-image", name, host));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
let _ = fs::remove_dir_all(&image);
let dst = image.join("share/doc/rust/html");
t!(fs::create_dir_all(&dst));
- let src = build.compiler_doc_out(host);
- build.cp_r(&src, &dst);
+ let src = builder.compiler_doc_out(host);
+ builder.cp_r(&src, &dst);
let mut cmd = rust_installer(builder);
cmd.arg("generate")
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=Rustc-documentation-is-installed.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg(format!("--package-name={}-{}", name, host))
.arg("--component-name=rustc-docs")
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--bulk-dirs=share/doc/rust/html");
- build.run(&mut cmd);
- build.remove_dir(&image);
+ builder.run(&mut cmd);
+ builder.remove_dir(&image);
- distdir(build).join(format!("{}-{}.tar.gz", name, host))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, host))
}
}
}
fn make_win_dist(
- rust_root: &Path, plat_root: &Path, target_triple: Interned<String>, build: &Build
+ rust_root: &Path, plat_root: &Path, target_triple: Interned<String>, builder: &Builder
) {
//Ask gcc where it keeps its stuff
- let mut cmd = Command::new(build.cc(target_triple));
+ let mut cmd = Command::new(builder.cc(target_triple));
cmd.arg("-print-search-dirs");
let gcc_out = output(&mut cmd);
let dist_bin_dir = rust_root.join("bin/");
fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed");
for src in rustc_dlls {
- build.copy_to_folder(&src, &dist_bin_dir);
+ builder.copy_to_folder(&src, &dist_bin_dir);
}
//Copy platform tools to platform-specific bin directory
let target_bin_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("bin");
fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed");
for src in target_tools {
- build.copy_to_folder(&src, &target_bin_dir);
+ builder.copy_to_folder(&src, &target_bin_dir);
}
//Copy platform libs to platform-specific lib directory
let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib");
fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed");
for src in target_libs {
- build.copy_to_folder(&src, &target_lib_dir);
+ builder.copy_to_folder(&src, &target_lib_dir);
}
}
/// This contains all the bits and pieces to run the MinGW Windows targets
/// without any extra installed software (e.g. we bundle gcc, libraries, etc).
fn run(self, builder: &Builder) -> Option<PathBuf> {
- let build = builder.build;
let host = self.host;
if !host.contains("pc-windows-gnu") {
return None;
}
- build.info(&format!("Dist mingw ({})", host));
- let name = pkgname(build, "rust-mingw");
- let image = tmpdir(build).join(format!("{}-{}-image", name, host));
+ builder.info(&format!("Dist mingw ({})", host));
+ let name = pkgname(builder, "rust-mingw");
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
let _ = fs::remove_dir_all(&image);
t!(fs::create_dir_all(&image));
// thrown away (this contains the runtime DLLs included in the rustc package
// above) and the second argument is where to place all the MinGW components
// (which is what we want).
- make_win_dist(&tmpdir(build), &image, host, &build);
+ make_win_dist(&tmpdir(builder), &image, host, &builder);
let mut cmd = rust_installer(builder);
cmd.arg("generate")
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=Rust-MinGW-is-installed.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg(format!("--package-name={}-{}", name, host))
.arg("--component-name=rust-mingw")
.arg("--legacy-manifest-dirs=rustlib,cargo");
- build.run(&mut cmd);
+ builder.run(&mut cmd);
t!(fs::remove_dir_all(&image));
- Some(distdir(build).join(format!("{}-{}.tar.gz", name, host)))
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host)))
}
}
/// Creates the `rustc` installer component.
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let compiler = self.compiler;
let host = self.compiler.host;
- build.info(&format!("Dist rustc stage{} ({})", compiler.stage, compiler.host));
- let name = pkgname(build, "rustc");
- let image = tmpdir(build).join(format!("{}-{}-image", name, host));
+ builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, compiler.host));
+ let name = pkgname(builder, "rustc");
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
let _ = fs::remove_dir_all(&image);
- let overlay = tmpdir(build).join(format!("{}-{}-overlay", name, host));
+ let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host));
let _ = fs::remove_dir_all(&overlay);
// Prepare the rustc "image", what will actually end up getting installed
// Prepare the overlay which is part of the tarball but won't actually be
// installed
let cp = |file: &str| {
- build.install(&build.src.join(file), &overlay, 0o644);
+ builder.install(&builder.src.join(file), &overlay, 0o644);
};
cp("COPYRIGHT");
cp("LICENSE-APACHE");
cp("LICENSE-MIT");
cp("README.md");
// tiny morsel of metadata is used by rust-packaging
- let version = build.rust_version();
- build.create(&overlay.join("version"), &version);
- if let Some(sha) = build.rust_sha() {
- build.create(&overlay.join("git-commit-hash"), &sha);
+ let version = builder.rust_version();
+ builder.create(&overlay.join("version"), &version);
+ if let Some(sha) = builder.rust_sha() {
+ builder.create(&overlay.join("git-commit-hash"), &sha);
}
// On MinGW we've got a few runtime DLL dependencies that we need to
// install will *also* include the rust-mingw package, which also needs
// licenses, so to be safe we just include it here in all MinGW packages.
if host.contains("pc-windows-gnu") {
- make_win_dist(&image, &tmpdir(build), host, build);
+ make_win_dist(&image, &tmpdir(builder), host, builder);
let dst = image.join("share/doc");
t!(fs::create_dir_all(&dst));
- build.cp_r(&build.src.join("src/etc/third-party"), &dst);
+ builder.cp_r(&builder.src.join("src/etc/third-party"), &dst);
}
// Finally, wrap everything up in a nice tarball!
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=Rust-is-ready-to-roll.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg("--non-installed-overlay").arg(&overlay)
.arg(format!("--package-name={}-{}", name, host))
.arg("--component-name=rustc")
.arg("--legacy-manifest-dirs=rustlib,cargo");
- build.run(&mut cmd);
- build.remove_dir(&image);
- build.remove_dir(&overlay);
+ builder.run(&mut cmd);
+ builder.remove_dir(&image);
+ builder.remove_dir(&overlay);
- return distdir(build).join(format!("{}-{}.tar.gz", name, host));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
fn prepare_image(builder: &Builder, compiler: Compiler, image: &Path) {
let host = compiler.host;
- let build = builder.build;
let src = builder.sysroot(compiler);
let libdir = libdir(&host);
// Copy rustc/rustdoc binaries
t!(fs::create_dir_all(image.join("bin")));
- build.cp_r(&src.join("bin"), &image.join("bin"));
+ builder.cp_r(&src.join("bin"), &image.join("bin"));
- build.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
+ builder.install(&builder.rustdoc(compiler.host), &image.join("bin"), 0o755);
// Copy runtime DLLs needed by the compiler
if libdir != "bin" {
- for entry in build.read_dir(&src.join(libdir)) {
+ for entry in builder.read_dir(&src.join(libdir)) {
let name = entry.file_name();
if let Some(s) = name.to_str() {
if is_dylib(s) {
- build.install(&entry.path(), &image.join(libdir), 0o644);
+ builder.install(&entry.path(), &image.join(libdir), 0o644);
}
}
}
let backends_rel = backends_src.strip_prefix(&src).unwrap();
let backends_dst = image.join(&backends_rel);
t!(fs::create_dir_all(&backends_dst));
- build.cp_r(&backends_src, &backends_dst);
+ builder.cp_r(&backends_src, &backends_dst);
// Copy over lld if it's there
if builder.config.lld_enabled {
.join("bin")
.join(&exe);
t!(fs::create_dir_all(&dst.parent().unwrap()));
- build.copy(&src, &dst);
+ builder.copy(&src, &dst);
}
// Man pages
t!(fs::create_dir_all(image.join("share/man/man1")));
- let man_src = build.src.join("src/doc/man");
+ let man_src = builder.src.join("src/doc/man");
let man_dst = image.join("share/man/man1");
let month_year = t!(time::strftime("%B %Y", &time::now()));
// don't use our `bootstrap::util::{copy, cp_r}`, because those try
// to hardlink, and we don't want to edit the source templates
- for file_entry in build.read_dir(&man_src) {
+ for file_entry in builder.read_dir(&man_src) {
let page_src = file_entry.path();
let page_dst = man_dst.join(file_entry.file_name());
t!(fs::copy(&page_src, &page_dst));
// template in month/year and version number
- build.replace_in_file(&page_dst,
+ builder.replace_in_file(&page_dst,
&[("<INSERT DATE HERE>", &month_year),
("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]);
}
// Misc license info
let cp = |file: &str| {
- build.install(&build.src.join(file), &image.join("share/doc/rust"), 0o644);
+ builder.install(&builder.src.join(file), &image.join("share/doc/rust"), 0o644);
};
cp("COPYRIGHT");
cp("LICENSE-APACHE");
/// Copies debugger scripts for `target` into the `sysroot` specified.
fn run(self, builder: &Builder) {
- let build = builder.build;
let host = self.host;
let sysroot = self.sysroot;
let dst = sysroot.join("lib/rustlib/etc");
t!(fs::create_dir_all(&dst));
let cp_debugger_script = |file: &str| {
- build.install(&build.src.join("src/etc/").join(file), &dst, 0o644);
+ builder.install(&builder.src.join("src/etc/").join(file), &dst, 0o644);
};
if host.contains("windows-msvc") {
// windbg debugger scripts
- build.install(&build.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
+ builder.install(&builder.src.join("src/etc/rust-windbg.cmd"), &sysroot.join("bin"),
0o755);
cp_debugger_script("natvis/intrinsic.natvis");
cp_debugger_script("debugger_pretty_printers_common.py");
// gdb debugger scripts
- build.install(&build.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
+ builder.install(&builder.src.join("src/etc/rust-gdb"), &sysroot.join("bin"),
0o755);
cp_debugger_script("gdb_load_rust_pretty_printers.py");
cp_debugger_script("gdb_rust_pretty_printing.py");
// lldb debugger scripts
- build.install(&build.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
+ builder.install(&builder.src.join("src/etc/rust-lldb"), &sysroot.join("bin"),
0o755);
cp_debugger_script("lldb_rust_formatters.py");
fn make_run(run: RunConfig) {
run.builder.ensure(Std {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
- let name = pkgname(build, "rust-std");
- build.info(&format!("Dist std stage{} ({} -> {})", compiler.stage, &compiler.host, target));
+ let name = pkgname(builder, "rust-std");
+ builder.info(&format!("Dist std stage{} ({} -> {})",
+ compiler.stage, &compiler.host, target));
// The only true set of target libraries came from the build triple, so
// let's reduce redundant work by only producing archives from that host.
- if compiler.host != build.build {
- build.info(&format!("\tskipping, not a build host"));
- return distdir(build).join(format!("{}-{}.tar.gz", name, target));
+ if compiler.host != builder.config.build {
+ builder.info(&format!("\tskipping, not a build host"));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
}
// We want to package up as many target libraries as possible
// for the `rust-std` package, so if this is a host target we
// depend on librustc and otherwise we just depend on libtest.
- if build.hosts.iter().any(|t| t == target) {
+ if builder.hosts.iter().any(|t| t == target) {
builder.ensure(compile::Rustc { compiler, target });
} else {
- if build.no_std(target) == Some(true) {
+ if builder.no_std(target) == Some(true) {
// the `test` doesn't compile for no-std targets
builder.ensure(compile::Std { compiler, target });
} else {
}
}
- let image = tmpdir(build).join(format!("{}-{}-image", name, target));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
let _ = fs::remove_dir_all(&image);
let dst = image.join("lib/rustlib").join(target);
t!(fs::create_dir_all(&dst));
let mut src = builder.sysroot_libdir(compiler, target).to_path_buf();
src.pop(); // Remove the trailing /lib folder from the sysroot_libdir
- build.cp_filtered(&src, &dst, &|path| {
+ builder.cp_filtered(&src, &dst, &|path| {
let name = path.file_name().and_then(|s| s.to_str());
- name != Some(build.config.rust_codegen_backends_dir.as_str()) &&
+ name != Some(builder.config.rust_codegen_backends_dir.as_str()) &&
name != Some("bin")
});
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=std-is-standing-at-the-ready.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg(format!("--package-name={}-{}", name, target))
.arg(format!("--component-name=rust-std-{}", target))
.arg("--legacy-manifest-dirs=rustlib,cargo");
- build.run(&mut cmd);
- build.remove_dir(&image);
- distdir(build).join(format!("{}-{}.tar.gz", name, target))
+ builder.run(&mut cmd);
+ builder.remove_dir(&image);
+ distdir(builder).join(format!("{}-{}.tar.gz", name, target))
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("analysis").default_condition(builder.build.config.extended)
+ run.path("analysis").default_condition(builder.config.extended)
}
fn make_run(run: RunConfig) {
run.builder.ensure(Analysis {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
/// Creates a tarball of save-analysis metadata, if available.
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
- assert!(build.config.extended);
- build.info(&format!("Dist analysis"));
- let name = pkgname(build, "rust-analysis");
+ assert!(builder.config.extended);
+ builder.info(&format!("Dist analysis"));
+ let name = pkgname(builder, "rust-analysis");
- if &compiler.host != build.build {
- build.info(&format!("\tskipping, not a build host"));
- return distdir(build).join(format!("{}-{}.tar.gz", name, target));
+ if &compiler.host != builder.config.build {
+ builder.info(&format!("\tskipping, not a build host"));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
}
builder.ensure(Std { compiler, target });
// Package save-analysis from stage1 if not doing a full bootstrap, as the
// stage2 artifacts is simply copied from stage1 in that case.
- let compiler = if build.force_use_stage1(compiler, target) {
+ let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler.clone()
};
- let image = tmpdir(build).join(format!("{}-{}-image", name, target));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
- let src = build.stage_out(compiler, Mode::Libstd)
- .join(target).join(build.cargo_dir()).join("deps");
+ let src = builder.stage_out(compiler, Mode::Libstd)
+ .join(target).join(builder.cargo_dir()).join("deps");
let image_src = src.join("save-analysis");
let dst = image.join("lib/rustlib").join(target).join("analysis");
t!(fs::create_dir_all(&dst));
- build.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
- build.cp_r(&image_src, &dst);
+ builder.info(&format!("image_src: {:?}, dst: {:?}", image_src, dst));
+ builder.cp_r(&image_src, &dst);
let mut cmd = rust_installer(builder);
cmd.arg("generate")
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=save-analysis-saved.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg(format!("--package-name={}-{}", name, target))
.arg(format!("--component-name=rust-analysis-{}", target))
.arg("--legacy-manifest-dirs=rustlib,cargo");
- build.run(&mut cmd);
- build.remove_dir(&image);
- distdir(build).join(format!("{}-{}.tar.gz", name, target))
+ builder.run(&mut cmd);
+ builder.remove_dir(&image);
+ distdir(builder).join(format!("{}-{}.tar.gz", name, target))
}
}
-fn copy_src_dirs(build: &Build, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) {
+fn copy_src_dirs(builder: &Builder, src_dirs: &[&str], exclude_dirs: &[&str], dst_dir: &Path) {
fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
let spath = match path.to_str() {
Some(path) => path,
for item in src_dirs {
let dst = &dst_dir.join(item);
t!(fs::create_dir_all(dst));
- build.cp_filtered(&build.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
+ builder.cp_filtered(
+ &builder.src.join(item), dst, &|path| filter_fn(exclude_dirs, item, path));
}
}
/// Creates the `rust-src` installer component
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
- build.info(&format!("Dist src"));
+ builder.info(&format!("Dist src"));
- let name = pkgname(build, "rust-src");
- let image = tmpdir(build).join(format!("{}-image", name));
+ let name = pkgname(builder, "rust-src");
+ let image = tmpdir(builder).join(format!("{}-image", name));
let _ = fs::remove_dir_all(&image);
let dst = image.join("lib/rustlib/src");
"src/jemalloc/test/unit",
];
- copy_src_dirs(build, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
+ copy_src_dirs(builder, &std_src_dirs[..], &std_src_dirs_exclude[..], &dst_src);
for file in src_files.iter() {
- build.copy(&build.src.join(file), &dst_src.join(file));
+ builder.copy(&builder.src.join(file), &dst_src.join(file));
}
// Create source tarball in rust-installer format
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=Awesome-Source.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg(format!("--package-name={}", name))
.arg("--component-name=rust-src")
.arg("--legacy-manifest-dirs=rustlib,cargo");
- build.run(&mut cmd);
+ builder.run(&mut cmd);
- build.remove_dir(&image);
- distdir(build).join(&format!("{}.tar.gz", name))
+ builder.remove_dir(&image);
+ distdir(builder).join(&format!("{}.tar.gz", name))
}
}
/// Creates the plain source tarball
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
- build.info(&format!("Create plain source tarball"));
+ builder.info(&format!("Create plain source tarball"));
// Make sure that the root folder of tarball has the correct name
- let plain_name = format!("{}-src", pkgname(build, "rustc"));
- let plain_dst_src = tmpdir(build).join(&plain_name);
+ let plain_name = format!("{}-src", pkgname(builder, "rustc"));
+ let plain_dst_src = tmpdir(builder).join(&plain_name);
let _ = fs::remove_dir_all(&plain_dst_src);
t!(fs::create_dir_all(&plain_dst_src));
"src",
];
- copy_src_dirs(build, &src_dirs[..], &[], &plain_dst_src);
+ copy_src_dirs(builder, &src_dirs[..], &[], &plain_dst_src);
// Copy the files normally
for item in &src_files {
- build.copy(&build.src.join(item), &plain_dst_src.join(item));
+ builder.copy(&builder.src.join(item), &plain_dst_src.join(item));
}
// Create the version file
- build.create(&plain_dst_src.join("version"), &build.rust_version());
- if let Some(sha) = build.rust_sha() {
- build.create(&plain_dst_src.join("git-commit-hash"), &sha);
+ builder.create(&plain_dst_src.join("version"), &builder.rust_version());
+ if let Some(sha) = builder.rust_sha() {
+ builder.create(&plain_dst_src.join("git-commit-hash"), &sha);
}
// If we're building from git sources, we need to vendor a complete distribution.
- if build.rust_info.is_git() {
+ if builder.rust_info.is_git() {
// Get cargo-vendor installed, if it isn't already.
let mut has_cargo_vendor = false;
- let mut cmd = Command::new(&build.initial_cargo);
+ let mut cmd = Command::new(&builder.initial_cargo);
for line in output(cmd.arg("install").arg("--list")).lines() {
has_cargo_vendor |= line.starts_with("cargo-vendor ");
}
if !has_cargo_vendor {
- let mut cmd = Command::new(&build.initial_cargo);
+ let mut cmd = Command::new(&builder.initial_cargo);
cmd.arg("install")
.arg("--force")
.arg("--debug")
.arg("--vers").arg(CARGO_VENDOR_VERSION)
.arg("cargo-vendor")
- .env("RUSTC", &build.initial_rustc);
- if let Some(dir) = build.openssl_install_dir(build.config.build) {
+ .env("RUSTC", &builder.initial_rustc);
+ if let Some(dir) = builder.openssl_install_dir(builder.config.build) {
builder.ensure(native::Openssl {
- target: build.config.build,
+ target: builder.config.build,
});
cmd.env("OPENSSL_DIR", dir);
}
- build.run(&mut cmd);
+ builder.run(&mut cmd);
}
// Vendor all Cargo dependencies
- let mut cmd = Command::new(&build.initial_cargo);
+ let mut cmd = Command::new(&builder.initial_cargo);
cmd.arg("vendor")
.current_dir(&plain_dst_src.join("src"));
- build.run(&mut cmd);
+ builder.run(&mut cmd);
}
// Create plain source tarball
- let plain_name = format!("rustc-{}-src", build.rust_package_vers());
- let mut tarball = distdir(build).join(&format!("{}.tar.gz", plain_name));
+ let plain_name = format!("rustc-{}-src", builder.rust_package_vers());
+ let mut tarball = distdir(builder).join(&format!("{}.tar.gz", plain_name));
tarball.set_extension(""); // strip .gz
tarball.set_extension(""); // strip .tar
if let Some(dir) = tarball.parent() {
- build.create_dir(&dir);
+ builder.create_dir(&dir);
}
- build.info(&format!("running installer"));
+ builder.info(&format!("running installer"));
let mut cmd = rust_installer(builder);
cmd.arg("tarball")
.arg("--input").arg(&plain_name)
.arg("--output").arg(&tarball)
.arg("--work-dir=.")
- .current_dir(tmpdir(build));
- build.run(&mut cmd);
- distdir(build).join(&format!("{}.tar.gz", plain_name))
+ .current_dir(tmpdir(builder));
+ builder.run(&mut cmd);
+ distdir(builder).join(&format!("{}.tar.gz", plain_name))
}
}
}
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- build.info(&format!("Dist cargo stage{} ({})", stage, target));
- let src = build.src.join("src/tools/cargo");
+ builder.info(&format!("Dist cargo stage{} ({})", stage, target));
+ let src = builder.src.join("src/tools/cargo");
let etc = src.join("src/etc");
- let release_num = build.release_num("cargo");
- let name = pkgname(build, "cargo");
- let version = builder.cargo_info.version(build, &release_num);
+ let release_num = builder.release_num("cargo");
+ let name = pkgname(builder, "cargo");
+ let version = builder.cargo_info.version(builder, &release_num);
- let tmp = tmpdir(build);
+ let tmp = tmpdir(builder);
let image = tmp.join("cargo-image");
drop(fs::remove_dir_all(&image));
- build.create_dir(&image);
+ builder.create_dir(&image);
// Prepare the image directory
- build.create_dir(&image.join("share/zsh/site-functions"));
- build.create_dir(&image.join("etc/bash_completion.d"));
+ builder.create_dir(&image.join("share/zsh/site-functions"));
+ builder.create_dir(&image.join("etc/bash_completion.d"));
let cargo = builder.ensure(tool::Cargo {
- compiler: builder.compiler(stage, build.build),
+ compiler: builder.compiler(stage, builder.config.build),
target
});
- build.install(&cargo, &image.join("bin"), 0o755);
+ builder.install(&cargo, &image.join("bin"), 0o755);
for man in t!(etc.join("man").read_dir()) {
let man = t!(man);
- build.install(&man.path(), &image.join("share/man/man1"), 0o644);
+ builder.install(&man.path(), &image.join("share/man/man1"), 0o644);
}
- build.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
- build.copy(&etc.join("cargo.bashcomp.sh"),
+ builder.install(&etc.join("_cargo"), &image.join("share/zsh/site-functions"), 0o644);
+ builder.copy(&etc.join("cargo.bashcomp.sh"),
&image.join("etc/bash_completion.d/cargo"));
let doc = image.join("share/doc/cargo");
- build.install(&src.join("README.md"), &doc, 0o644);
- build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
- build.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
+ builder.install(&src.join("README.md"), &doc, 0o644);
+ builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
+ builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
+ builder.install(&src.join("LICENSE-THIRD-PARTY"), &doc, 0o644);
// Prepare the overlay
let overlay = tmp.join("cargo-overlay");
drop(fs::remove_dir_all(&overlay));
- build.create_dir(&overlay);
- build.install(&src.join("README.md"), &overlay, 0o644);
- build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
- build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
- build.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
- build.create(&overlay.join("version"), &version);
+ builder.create_dir(&overlay);
+ builder.install(&src.join("README.md"), &overlay, 0o644);
+ builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
+ builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
+ builder.install(&src.join("LICENSE-THIRD-PARTY"), &overlay, 0o644);
+ builder.create(&overlay.join("version"), &version);
// Generate the installer tarball
let mut cmd = rust_installer(builder);
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=Rust-is-ready-to-roll.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg("--non-installed-overlay").arg(&overlay)
.arg(format!("--package-name={}-{}", name, target))
.arg("--component-name=cargo")
.arg("--legacy-manifest-dirs=rustlib,cargo");
- build.run(&mut cmd);
- distdir(build).join(format!("{}-{}.tar.gz", name, target))
+ builder.run(&mut cmd);
+ distdir(builder).join(format!("{}-{}.tar.gz", name, target))
}
}
}
fn run(self, builder: &Builder) -> Option<PathBuf> {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- assert!(build.config.extended);
+ assert!(builder.config.extended);
- build.info(&format!("Dist RLS stage{} ({})", stage, target));
- let src = build.src.join("src/tools/rls");
- let release_num = build.release_num("rls");
- let name = pkgname(build, "rls");
- let version = build.rls_info.version(build, &release_num);
+ builder.info(&format!("Dist RLS stage{} ({})", stage, target));
+ let src = builder.src.join("src/tools/rls");
+ let release_num = builder.release_num("rls");
+ let name = pkgname(builder, "rls");
+ let version = builder.rls_info.version(builder, &release_num);
- let tmp = tmpdir(build);
+ let tmp = tmpdir(builder);
let image = tmp.join("rls-image");
drop(fs::remove_dir_all(&image));
t!(fs::create_dir_all(&image));
// We expect RLS to build, because we've exited this step above if tool
// state for RLS isn't testing.
let rls = builder.ensure(tool::Rls {
- compiler: builder.compiler(stage, build.build),
+ compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
}).or_else(|| { println!("Unable to build RLS, skipping dist"); None })?;
- build.install(&rls, &image.join("bin"), 0o755);
+ builder.install(&rls, &image.join("bin"), 0o755);
let doc = image.join("share/doc/rls");
- build.install(&src.join("README.md"), &doc, 0o644);
- build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
+ builder.install(&src.join("README.md"), &doc, 0o644);
+ builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
+ builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
// Prepare the overlay
let overlay = tmp.join("rls-overlay");
drop(fs::remove_dir_all(&overlay));
t!(fs::create_dir_all(&overlay));
- build.install(&src.join("README.md"), &overlay, 0o644);
- build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
- build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
- build.create(&overlay.join("version"), &version);
+ builder.install(&src.join("README.md"), &overlay, 0o644);
+ builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
+ builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
+ builder.create(&overlay.join("version"), &version);
// Generate the installer tarball
let mut cmd = rust_installer(builder);
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=RLS-ready-to-serve.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg("--non-installed-overlay").arg(&overlay)
.arg(format!("--package-name={}-{}", name, target))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=rls-preview");
- build.run(&mut cmd);
- Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
+ builder.run(&mut cmd);
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
}
}
}
fn run(self, builder: &Builder) -> Option<PathBuf> {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- build.info(&format!("Dist Rustfmt stage{} ({})", stage, target));
- let src = build.src.join("src/tools/rustfmt");
- let release_num = build.release_num("rustfmt");
- let name = pkgname(build, "rustfmt");
- let version = build.rustfmt_info.version(build, &release_num);
+ builder.info(&format!("Dist Rustfmt stage{} ({})", stage, target));
+ let src = builder.src.join("src/tools/rustfmt");
+ let release_num = builder.release_num("rustfmt");
+ let name = pkgname(builder, "rustfmt");
+ let version = builder.rustfmt_info.version(builder, &release_num);
- let tmp = tmpdir(build);
+ let tmp = tmpdir(builder);
let image = tmp.join("rustfmt-image");
drop(fs::remove_dir_all(&image));
- build.create_dir(&image);
+ builder.create_dir(&image);
// Prepare the image directory
let rustfmt = builder.ensure(tool::Rustfmt {
- compiler: builder.compiler(stage, build.build),
+ compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
}).or_else(|| { println!("Unable to build Rustfmt, skipping dist"); None })?;
let cargofmt = builder.ensure(tool::Cargofmt {
- compiler: builder.compiler(stage, build.build),
+ compiler: builder.compiler(stage, builder.config.build),
target, extra_features: Vec::new()
}).or_else(|| { println!("Unable to build Cargofmt, skipping dist"); None })?;
- build.install(&rustfmt, &image.join("bin"), 0o755);
- build.install(&cargofmt, &image.join("bin"), 0o755);
+ builder.install(&rustfmt, &image.join("bin"), 0o755);
+ builder.install(&cargofmt, &image.join("bin"), 0o755);
let doc = image.join("share/doc/rustfmt");
- build.install(&src.join("README.md"), &doc, 0o644);
- build.install(&src.join("LICENSE-MIT"), &doc, 0o644);
- build.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
+ builder.install(&src.join("README.md"), &doc, 0o644);
+ builder.install(&src.join("LICENSE-MIT"), &doc, 0o644);
+ builder.install(&src.join("LICENSE-APACHE"), &doc, 0o644);
// Prepare the overlay
let overlay = tmp.join("rustfmt-overlay");
drop(fs::remove_dir_all(&overlay));
- build.create_dir(&overlay);
- build.install(&src.join("README.md"), &overlay, 0o644);
- build.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
- build.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
- build.create(&overlay.join("version"), &version);
+ builder.create_dir(&overlay);
+ builder.install(&src.join("README.md"), &overlay, 0o644);
+ builder.install(&src.join("LICENSE-MIT"), &overlay, 0o644);
+ builder.install(&src.join("LICENSE-APACHE"), &overlay, 0o644);
+ builder.create(&overlay.join("version"), &version);
// Generate the installer tarball
let mut cmd = rust_installer(builder);
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=rustfmt-ready-to-fmt.")
.arg("--image-dir").arg(&image)
- .arg("--work-dir").arg(&tmpdir(build))
- .arg("--output-dir").arg(&distdir(build))
+ .arg("--work-dir").arg(&tmpdir(builder))
+ .arg("--output-dir").arg(&distdir(builder))
.arg("--non-installed-overlay").arg(&overlay)
.arg(format!("--package-name={}-{}", name, target))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=rustfmt-preview");
- build.run(&mut cmd);
- Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
+ builder.run(&mut cmd);
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
}
}
fn make_run(run: RunConfig) {
run.builder.ensure(Extended {
stage: run.builder.top_stage,
- host: run.builder.build.build,
+ host: run.builder.config.build,
target: run.target,
});
}
/// Creates a combined installer for the specified target in the provided stage.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- build.info(&format!("Dist extended stage{} ({})", stage, target));
+ builder.info(&format!("Dist extended stage{} ({})", stage, target));
let rustc_installer = builder.ensure(Rustc {
compiler: builder.compiler(stage, target),
target,
});
- let tmp = tmpdir(build);
+ let tmp = tmpdir(builder);
let overlay = tmp.join("extended-overlay");
- let etc = build.src.join("src/etc/installer");
+ let etc = builder.src.join("src/etc/installer");
let work = tmp.join("work");
let _ = fs::remove_dir_all(&overlay);
- build.install(&build.src.join("COPYRIGHT"), &overlay, 0o644);
- build.install(&build.src.join("LICENSE-APACHE"), &overlay, 0o644);
- build.install(&build.src.join("LICENSE-MIT"), &overlay, 0o644);
- let version = build.rust_version();
- build.create(&overlay.join("version"), &version);
- if let Some(sha) = build.rust_sha() {
- build.create(&overlay.join("git-commit-hash"), &sha);
+ builder.install(&builder.src.join("COPYRIGHT"), &overlay, 0o644);
+ builder.install(&builder.src.join("LICENSE-APACHE"), &overlay, 0o644);
+ builder.install(&builder.src.join("LICENSE-MIT"), &overlay, 0o644);
+ let version = builder.rust_version();
+ builder.create(&overlay.join("version"), &version);
+ if let Some(sha) = builder.rust_sha() {
+ builder.create(&overlay.join("git-commit-hash"), &sha);
}
- build.install(&etc.join("README.md"), &overlay, 0o644);
+ builder.install(&etc.join("README.md"), &overlay, 0o644);
// When rust-std package split from rustc, we needed to ensure that during
// upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
tarballs.extend(rustfmt_installer.clone());
tarballs.push(analysis_installer);
tarballs.push(std_installer);
- if build.config.docs {
+ if builder.config.docs {
tarballs.push(docs_installer);
}
if target.contains("pc-windows-gnu") {
.arg("--rel-manifest-dir=rustlib")
.arg("--success-message=Rust-is-ready-to-roll.")
.arg("--work-dir").arg(&work)
- .arg("--output-dir").arg(&distdir(build))
- .arg(format!("--package-name={}-{}", pkgname(build, "rust"), target))
+ .arg("--output-dir").arg(&distdir(builder))
+ .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--input-tarballs").arg(input_tarballs)
.arg("--non-installed-overlay").arg(&overlay);
- build.run(&mut cmd);
+ builder.run(&mut cmd);
let mut license = String::new();
- license += &build.read(&build.src.join("COPYRIGHT"));
- license += &build.read(&build.src.join("LICENSE-APACHE"));
- license += &build.read(&build.src.join("LICENSE-MIT"));
+ license += &builder.read(&builder.src.join("COPYRIGHT"));
+ license += &builder.read(&builder.src.join("LICENSE-APACHE"));
+ license += &builder.read(&builder.src.join("LICENSE-MIT"));
license.push_str("\n");
license.push_str("\n");
.arg("--scripts").arg(pkg.join(component))
.arg("--nopayload")
.arg(pkg.join(component).with_extension("pkg"));
- build.run(&mut cmd);
+ builder.run(&mut cmd);
};
let prepare = |name: &str| {
- build.create_dir(&pkg.join(name));
- build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)),
+ builder.create_dir(&pkg.join(name));
+ builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target)),
&pkg.join(name));
- build.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
+ builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
pkgbuild(name);
};
prepare("rustc");
}
// create an 'uninstall' package
- build.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
+ builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
pkgbuild("uninstall");
- build.create_dir(&pkg.join("res"));
- build.create(&pkg.join("res/LICENSE.txt"), &license);
- build.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
+ builder.create_dir(&pkg.join("res"));
+ builder.create(&pkg.join("res/LICENSE.txt"), &license);
+ builder.install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
let mut cmd = Command::new("productbuild");
cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
.arg("--resources").arg(pkg.join("res"))
- .arg(distdir(build).join(format!("{}-{}.pkg",
- pkgname(build, "rust"),
+ .arg(distdir(builder).join(format!("{}-{}.pkg",
+ pkgname(builder, "rust"),
target)))
.arg("--package-path").arg(&pkg);
- build.run(&mut cmd);
+ builder.run(&mut cmd);
}
if target.contains("windows") {
let _ = fs::remove_dir_all(&exe);
let prepare = |name: &str| {
- build.create_dir(&exe.join(name));
+ builder.create_dir(&exe.join(name));
let dir = if name == "rust-std" || name == "rust-analysis" {
format!("{}-{}", name, target)
} else if name == "rls" {
} else {
name.to_string()
};
- build.cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target))
+ builder.cp_r(&work.join(&format!("{}-{}", pkgname(builder, name), target))
.join(dir),
&exe.join(name));
- build.remove(&exe.join(name).join("manifest.in"));
+ builder.remove(&exe.join(name).join("manifest.in"));
};
prepare("rustc");
prepare("cargo");
prepare("rust-mingw");
}
- build.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
- build.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
- build.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
- build.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
- build.create(&exe.join("LICENSE.txt"), &license);
+ builder.install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
+ builder.install(&etc.join("exe/modpath.iss"), &exe, 0o644);
+ builder.install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
+ builder.install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
+ builder.create(&exe.join("LICENSE.txt"), &license);
// Generate exe installer
let mut cmd = Command::new("iscc");
if target.contains("windows-gnu") {
cmd.arg("/dMINGW");
}
- add_env(build, &mut cmd, target);
- build.run(&mut cmd);
- build.install(&exe.join(format!("{}-{}.exe", pkgname(build, "rust"), target)),
- &distdir(build),
+ add_env(builder, &mut cmd, target);
+ builder.run(&mut cmd);
+ builder.install(&exe.join(format!("{}-{}.exe", pkgname(builder, "rust"), target)),
+ &distdir(builder),
0o755);
// Generate msi installer
let light = wix.join("bin/light.exe");
let heat_flags = ["-nologo", "-gg", "-sfrag", "-srd", "-sreg"];
- build.run(Command::new(&heat)
+ builder.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("rustc")
.arg("-dr").arg("Rustc")
.arg("-var").arg("var.RustcDir")
.arg("-out").arg(exe.join("RustcGroup.wxs")));
- build.run(Command::new(&heat)
+ builder.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("rust-docs")
.arg("-var").arg("var.DocsDir")
.arg("-out").arg(exe.join("DocsGroup.wxs"))
.arg("-t").arg(etc.join("msi/squash-components.xsl")));
- build.run(Command::new(&heat)
+ builder.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("cargo")
.arg("-var").arg("var.CargoDir")
.arg("-out").arg(exe.join("CargoGroup.wxs"))
.arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
- build.run(Command::new(&heat)
+ builder.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("rust-std")
.arg("-var").arg("var.StdDir")
.arg("-out").arg(exe.join("StdGroup.wxs")));
if rls_installer.is_some() {
- build.run(Command::new(&heat)
+ builder.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("rls")
.arg("-out").arg(exe.join("RlsGroup.wxs"))
.arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
}
- build.run(Command::new(&heat)
+ builder.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("rust-analysis")
.arg("-out").arg(exe.join("AnalysisGroup.wxs"))
.arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
if target.contains("windows-gnu") {
- build.run(Command::new(&heat)
+ builder.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("rust-mingw")
.arg("-arch").arg(&arch)
.arg("-out").arg(&output)
.arg(&input);
- add_env(build, &mut cmd, target);
+ add_env(builder, &mut cmd, target);
if rls_installer.is_some() {
cmd.arg("-dRlsDir=rls");
if target.contains("windows-gnu") {
cmd.arg("-dGccDir=rust-mingw");
}
- build.run(&mut cmd);
+ builder.run(&mut cmd);
};
candle(&xform(&etc.join("msi/rust.wxs")));
candle(&etc.join("msi/ui.wxs"));
candle("GccGroup.wxs".as_ref());
}
- build.create(&exe.join("LICENSE.rtf"), &rtf);
- build.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
- build.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
+ builder.create(&exe.join("LICENSE.rtf"), &rtf);
+ builder.install(&etc.join("gfx/banner.bmp"), &exe, 0o644);
+ builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
- let filename = format!("{}-{}.msi", pkgname(build, "rust"), target);
+ let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
let mut cmd = Command::new(&light);
cmd.arg("-nologo")
.arg("-ext").arg("WixUIExtension")
// ICE57 wrongly complains about the shortcuts
cmd.arg("-sice:ICE57");
- build.run(&mut cmd);
+ builder.run(&mut cmd);
- if !build.config.dry_run {
- t!(fs::rename(exe.join(&filename), distdir(build).join(&filename)));
+ if !builder.config.dry_run {
+ t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
}
}
}
}
-fn add_env(build: &Build, cmd: &mut Command, target: Interned<String>) {
+fn add_env(builder: &Builder, cmd: &mut Command, target: Interned<String>) {
let mut parts = channel::CFG_RELEASE_NUM.split('.');
- cmd.env("CFG_RELEASE_INFO", build.rust_version())
+ cmd.env("CFG_RELEASE_INFO", builder.rust_version())
.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM)
- .env("CFG_RELEASE", build.rust_release())
+ .env("CFG_RELEASE", builder.rust_release())
.env("CFG_VER_MAJOR", parts.next().unwrap())
.env("CFG_VER_MINOR", parts.next().unwrap())
.env("CFG_VER_PATCH", parts.next().unwrap())
.env("CFG_VER_BUILD", "0") // just needed to build
- .env("CFG_PACKAGE_VERS", build.rust_package_vers())
- .env("CFG_PACKAGE_NAME", pkgname(build, "rust"))
+ .env("CFG_PACKAGE_VERS", builder.rust_package_vers())
+ .env("CFG_PACKAGE_NAME", pkgname(builder, "rust"))
.env("CFG_BUILD", target)
- .env("CFG_CHANNEL", &build.config.channel);
+ .env("CFG_CHANNEL", &builder.config.channel);
if target.contains("windows-gnu") {
cmd.env("CFG_MINGW", "1")
}
fn run(self, builder: &Builder) {
- let build = builder.build;
let mut cmd = builder.tool_cmd(Tool::BuildManifest);
- if build.config.dry_run {
+ if builder.config.dry_run {
return;
}
- let sign = build.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
+ let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| {
panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n")
});
- let addr = build.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
+ let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| {
panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n")
});
- let file = build.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
+ let file = builder.config.dist_gpg_password_file.as_ref().unwrap_or_else(|| {
panic!("\n\nfailed to specify `dist.gpg-password-file` in `config.toml`\n\n")
});
let mut pass = String::new();
let today = output(Command::new("date").arg("+%Y-%m-%d"));
cmd.arg(sign);
- cmd.arg(distdir(build));
+ cmd.arg(distdir(builder));
cmd.arg(today.trim());
- cmd.arg(build.rust_package_vers());
- cmd.arg(build.package_vers(&build.release_num("cargo")));
- cmd.arg(build.package_vers(&build.release_num("rls")));
- cmd.arg(build.package_vers(&build.release_num("rustfmt")));
+ cmd.arg(builder.rust_package_vers());
+ cmd.arg(builder.package_vers(&builder.release_num("cargo")));
+ cmd.arg(builder.package_vers(&builder.release_num("rls")));
+ cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
cmd.arg(addr);
- build.create_dir(&distdir(build));
+ builder.create_dir(&distdir(builder));
let mut child = t!(cmd.stdin(Stdio::piped()).spawn());
t!(child.stdin.take().unwrap().write_all(pass.as_bytes()));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Documentation generation for rustbuild.
+//! Documentation generation for rustbuilder.
//!
//! This module implements generation for all bits and pieces of documentation
//! for the Rust project. This notably includes suites like the rust book, the
use std::io;
use std::path::{PathBuf, Path};
-use {Build, Mode};
+use Mode;
use build_helper::up_to_date;
use util::symlink_dir;
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path($path).default_condition(builder.build.config.docs)
+ run.path($path).default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
/// This will not actually generate any documentation if the documentation has
/// already been generated.
fn run(self, builder: &Builder) {
- let src = builder.build.src.join("src/doc");
+ let src = builder.src.join("src/doc");
builder.ensure(RustbookSrc {
target: self.target,
name: self.name,
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/doc/unstable-book").default_condition(builder.build.config.docs)
+ run.path("src/doc/unstable-book").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
builder.ensure(RustbookSrc {
target: self.target,
name: INTERNER.intern_str("unstable-book"),
- src: builder.build.md_doc_out(self.target),
+ src: builder.md_doc_out(self.target),
})
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/tools/cargo/src/doc/book").default_condition(builder.build.config.docs)
+ run.path("src/tools/cargo/src/doc/book").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
}
fn run(self, builder: &Builder) {
- let build = builder.build;
-
let target = self.target;
let name = self.name;
- let src = build.src.join("src/tools/cargo/src/doc");
+ let src = builder.src.join("src/tools/cargo/src/doc");
- let out = build.doc_out(target);
+ let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let out = out.join(name);
- build.info(&format!("Cargo Book ({}) - {}", target, name));
+ builder.info(&format!("Cargo Book ({}) - {}", target, name));
let _ = fs::remove_dir_all(&out);
- build.run(builder.tool_cmd(Tool::Rustbook)
+ builder.run(builder.tool_cmd(Tool::Rustbook)
.arg("build")
.arg(&src)
.arg("-d")
/// This will not actually generate any documentation if the documentation has
/// already been generated.
fn run(self, builder: &Builder) {
- let build = builder.build;
let target = self.target;
let name = self.name;
let src = self.src;
- let out = build.doc_out(target);
+ let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let out = out.join(name);
if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
return
}
- build.info(&format!("Rustbook ({}) - {}", target, name));
+ builder.info(&format!("Rustbook ({}) - {}", target, name));
let _ = fs::remove_dir_all(&out);
- build.run(rustbook_cmd
+ builder.run(rustbook_cmd
.arg("build")
.arg(&src)
.arg("-d")
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/doc/book").default_condition(builder.build.config.docs)
+ run.path("src/doc/book").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
run.builder.ensure(TheBook {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
name: "book",
});
/// * Index page
/// * Redirect pages
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let name = self.name;
// build the index page
let index = format!("{}/index.md", name);
- build.info(&format!("Documenting book index ({})", target));
+ builder.info(&format!("Documenting book index ({})", target));
invoke_rustdoc(builder, compiler, target, &index);
// build the redirect pages
- build.info(&format!("Documenting book redirect pages ({})", target));
- for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) {
+ builder.info(&format!("Documenting book redirect pages ({})", target));
+ for file in t!(fs::read_dir(builder.src.join("src/doc/book/redirects"))) {
let file = t!(file);
let path = file.path();
let path = path.to_str().unwrap();
}
fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String>, markdown: &str) {
- let build = builder.build;
- let out = build.doc_out(target);
+ let out = builder.doc_out(target);
- let path = build.src.join("src/doc").join(markdown);
+ let path = builder.src.join("src/doc").join(markdown);
- let favicon = build.src.join("src/doc/favicon.inc");
- let footer = build.src.join("src/doc/footer.inc");
+ let favicon = builder.src.join("src/doc/favicon.inc");
+ let footer = builder.src.join("src/doc/footer.inc");
let version_info = out.join("version_info.html");
let mut cmd = builder.rustdoc_cmd(compiler.host);
.arg("--markdown-css")
.arg("../rust.css");
- build.run(&mut cmd);
+ builder.run(&mut cmd);
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/doc").default_condition(builder.build.config.docs)
+ run.path("src/doc").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
run.builder.ensure(Standalone {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
///
/// In the end, this is just a glorified wrapper around rustdoc!
fn run(self, builder: &Builder) {
- let build = builder.build;
let target = self.target;
let compiler = self.compiler;
- build.info(&format!("Documenting standalone ({})", target));
- let out = build.doc_out(target);
+ builder.info(&format!("Documenting standalone ({})", target));
+ let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
- let favicon = build.src.join("src/doc/favicon.inc");
- let footer = build.src.join("src/doc/footer.inc");
- let full_toc = build.src.join("src/doc/full-toc.inc");
- t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));
+ let favicon = builder.src.join("src/doc/favicon.inc");
+ let footer = builder.src.join("src/doc/footer.inc");
+ let full_toc = builder.src.join("src/doc/full-toc.inc");
+ t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
- let version_input = build.src.join("src/doc/version_info.html.template");
+ let version_input = builder.src.join("src/doc/version_info.html.template");
let version_info = out.join("version_info.html");
- if !build.config.dry_run && !up_to_date(&version_input, &version_info) {
+ if !builder.config.dry_run && !up_to_date(&version_input, &version_info) {
let mut info = String::new();
t!(t!(File::open(&version_input)).read_to_string(&mut info));
- let info = info.replace("VERSION", &build.rust_release())
- .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or(""))
- .replace("STAMP", build.rust_info.sha().unwrap_or(""));
+ let info = info.replace("VERSION", &builder.rust_release())
+ .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or(""))
+ .replace("STAMP", builder.rust_info.sha().unwrap_or(""));
t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
}
- for file in t!(fs::read_dir(build.src.join("src/doc"))) {
+ for file in t!(fs::read_dir(builder.src.join("src/doc"))) {
let file = t!(file);
let path = file.path();
let filename = path.file_name().unwrap().to_str().unwrap();
up_to_date(&favicon, &html) &&
up_to_date(&full_toc, &html) &&
up_to_date(&version_info, &html) &&
- (build.config.dry_run || up_to_date(&rustdoc, &html)) {
+ (builder.config.dry_run || up_to_date(&rustdoc, &html)) {
continue
}
} else {
cmd.arg("--markdown-css").arg("rust.css");
}
- build.run(&mut cmd);
+ builder.run(&mut cmd);
}
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.all_krates("std").default_condition(builder.build.config.docs)
+ run.all_krates("std").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
/// This will generate all documentation for the standard library and its
/// dependencies. This is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- build.info(&format!("Documenting stage{} std ({})", stage, target));
- let out = build.doc_out(target);
+ builder.info(&format!("Documenting stage{} std ({})", stage, target));
+ let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
- let compiler = builder.compiler(stage, build.build);
+ let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
- let compiler = if build.force_use_stage1(compiler, target) {
+ let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
};
builder.ensure(compile::Std { compiler, target });
- let out_dir = build.stage_out(compiler, Mode::Libstd)
+ let out_dir = builder.stage_out(compiler, Mode::Libstd)
.join(target).join("doc");
// Here what we're doing is creating a *symlink* (directory junction on
//
// This way rustdoc generates output directly into the output, and rustdoc
// will also directly handle merging.
- let my_out = build.crate_doc_out(target);
- build.clear_if_dirty(&my_out, &rustdoc);
- t!(symlink_dir_force(&build.config, &my_out, &out_dir));
+ let my_out = builder.crate_doc_out(target);
+ builder.clear_if_dirty(&my_out, &rustdoc);
+ t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc");
compile::std_cargo(builder, &compiler, target, &mut cargo);
t!(fs::create_dir_all(out_dir.join(krate)));
}
- build.run(&mut cargo);
- build.cp_r(&my_out, &out);
+ builder.run(&mut cargo);
+ builder.cp_r(&my_out, &out);
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.krate("test").default_condition(builder.build.config.docs)
+ run.krate("test").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
/// This will generate all documentation for libtest and its dependencies. This
/// is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- build.info(&format!("Documenting stage{} test ({})", stage, target));
- let out = build.doc_out(target);
+ builder.info(&format!("Documenting stage{} test ({})", stage, target));
+ let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
- let compiler = builder.compiler(stage, build.build);
+ let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
- let compiler = if build.force_use_stage1(compiler, target) {
+ let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
builder.ensure(Std { stage, target });
builder.ensure(compile::Test { compiler, target });
- let out_dir = build.stage_out(compiler, Mode::Libtest)
+ let out_dir = builder.stage_out(compiler, Mode::Libtest)
.join(target).join("doc");
// See docs in std above for why we symlink
- let my_out = build.crate_doc_out(target);
- build.clear_if_dirty(&my_out, &rustdoc);
+ let my_out = builder.crate_doc_out(target);
+ builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc");
- compile::test_cargo(build, &compiler, target, &mut cargo);
+ compile::test_cargo(builder, &compiler, target, &mut cargo);
cargo.arg("--no-deps").arg("-p").arg("test");
- build.run(&mut cargo);
- build.cp_r(&my_out, &out);
+ builder.run(&mut cargo);
+ builder.cp_r(&my_out, &out);
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.krate("rustc-main").default_condition(builder.build.config.docs)
+ run.krate("rustc-main").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
/// here as we want to be able to keep it separate from the standard
/// documentation. This is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- build.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target));
- let out = build.doc_out(target);
+ builder.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target));
+ let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
- let compiler = builder.compiler(stage, build.build);
+ let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
- let compiler = if build.force_use_stage1(compiler, target) {
+ let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
builder.ensure(Std { stage, target });
builder.ensure(compile::Rustc { compiler, target });
- let out_dir = build.stage_out(compiler, Mode::Librustc)
+ let out_dir = builder.stage_out(compiler, Mode::Librustc)
.join(target).join("doc");
// See docs in std above for why we symlink
- let my_out = build.crate_doc_out(target);
- build.clear_if_dirty(&my_out, &rustdoc);
+ let my_out = builder.crate_doc_out(target);
+ builder.clear_if_dirty(&my_out, &rustdoc);
t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
- compile::rustc_cargo(build, &mut cargo);
+ compile::rustc_cargo(builder, &mut cargo);
// We don't want to build docs for internal compiler dependencies in this
// step (there is another step for that). Therefore, we whitelist the crates
cargo.arg("-p").arg(krate);
}
- build.run(&mut cargo);
- build.cp_r(&my_out, &out);
+ builder.run(&mut cargo);
+ builder.cp_r(&my_out, &out);
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.krate("rustc-main").default_condition(builder.build.config.docs)
+ run.krate("rustc-main").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
/// we do not merge it with the other documentation from std, test and
/// proc_macros. This is largely just a wrapper around `cargo doc`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let target = self.target;
- build.info(&format!("Documenting stage{} compiler ({})", stage, target));
- let out = build.compiler_doc_out(target);
+ builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
+ let out = builder.compiler_doc_out(target);
t!(fs::create_dir_all(&out));
- let compiler = builder.compiler(stage, build.build);
+ let compiler = builder.compiler(stage, builder.config.build);
let rustdoc = builder.rustdoc(compiler.host);
- let compiler = if build.force_use_stage1(compiler, target) {
+ let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler
};
- if !build.config.compiler_docs {
- build.info(&format!("\tskipping - compiler docs disabled"));
+ if !builder.config.compiler_docs {
+ builder.info(&format!("\tskipping - compiler docs disabled"));
return;
}
builder.ensure(Std { stage, target });
builder.ensure(compile::Rustc { compiler, target });
- let out_dir = build.stage_out(compiler, Mode::Librustc)
+ let out_dir = builder.stage_out(compiler, Mode::Librustc)
.join(target).join("doc");
// We do not symlink to the same shared folder that already contains std library
// documentation from previous steps as we do not want to include that.
- build.clear_if_dirty(&out, &rustdoc);
+ builder.clear_if_dirty(&out, &rustdoc);
t!(symlink_dir_force(&builder.config, &out, &out_dir));
let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
cargo.env("RUSTDOCFLAGS", "--document-private-items");
- compile::rustc_cargo(build, &mut cargo);
+ compile::rustc_cargo(builder, &mut cargo);
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("--no-deps");
let mut compiler_crates = HashSet::new();
for root_crate in &["rustc", "rustc_driver"] {
let interned_root_crate = INTERNER.intern_str(root_crate);
- find_compiler_crates(&build, &interned_root_crate, &mut compiler_crates);
+ find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates);
}
for krate in &compiler_crates {
cargo.arg("-p").arg(krate);
}
- build.run(&mut cargo);
+ builder.run(&mut cargo);
}
}
fn find_compiler_crates(
- build: &Build,
+ builder: &Builder,
name: &Interned<String>,
crates: &mut HashSet<Interned<String>>
) {
crates.insert(*name);
// Look for dependencies.
- for dep in build.crates.get(name).unwrap().deps.iter() {
- if build.crates.get(dep).unwrap().is_local(build) {
- find_compiler_crates(build, dep, crates);
+ for dep in builder.crates.get(name).unwrap().deps.iter() {
+ if builder.crates.get(dep).unwrap().is_local(builder) {
+ find_compiler_crates(builder, dep, crates);
}
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/tools/error_index_generator").default_condition(builder.build.config.docs)
+ run.path("src/tools/error_index_generator").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
/// Generates the HTML rendered error-index by running the
/// `error_index_generator` tool.
fn run(self, builder: &Builder) {
- let build = builder.build;
let target = self.target;
- build.info(&format!("Documenting error index ({})", target));
- let out = build.doc_out(target);
+ builder.info(&format!("Documenting error index ({})", target));
+ let out = builder.doc_out(target);
t!(fs::create_dir_all(&out));
let mut index = builder.tool_cmd(Tool::ErrorIndex);
index.arg("html");
index.arg(out.join("error-index.html"));
// FIXME: shouldn't have to pass this env var
- index.env("CFG_BUILD", &build.build)
- .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir());
+ index.env("CFG_BUILD", &builder.config.build)
+ .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
- build.run(&mut index);
+ builder.run(&mut index);
}
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/tools/unstable-book-gen").default_condition(builder.build.config.docs)
+ run.path("src/tools/unstable-book-gen").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
}
fn run(self, builder: &Builder) {
- let build = builder.build;
let target = self.target;
builder.ensure(compile::Std {
- compiler: builder.compiler(builder.top_stage, build.build),
+ compiler: builder.compiler(builder.top_stage, builder.config.build),
target,
});
- build.info(&format!("Generating unstable book md files ({})", target));
- let out = build.md_doc_out(target).join("unstable-book");
- build.create_dir(&out);
- build.remove_dir(&out);
+ builder.info(&format!("Generating unstable book md files ({})", target));
+ let out = builder.md_doc_out(target).join("unstable-book");
+ builder.create_dir(&out);
+ builder.remove_dir(&out);
let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
- cmd.arg(build.src.join("src"));
+ cmd.arg(builder.src.join("src"));
cmd.arg(out);
- build.run(&mut cmd);
+ builder.run(&mut cmd);
}
}
stage: u32,
host: Option<Interned<String>>
) {
- let build = builder.build;
- build.info(&format!("Install {} stage{} ({:?})", package, stage, host));
+ builder.info(&format!("Install {} stage{} ({:?})", package, stage, host));
let prefix_default = PathBuf::from("/usr/local");
let sysconfdir_default = PathBuf::from("/etc");
let bindir_default = PathBuf::from("bin");
let libdir_default = PathBuf::from("lib");
let mandir_default = datadir_default.join("man");
- let prefix = build.config.prefix.as_ref().map_or(prefix_default, |p| {
+ let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| {
fs::canonicalize(p).expect(&format!("could not canonicalize {}", p.display()))
});
- let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
- let datadir = build.config.datadir.as_ref().unwrap_or(&datadir_default);
- let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
- let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default);
- let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
- let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);
+ let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
+ let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default);
+ let docdir = builder.config.docdir.as_ref().unwrap_or(&docdir_default);
+ let bindir = builder.config.bindir.as_ref().unwrap_or(&bindir_default);
+ let libdir = builder.config.libdir.as_ref().unwrap_or(&libdir_default);
+ let mandir = builder.config.mandir.as_ref().unwrap_or(&mandir_default);
let sysconfdir = prefix.join(sysconfdir);
let datadir = prefix.join(datadir);
let libdir = add_destdir(&libdir, &destdir);
let mandir = add_destdir(&mandir, &destdir);
- let empty_dir = build.out.join("tmp/empty_dir");
+ let empty_dir = builder.out.join("tmp/empty_dir");
t!(fs::create_dir_all(&empty_dir));
let package_name = if let Some(host) = host {
- format!("{}-{}", pkgname(build, name), host)
+ format!("{}-{}", pkgname(builder, name), host)
} else {
- pkgname(build, name)
+ pkgname(builder, name)
};
let mut cmd = Command::new("sh");
cmd.current_dir(&empty_dir)
- .arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
+ .arg(sanitize_sh(&tmpdir(builder).join(&package_name).join("install.sh")))
.arg(format!("--prefix={}", sanitize_sh(&prefix)))
.arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
.arg(format!("--datadir={}", sanitize_sh(&datadir)))
.arg(format!("--libdir={}", sanitize_sh(&libdir)))
.arg(format!("--mandir={}", sanitize_sh(&mandir)))
.arg("--disable-ldconfig");
- build.run(&mut cmd);
+ builder.run(&mut cmd);
t!(fs::remove_dir_all(&empty_dir));
}
run.builder.ensure($name {
stage: run.builder.top_stage,
target: run.target,
- host: run.builder.build.build,
+ host: run.builder.config.build,
});
}
install_docs(builder, self.stage, self.target);
};
Std, "src/libstd", true, only_hosts: true, {
- for target in &builder.build.targets {
+ for target in &builder.targets {
builder.ensure(dist::Std {
compiler: builder.compiler(self.stage, self.host),
target: *target
use cmake;
use cc;
-use Build;
use util::{self, exe};
use build_helper::up_to_date;
use builder::{Builder, RunConfig, ShouldRun, Step};
/// Compile LLVM for `target`.
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let target = self.target;
let emscripten = self.emscripten;
// If we're using a custom LLVM bail out here, but we can only use a
// custom LLVM for the build triple.
if !self.emscripten {
- if let Some(config) = build.config.target_config.get(&target) {
+ if let Some(config) = builder.config.target_config.get(&target) {
if let Some(ref s) = config.llvm_config {
- check_llvm_version(build, s);
+ check_llvm_version(builder, s);
return s.to_path_buf()
}
}
}
- let rebuild_trigger = build.src.join("src/rustllvm/llvm-rebuild-trigger");
+ let rebuild_trigger = builder.src.join("src/rustllvm/llvm-rebuild-trigger");
let mut rebuild_trigger_contents = String::new();
t!(t!(File::open(&rebuild_trigger)).read_to_string(&mut rebuild_trigger_contents));
let (out_dir, llvm_config_ret_dir) = if emscripten {
- let dir = build.emscripten_llvm_out(target);
+ let dir = builder.emscripten_llvm_out(target);
let config_dir = dir.join("bin");
(dir, config_dir)
} else {
- let mut dir = build.llvm_out(build.config.build);
- if !build.config.build.contains("msvc") || build.config.ninja {
+ let mut dir = builder.llvm_out(builder.config.build);
+ if !builder.config.build.contains("msvc") || builder.config.ninja {
dir.push("build");
}
- (build.llvm_out(target), dir.join("bin"))
+ (builder.llvm_out(target), dir.join("bin"))
};
let done_stamp = out_dir.join("llvm-finished-building");
let build_llvm_config = llvm_config_ret_dir
- .join(exe("llvm-config", &*build.config.build));
+ .join(exe("llvm-config", &*builder.config.build));
if done_stamp.exists() {
let mut done_contents = String::new();
t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents));
}
}
- let _folder = build.fold_output(|| "llvm");
+ let _folder = builder.fold_output(|| "llvm");
let descriptor = if emscripten { "Emscripten " } else { "" };
- build.info(&format!("Building {}LLVM for {}", descriptor, target));
- let _time = util::timeit(&build);
+ builder.info(&format!("Building {}LLVM for {}", descriptor, target));
+ let _time = util::timeit(&builder);
t!(fs::create_dir_all(&out_dir));
// http://llvm.org/docs/CMake.html
let root = if self.emscripten { "src/llvm-emscripten" } else { "src/llvm" };
- let mut cfg = cmake::Config::new(build.src.join(root));
+ let mut cfg = cmake::Config::new(builder.src.join(root));
- let profile = match (build.config.llvm_optimize, build.config.llvm_release_debuginfo) {
+ let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
(false, _) => "Debug",
(true, false) => "Release",
(true, true) => "RelWithDebInfo",
let llvm_targets = if self.emscripten {
"JSBackend"
} else {
- match build.config.llvm_targets {
+ match builder.config.llvm_targets {
Some(ref s) => s,
None => "X86;ARM;AArch64;Mips;PowerPC;SystemZ;MSP430;Sparc;NVPTX;Hexagon",
}
let llvm_exp_targets = if self.emscripten {
""
} else {
- &build.config.llvm_experimental_targets[..]
+ &builder.config.llvm_experimental_targets[..]
};
- let assertions = if build.config.llvm_assertions {"ON"} else {"OFF"};
+ let assertions = if builder.config.llvm_assertions {"ON"} else {"OFF"};
cfg.out_dir(&out_dir)
.profile(profile)
.define("WITH_POLLY", "OFF")
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
- .define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string())
+ .define("LLVM_ENABLE_LIBXML2", "OFF")
+ .define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
cfg.define("LLVM_BUILD_32_BITS", "ON");
}
- if let Some(num_linkers) = build.config.llvm_link_jobs {
+ if let Some(num_linkers) = builder.config.llvm_link_jobs {
if num_linkers > 0 {
cfg.define("LLVM_PARALLEL_LINK_JOBS", num_linkers.to_string());
}
}
// http://llvm.org/docs/HowToCrossCompileLLVM.html
- if target != build.build && !emscripten {
+ if target != builder.config.build && !emscripten {
builder.ensure(Llvm {
- target: build.build,
+ target: builder.config.build,
emscripten: false,
});
// FIXME: if the llvm root for the build triple is overridden then we
// should use llvm-tblgen from there, also should verify that it
// actually exists most of the time in normal installs of LLVM.
- let host = build.llvm_out(build.build).join("bin/llvm-tblgen");
+ let host = builder.llvm_out(builder.config.build).join("bin/llvm-tblgen");
cfg.define("CMAKE_CROSSCOMPILING", "True")
.define("LLVM_TABLEGEN", &host);
cfg.define("CMAKE_SYSTEM_NAME", "FreeBSD");
}
- cfg.define("LLVM_NATIVE_BUILD", build.llvm_out(build.build).join("build"));
+ cfg.define("LLVM_NATIVE_BUILD", builder.llvm_out(builder.config.build).join("build"));
}
- configure_cmake(build, target, &mut cfg, false);
+ configure_cmake(builder, target, &mut cfg, false);
// FIXME: we don't actually need to build all LLVM tools and all LLVM
// libraries here, e.g. we just want a few components and a few
}
}
-fn check_llvm_version(build: &Build, llvm_config: &Path) {
- if !build.config.llvm_version_check {
+fn check_llvm_version(builder: &Builder, llvm_config: &Path) {
+ if !builder.config.llvm_version_check {
return
}
- if build.config.dry_run {
+ if builder.config.dry_run {
return;
}
panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version)
}
-fn configure_cmake(build: &Build,
+fn configure_cmake(builder: &Builder,
target: Interned<String>,
cfg: &mut cmake::Config,
building_dist_binaries: bool) {
- if build.config.ninja {
+ if builder.config.ninja {
cfg.generator("Ninja");
}
cfg.target(&target)
- .host(&build.config.build);
+ .host(&builder.config.build);
let sanitize_cc = |cc: &Path| {
if target.contains("msvc") {
// MSVC with CMake uses msbuild by default which doesn't respect these
// vars that we'd otherwise configure. In that case we just skip this
// entirely.
- if target.contains("msvc") && !build.config.ninja {
+ if target.contains("msvc") && !builder.config.ninja {
return
}
- let cc = build.cc(target);
- let cxx = build.cxx(target).unwrap();
+ let cc = builder.cc(target);
+ let cxx = builder.cxx(target).unwrap();
// Handle msvc + ninja + ccache specially (this is what the bots use)
if target.contains("msvc") &&
- build.config.ninja &&
- build.config.ccache.is_some() {
+ builder.config.ninja &&
+ builder.config.ccache.is_some() {
let mut cc = env::current_exe().expect("failed to get cwd");
cc.set_file_name("sccache-plus-cl.exe");
cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc))
.define("CMAKE_CXX_COMPILER", sanitize_cc(&cc));
cfg.env("SCCACHE_PATH",
- build.config.ccache.as_ref().unwrap())
+ builder.config.ccache.as_ref().unwrap())
.env("SCCACHE_TARGET", target);
// If ccache is configured we inform the build a little differently hwo
// to invoke ccache while also invoking our compilers.
- } else if let Some(ref ccache) = build.config.ccache {
+ } else if let Some(ref ccache) = builder.config.ccache {
cfg.define("CMAKE_C_COMPILER", ccache)
.define("CMAKE_C_COMPILER_ARG1", sanitize_cc(cc))
.define("CMAKE_CXX_COMPILER", ccache)
.define("CMAKE_CXX_COMPILER", sanitize_cc(cxx));
}
- cfg.build_arg("-j").build_arg(build.jobs().to_string());
- cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" "));
- let mut cxxflags = build.cflags(target).join(" ");
+ cfg.build_arg("-j").build_arg(builder.jobs().to_string());
+ cfg.define("CMAKE_C_FLAGS", builder.cflags(target).join(" "));
+ let mut cxxflags = builder.cflags(target).join(" ");
if building_dist_binaries {
- if build.config.llvm_static_stdcpp && !target.contains("windows") {
+ if builder.config.llvm_static_stdcpp && !target.contains("windows") {
cxxflags.push_str(" -static-libstdc++");
}
}
cfg.define("CMAKE_CXX_FLAGS", cxxflags);
- if let Some(ar) = build.ar(target) {
+ if let Some(ar) = builder.ar(target) {
if ar.is_absolute() {
// LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it
// tries to resolve this path in the LLVM build directory.
return PathBuf::from("lld-out-dir-test-gen");
}
let target = self.target;
- let build = builder.build;
let llvm_config = builder.ensure(Llvm {
target: self.target,
emscripten: false,
});
- let out_dir = build.lld_out(target);
+ let out_dir = builder.lld_out(target);
let done_stamp = out_dir.join("lld-finished-building");
if done_stamp.exists() {
return out_dir
}
- let _folder = build.fold_output(|| "lld");
- build.info(&format!("Building LLD for {}", target));
- let _time = util::timeit(&build);
+ let _folder = builder.fold_output(|| "lld");
+ builder.info(&format!("Building LLD for {}", target));
+ let _time = util::timeit(&builder);
t!(fs::create_dir_all(&out_dir));
- let mut cfg = cmake::Config::new(build.src.join("src/tools/lld"));
- configure_cmake(build, target, &mut cfg, true);
+ let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld"));
+ configure_cmake(builder, target, &mut cfg, true);
cfg.out_dir(&out_dir)
.profile("Release")
if builder.config.dry_run {
return;
}
- let build = builder.build;
let target = self.target;
- let dst = build.test_helpers_out(target);
- let src = build.src.join("src/test/auxiliary/rust_test_helpers.c");
+ let dst = builder.test_helpers_out(target);
+ let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c");
if up_to_date(&src, &dst.join("librust_test_helpers.a")) {
return
}
- let _folder = build.fold_output(|| "build_test_helpers");
- build.info(&format!("Building test helpers"));
+ let _folder = builder.fold_output(|| "build_test_helpers");
+ builder.info(&format!("Building test helpers"));
t!(fs::create_dir_all(&dst));
let mut cfg = cc::Build::new();
// extra configuration, so inform gcc of these compilers. Note, though, that
// on MSVC we still need gcc's detection of env vars (ugh).
if !target.contains("msvc") {
- if let Some(ar) = build.ar(target) {
+ if let Some(ar) = builder.ar(target) {
cfg.archiver(ar);
}
- cfg.compiler(build.cc(target));
+ cfg.compiler(builder.cc(target));
}
cfg.cargo_metadata(false)
.out_dir(&dst)
.target(&target)
- .host(&build.build)
+ .host(&builder.config.build)
.opt_level(0)
.warnings(false)
.debug(false)
- .file(build.src.join("src/test/auxiliary/rust_test_helpers.c"))
+ .file(builder.src.join("src/test/auxiliary/rust_test_helpers.c"))
.compile("rust_test_helpers");
}
}
if builder.config.dry_run {
return;
}
- let build = builder.build;
let target = self.target;
- let out = match build.openssl_dir(target) {
+ let out = match builder.openssl_dir(target) {
Some(dir) => dir,
None => return,
};
}
// Ensure the hash is correct.
- let mut shasum = if target.contains("apple") || build.build.contains("netbsd") {
+ let mut shasum = if target.contains("apple") ||
+ builder.config.build.contains("netbsd") {
let mut cmd = Command::new("shasum");
cmd.arg("-a").arg("256");
cmd
t!(fs::rename(&tmp, &tarball));
}
let obj = out.join(format!("openssl-{}", OPENSSL_VERS));
- let dst = build.openssl_install_dir(target).unwrap();
+ let dst = builder.openssl_install_dir(target).unwrap();
drop(fs::remove_dir_all(&obj));
drop(fs::remove_dir_all(&dst));
- build.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out));
+ builder.run(Command::new("tar").arg("zxf").arg(&tarball).current_dir(&out));
let mut configure = Command::new("perl");
configure.arg(obj.join("Configure"));
_ => panic!("don't know how to configure OpenSSL for {}", target),
};
configure.arg(os);
- configure.env("CC", build.cc(target));
- for flag in build.cflags(target) {
+ configure.env("CC", builder.cc(target));
+ for flag in builder.cflags(target) {
configure.arg(flag);
}
// There is no specific os target for android aarch64 or x86_64,
if target == "sparc64-unknown-netbsd" {
// Need -m64 to get assembly generated correctly for sparc64.
configure.arg("-m64");
- if build.build.contains("netbsd") {
+ if builder.config.build.contains("netbsd") {
// Disable sparc64 asm on NetBSD builders, it uses
// m4(1)'s -B flag, which NetBSD m4 does not support.
configure.arg("no-asm");
configure.arg("no-asm");
}
configure.current_dir(&obj);
- build.info(&format!("Configuring openssl for {}", target));
- build.run_quiet(&mut configure);
- build.info(&format!("Building openssl for {}", target));
- build.run_quiet(Command::new("make").arg("-j1").current_dir(&obj));
- build.info(&format!("Installing openssl for {}", target));
- build.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj));
+ builder.info(&format!("Configuring openssl for {}", target));
+ builder.run_quiet(&mut configure);
+ builder.info(&format!("Building openssl for {}", target));
+ builder.run_quiet(Command::new("make").arg("-j1").current_dir(&obj));
+ builder.info(&format!("Installing openssl for {}", target));
+ builder.run_quiet(Command::new("make").arg("install").arg("-j1").current_dir(&obj));
let mut f = t!(File::create(&stamp));
t!(f.write_all(OPENSSL_VERS.as_bytes()));
continue;
}
- cmd_finder.must_have(build.cc(*target));
- if let Some(ar) = build.ar(*target) {
- cmd_finder.must_have(ar);
+ if !build.config.dry_run {
+ cmd_finder.must_have(build.cc(*target));
+ if let Some(ar) = build.ar(*target) {
+ cmd_finder.must_have(ar);
+ }
}
}
for host in &build.hosts {
- cmd_finder.must_have(build.cxx(*host).unwrap());
+ if !build.config.dry_run {
+ cmd_finder.must_have(build.cxx(*host).unwrap());
+ }
// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
use native;
use tool::{self, Tool};
use util::{self, dylib_path, dylib_path_var};
-use {Build, Mode};
+use Mode;
use toolstate::ToolState;
const ADB_TEST_DIR: &str = "/data/tmp/work";
}
}
-fn try_run(build: &Build, cmd: &mut Command) -> bool {
- if !build.fail_fast {
- if !build.try_run(cmd) {
- let mut failures = build.delayed_failures.borrow_mut();
+fn try_run(builder: &Builder, cmd: &mut Command) -> bool {
+ if !builder.fail_fast {
+ if !builder.try_run(cmd) {
+ let mut failures = builder.delayed_failures.borrow_mut();
failures.push(format!("{:?}", cmd));
return false;
}
} else {
- build.run(cmd);
+ builder.run(cmd);
}
true
}
-fn try_run_quiet(build: &Build, cmd: &mut Command) -> bool {
- if !build.fail_fast {
- if !build.try_run_quiet(cmd) {
- let mut failures = build.delayed_failures.borrow_mut();
+fn try_run_quiet(builder: &Builder, cmd: &mut Command) -> bool {
+ if !builder.fail_fast {
+ if !builder.try_run_quiet(cmd) {
+ let mut failures = builder.delayed_failures.borrow_mut();
failures.push(format!("{:?}", cmd));
return false;
}
} else {
- build.run_quiet(cmd);
+ builder.run_quiet(cmd);
}
true
}
/// This tool in `src/tools` will verify the validity of all our links in the
/// documentation to ensure we don't have a bunch of dead ones.
fn run(self, builder: &Builder) {
- let build = builder.build;
let host = self.host;
- build.info(&format!("Linkcheck ({})", host));
+ builder.info(&format!("Linkcheck ({})", host));
builder.default_doc(None);
- let _time = util::timeit(&build);
- try_run(build, builder.tool_cmd(Tool::Linkchecker)
- .arg(build.out.join(host).join("doc")));
+ let _time = util::timeit(&builder);
+ try_run(builder, builder.tool_cmd(Tool::Linkchecker)
+ .arg(builder.out.join(host).join("doc")));
}
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/tools/linkchecker").default_condition(builder.build.config.docs)
+ run.path("src/tools/linkchecker").default_condition(builder.config.docs)
}
fn make_run(run: RunConfig) {
/// This tool in `src/tools` will check out a few Rust projects and run `cargo
/// test` to ensure that we don't regress the test suites there.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(compile::Rustc { compiler, target: compiler.host });
// Note that this is a short, cryptic, and not scoped directory name. This
// is currently to minimize the length of path on Windows where we otherwise
// quickly run into path name limit constraints.
- let out_dir = build.out.join("ct");
+ let out_dir = builder.out.join("ct");
t!(fs::create_dir_all(&out_dir));
- let _time = util::timeit(&build);
+ let _time = util::timeit(&builder);
let mut cmd = builder.tool_cmd(Tool::CargoTest);
- try_run(build, cmd.arg(&build.initial_cargo)
+ try_run(builder, cmd.arg(&builder.initial_cargo)
.arg(&out_dir)
.env("RUSTC", builder.rustc(compiler))
.env("RUSTDOC", builder.rustdoc(compiler.host)));
/// Runs `cargo test` for `cargo` packaged with Rust.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = builder.compiler(self.stage, self.host);
builder.ensure(tool::Cargo { compiler, target: self.host });
let mut cargo = builder.cargo(compiler, Mode::Tool, self.host, "test");
- cargo.arg("--manifest-path").arg(build.src.join("src/tools/cargo/Cargo.toml"));
- if !build.fail_fast {
+ cargo.arg("--manifest-path").arg(builder.src.join("src/tools/cargo/Cargo.toml"));
+ if !builder.fail_fast {
cargo.arg("--no-fail-fast");
}
// available.
cargo.env("CFG_DISABLE_CROSS_TESTS", "1");
- try_run(build, cargo.env("PATH", &path_for_cargo(builder, compiler)));
+ try_run(builder, cargo.env("PATH", &path_for_cargo(builder, compiler)));
}
}
/// Runs `cargo test` for the rls.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
- builder.ensure(tool::Rls { compiler, target: self.host, extra_features: Vec::new() });
+ let build_result = builder.ensure(tool::Rls {
+ compiler,
+ target: self.host,
+ extra_features: Vec::new(),
+ });
+ if build_result.is_none() {
+ eprintln!("failed to test rls: could not build");
+ return;
+ }
+
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
host,
builder.add_rustc_lib_path(compiler, &mut cargo);
- if try_run(build, &mut cargo) {
- build.save_toolstate("rls", ToolState::TestPass);
+ if try_run(builder, &mut cargo) {
+ builder.save_toolstate("rls", ToolState::TestPass);
}
}
}
/// Runs `cargo test` for rustfmt.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
- builder.ensure(tool::Rustfmt { compiler, target: self.host, extra_features: Vec::new() });
+ let build_result = builder.ensure(tool::Rustfmt {
+ compiler,
+ target: self.host,
+ extra_features: Vec::new(),
+ });
+ if build_result.is_none() {
+ eprintln!("failed to test rustfmt: could not build");
+ return;
+ }
+
let mut cargo = tool::prepare_tool_cargo(builder,
compiler,
host,
builder.add_rustc_lib_path(compiler, &mut cargo);
- if try_run(build, &mut cargo) {
- build.save_toolstate("rustfmt", ToolState::TestPass);
+ if try_run(builder, &mut cargo) {
+ builder.save_toolstate("rustfmt", ToolState::TestPass);
}
}
}
const DEFAULT: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
- let test_miri = run.builder.build.config.test_miri;
+ let test_miri = run.builder.config.test_miri;
run.path("src/tools/miri").default_condition(test_miri)
}
/// Runs `cargo test` for miri.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
});
if let Some(miri) = miri {
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
- cargo.arg("--manifest-path").arg(build.src.join("src/tools/miri/Cargo.toml"));
+ cargo.arg("--manifest-path").arg(builder.src.join("src/tools/miri/Cargo.toml"));
// Don't build tests dynamically, just a pain to work with
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
builder.add_rustc_lib_path(compiler, &mut cargo);
- if try_run(build, &mut cargo) {
- build.save_toolstate("miri", ToolState::TestPass);
+ if try_run(builder, &mut cargo) {
+ builder.save_toolstate("miri", ToolState::TestPass);
}
} else {
eprintln!("failed to test miri: could not build");
/// Runs `cargo test` for clippy.
fn run(self, builder: &Builder) {
- let build = builder.build;
let stage = self.stage;
let host = self.host;
let compiler = builder.compiler(stage, host);
});
if let Some(clippy) = clippy {
let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test");
- cargo.arg("--manifest-path").arg(build.src.join("src/tools/clippy/Cargo.toml"));
+ cargo.arg("--manifest-path").arg(builder.src.join("src/tools/clippy/Cargo.toml"));
// Don't build tests dynamically, just a pain to work with
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
builder.add_rustc_lib_path(compiler, &mut cargo);
- if try_run(build, &mut cargo) {
- build.save_toolstate("clippy-driver", ToolState::TestPass);
+ if try_run(builder, &mut cargo) {
+ builder.save_toolstate("clippy-driver", ToolState::TestPass);
}
} else {
eprintln!("failed to test clippy: could not build");
.env("RUSTC_STAGE", self.compiler.stage.to_string())
.env("RUSTC_SYSROOT", builder.sysroot(self.compiler))
.env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host))
- .env("CFG_RELEASE_CHANNEL", &builder.build.config.channel)
+ .env("CFG_RELEASE_CHANNEL", &builder.config.channel)
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host))
- .env("RUSTDOC_CRATE_VERSION", builder.build.rust_version())
+ .env("RUSTDOC_CRATE_VERSION", builder.rust_version())
.env("RUSTC_BOOTSTRAP", "1");
- if let Some(linker) = builder.build.linker(self.compiler.host) {
+ if let Some(linker) = builder.linker(self.compiler.host) {
cmd.env("RUSTC_TARGET_LINKER", linker);
}
- try_run(builder.build, &mut cmd);
+ try_run(builder, &mut cmd);
}
}
}
}
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct RustdocUi {
+ pub host: Interned<String>,
+ pub target: Interned<String>,
+ pub compiler: Compiler,
+}
+
+impl Step for RustdocUi {
+ type Output = ();
+ const DEFAULT: bool = true;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun) -> ShouldRun {
+ run.path("src/test/rustdoc-ui")
+ }
+
+ fn make_run(run: RunConfig) {
+ let compiler = run.builder.compiler(run.builder.top_stage, run.host);
+ run.builder.ensure(RustdocUi {
+ host: run.host,
+ target: run.target,
+ compiler,
+ });
+ }
+
+ fn run(self, builder: &Builder) {
+ builder.ensure(Compiletest {
+ compiler: self.compiler,
+ target: self.target,
+ mode: "ui",
+ suite: "rustdoc-ui",
+ compare_mode: None,
+ })
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct Tidy;
/// otherwise just implements a few lint-like checks that are specific to the
/// compiler itself.
fn run(self, builder: &Builder) {
- let build = builder.build;
-
let mut cmd = builder.tool_cmd(Tool::Tidy);
- cmd.arg(build.src.join("src"));
- cmd.arg(&build.initial_cargo);
- if !build.config.vendor {
+ cmd.arg(builder.src.join("src"));
+ cmd.arg(&builder.initial_cargo);
+ if !builder.config.vendor {
cmd.arg("--no-vendor");
}
- if build.config.quiet_tests {
+ if builder.config.quiet_tests {
cmd.arg("--quiet");
}
- let _folder = build.fold_output(|| "tidy");
+ let _folder = builder.fold_output(|| "tidy");
builder.info(&format!("tidy check"));
- try_run(build, &mut cmd);
+ try_run(builder, &mut cmd);
}
fn should_run(run: ShouldRun) -> ShouldRun {
}
}
-fn testdir(build: &Build, host: Interned<String>) -> PathBuf {
- build.out.join(host).join("test")
+fn testdir(builder: &Builder, host: Interned<String>) -> PathBuf {
+ builder.out.join(host).join("test")
}
macro_rules! default_test {
}
}
+macro_rules! default_test_with_compare_mode {
+ ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr,
+ compare_mode: $compare_mode:expr }) => {
+ test_with_compare_mode!($name { path: $path, mode: $mode, suite: $suite, default: true,
+ host: false, compare_mode: $compare_mode });
+ }
+}
+
macro_rules! host_test {
($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr }) => {
test!($name { path: $path, mode: $mode, suite: $suite, default: true, host: true });
}
macro_rules! test {
+ ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
+ host: $host:expr }) => {
+ test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
+ host: $host, compare_mode: None });
+ }
+}
+
+macro_rules! test_with_compare_mode {
+ ($name:ident { path: $path:expr, mode: $mode:expr, suite: $suite:expr, default: $default:expr,
+ host: $host:expr, compare_mode: $compare_mode:expr }) => {
+ test_definitions!($name { path: $path, mode: $mode, suite: $suite, default: $default,
+ host: $host, compare_mode: Some($compare_mode) });
+ }
+}
+
+macro_rules! test_definitions {
($name:ident {
path: $path:expr,
mode: $mode:expr,
suite: $suite:expr,
default: $default:expr,
- host: $host:expr
+ host: $host:expr,
+ compare_mode: $compare_mode:expr
}) => {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct $name {
target: self.target,
mode: $mode,
suite: $suite,
+ compare_mode: $compare_mode,
})
}
}
}
}
-default_test!(Ui {
+default_test_with_compare_mode!(Ui {
path: "src/test/ui",
mode: "ui",
- suite: "ui"
+ suite: "ui",
+ compare_mode: "nll"
});
default_test!(RunPass {
target: Interned<String>,
mode: &'static str,
suite: &'static str,
+ compare_mode: Option<&'static str>,
}
impl Step for Compiletest {
/// compiletest `mode` and `suite` arguments. For example `mode` can be
/// "run-pass" or `suite` can be something like `debuginfo`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let mode = self.mode;
let suite = self.suite;
+ let compare_mode = self.compare_mode;
// Skip codegen tests if they aren't enabled in configuration.
- if !build.config.codegen_tests && suite == "codegen" {
+ if !builder.config.codegen_tests && suite == "codegen" {
return;
}
if suite == "debuginfo" {
// Skip debuginfo tests on MSVC
- if build.build.contains("msvc") {
+ if builder.config.build.contains("msvc") {
return;
}
if mode == "debuginfo-XXX" {
- return if build.build.contains("apple") {
+ return if builder.config.build.contains("apple") {
builder.ensure(Compiletest {
mode: "debuginfo-lldb",
..self
cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target));
cmd.arg("--rustc-path").arg(builder.rustc(compiler));
+ let is_rustdoc_ui = suite.ends_with("rustdoc-ui");
+
// Avoid depending on rustdoc when we don't need it.
- if mode == "rustdoc" || (mode == "run-make" && suite.ends_with("fulldeps")) {
+ if mode == "rustdoc" ||
+ (mode == "run-make" && suite.ends_with("fulldeps")) ||
+ (mode == "ui" && is_rustdoc_ui) {
cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host));
}
- cmd.arg("--src-base").arg(build.src.join("src/test").join(suite));
- cmd.arg("--build-base").arg(testdir(build, compiler.host).join(suite));
+ cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite));
+ cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite));
cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target));
cmd.arg("--mode").arg(mode);
cmd.arg("--target").arg(target);
cmd.arg("--host").arg(&*compiler.host);
- cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(build.build));
+ cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
- if let Some(ref nodejs) = build.config.nodejs {
+ if let Some(ref nodejs) = builder.config.nodejs {
cmd.arg("--nodejs").arg(nodejs);
}
- let mut flags = vec!["-Crpath".to_string()];
- if build.config.rust_optimize_tests {
- flags.push("-O".to_string());
- }
- if build.config.rust_debuginfo_tests {
- flags.push("-g".to_string());
+ let mut flags = if is_rustdoc_ui {
+ Vec::new()
+ } else {
+ vec!["-Crpath".to_string()]
+ };
+ if !is_rustdoc_ui {
+ if builder.config.rust_optimize_tests {
+ flags.push("-O".to_string());
+ }
+ if builder.config.rust_debuginfo_tests {
+ flags.push("-g".to_string());
+ }
}
flags.push("-Zunstable-options".to_string());
- flags.push(build.config.cmd.rustc_args().join(" "));
+ flags.push(builder.config.cmd.rustc_args().join(" "));
- if let Some(linker) = build.linker(target) {
+ if let Some(linker) = builder.linker(target) {
cmd.arg("--linker").arg(linker);
}
let mut targetflags = flags.clone();
targetflags.push(format!("-Lnative={}",
- build.test_helpers_out(target).display()));
+ builder.test_helpers_out(target).display()));
cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
- cmd.arg("--docck-python").arg(build.python());
+ cmd.arg("--docck-python").arg(builder.python());
- if build.build.ends_with("apple-darwin") {
+ if builder.config.build.ends_with("apple-darwin") {
// Force /usr/bin/python on macOS for LLDB tests because we're loading the
// LLDB plugin's compiled module which only works with the system python
// (namely not Homebrew-installed python)
cmd.arg("--lldb-python").arg("/usr/bin/python");
} else {
- cmd.arg("--lldb-python").arg(build.python());
+ cmd.arg("--lldb-python").arg(builder.python());
}
- if let Some(ref gdb) = build.config.gdb {
+ if let Some(ref gdb) = builder.config.gdb {
cmd.arg("--gdb").arg(gdb);
}
- if let Some(ref vers) = build.lldb_version {
+ if let Some(ref vers) = builder.lldb_version {
cmd.arg("--lldb-version").arg(vers);
}
- if let Some(ref dir) = build.lldb_python_dir {
+ if let Some(ref dir) = builder.lldb_python_dir {
cmd.arg("--lldb-python-dir").arg(dir);
}
- cmd.args(&build.config.cmd.test_args());
+ cmd.args(&builder.config.cmd.test_args());
- if build.is_verbose() {
+ if builder.is_verbose() {
cmd.arg("--verbose");
}
- if build.config.quiet_tests {
+ if builder.config.quiet_tests {
cmd.arg("--quiet");
}
- if build.config.llvm_enabled {
+ if builder.config.llvm_enabled {
let llvm_config = builder.ensure(native::Llvm {
- target: build.config.build,
+ target: builder.config.build,
emscripten: false,
});
- if !build.config.dry_run {
+ if !builder.config.dry_run {
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
cmd.arg("--llvm-version").arg(llvm_version);
}
- if !build.is_rust_llvm(target) {
+ if !builder.is_rust_llvm(target) {
cmd.arg("--system-llvm");
}
// Only pass correct values for these flags for the `run-make` suite as it
// requires that a C++ compiler was configured which isn't always the case.
- if !build.config.dry_run && suite == "run-make-fulldeps" {
+ if !builder.config.dry_run && suite == "run-make-fulldeps" {
let llvm_components = output(Command::new(&llvm_config).arg("--components"));
let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags"));
- cmd.arg("--cc").arg(build.cc(target))
- .arg("--cxx").arg(build.cxx(target).unwrap())
- .arg("--cflags").arg(build.cflags(target).join(" "))
+ cmd.arg("--cc").arg(builder.cc(target))
+ .arg("--cxx").arg(builder.cxx(target).unwrap())
+ .arg("--cflags").arg(builder.cflags(target).join(" "))
.arg("--llvm-components").arg(llvm_components.trim())
.arg("--llvm-cxxflags").arg(llvm_cxxflags.trim());
- if let Some(ar) = build.ar(target) {
+ if let Some(ar) = builder.ar(target) {
cmd.arg("--ar").arg(ar);
}
}
}
- if suite == "run-make-fulldeps" && !build.config.llvm_enabled {
+ if suite == "run-make-fulldeps" && !builder.config.llvm_enabled {
builder.info(
&format!("Ignoring run-make test suite as they generally don't work without LLVM"));
return;
.arg("--llvm-cxxflags").arg("");
}
- if build.remote_tested(target) {
+ if builder.remote_tested(target) {
cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient));
}
// Note that if we encounter `PATH` we make sure to append to our own `PATH`
// rather than stomp over it.
if target.contains("msvc") {
- for &(ref k, ref v) in build.cc[&target].env() {
+ for &(ref k, ref v) in builder.cc[&target].env() {
if k != "PATH" {
cmd.env(k, v);
}
}
}
cmd.env("RUSTC_BOOTSTRAP", "1");
- build.add_rust_test_threads(&mut cmd);
+ builder.add_rust_test_threads(&mut cmd);
- if build.config.sanitizers {
+ if builder.config.sanitizers {
cmd.env("SANITIZER_SUPPORT", "1");
}
- if build.config.profiler {
+ if builder.config.profiler {
cmd.env("PROFILER_SUPPORT", "1");
}
- cmd.env("RUST_TEST_TMPDIR", build.out.join("tmp"));
+ cmd.env("RUST_TEST_TMPDIR", builder.out.join("tmp"));
cmd.arg("--adb-path").arg("adb");
cmd.arg("--adb-test-dir").arg(ADB_TEST_DIR);
if target.contains("android") {
// Assume that cc for this target comes from the android sysroot
cmd.arg("--android-cross-path")
- .arg(build.cc(target).parent().unwrap().parent().unwrap());
+ .arg(builder.cc(target).parent().unwrap().parent().unwrap());
} else {
cmd.arg("--android-cross-path").arg("");
}
- build.ci_env.force_coloring_in_ci(&mut cmd);
+ builder.ci_env.force_coloring_in_ci(&mut cmd);
- let _folder = build.fold_output(|| format!("test_{}", suite));
+ let _folder = builder.fold_output(|| format!("test_{}", suite));
builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})",
suite, mode, &compiler.host, target));
- let _time = util::timeit(&build);
- try_run(build, &mut cmd);
+ let _time = util::timeit(&builder);
+ try_run(builder, &mut cmd);
+
+ if let Some(compare_mode) = compare_mode {
+ cmd.arg("--compare-mode").arg(compare_mode);
+ let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode));
+ builder.info(&format!("Check compiletest suite={} mode={} compare_mode={} ({} -> {})",
+ suite, mode, compare_mode, &compiler.host, target));
+ let _time = util::timeit(&builder);
+ try_run(builder, &mut cmd);
+ }
}
}
/// located in `src/doc`. The `rustdoc` that's run is the one that sits next to
/// `compiler`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
builder.ensure(compile::Test { compiler, target: compiler.host });
// Do a breadth-first traversal of the `src/doc` directory and just run
// tests for all files that end in `*.md`
- let mut stack = vec![build.src.join(self.path)];
- let _time = util::timeit(&build);
- let _folder = build.fold_output(|| format!("test_{}", self.name));
+ let mut stack = vec![builder.src.join(self.path)];
+ let _time = util::timeit(&builder);
+ let _folder = builder.fold_output(|| format!("test_{}", self.name));
let mut files = Vec::new();
while let Some(p) = stack.pop() {
}
// The nostarch directory in the book is for no starch, and so isn't
- // guaranteed to build. We don't care if it doesn't build, so skip it.
+ // guaranteed to builder. We don't care if it doesn't build, so skip it.
if p.to_str().map_or(false, |p| p.contains("nostarch")) {
continue;
}
} else {
ToolState::TestFail
};
- build.save_toolstate(self.name, toolstate);
+ builder.save_toolstate(self.name, toolstate);
}
}
}
/// generate a markdown file from the error indexes of the code base which is
/// then passed to `rustdoc --test`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
builder.ensure(compile::Std { compiler, target: compiler.host });
- let dir = testdir(build, compiler.host);
+ let dir = testdir(builder, compiler.host);
t!(fs::create_dir_all(&dir));
let output = dir.join("error-index.md");
let mut tool = builder.tool_cmd(Tool::ErrorIndex);
tool.arg("markdown")
.arg(&output)
- .env("CFG_BUILD", &build.build)
- .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir());
+ .env("CFG_BUILD", &builder.config.build)
+ .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
- let _folder = build.fold_output(|| "test_error_index");
- build.info(&format!("Testing error-index stage{}", compiler.stage));
- let _time = util::timeit(&build);
- build.run(&mut tool);
+ let _folder = builder.fold_output(|| "test_error_index");
+ builder.info(&format!("Testing error-index stage{}", compiler.stage));
+ let _time = util::timeit(&builder);
+ builder.run(&mut tool);
markdown_test(builder, compiler, &output);
}
}
fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool {
- let build = builder.build;
match File::open(markdown) {
Ok(mut file) => {
let mut contents = String::new();
Err(_) => {},
}
- build.info(&format!("doc tests for: {}", markdown.display()));
+ builder.info(&format!("doc tests for: {}", markdown.display()));
let mut cmd = builder.rustdoc_cmd(compiler.host);
- build.add_rust_test_threads(&mut cmd);
+ builder.add_rust_test_threads(&mut cmd);
cmd.arg("--test");
cmd.arg(markdown);
cmd.env("RUSTC_BOOTSTRAP", "1");
- let test_args = build.config.cmd.test_args().join(" ");
+ let test_args = builder.config.cmd.test_args().join(" ");
cmd.arg("--test-args").arg(test_args);
- if build.config.quiet_tests {
- try_run_quiet(build, &mut cmd)
+ if builder.config.quiet_tests {
+ try_run_quiet(builder, &mut cmd)
} else {
- try_run(build, &mut cmd)
+ try_run(builder, &mut cmd)
}
}
/// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
/// arguments, and those arguments are discovered from `cargo metadata`.
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let mode = self.mode;
// libstd, then what we're actually testing is the libstd produced in
// stage1. Reflect that here by updating the compiler that we're working
// with automatically.
- let compiler = if build.force_use_stage1(compiler, target) {
+ let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
compiler.clone()
compile::std_cargo(builder, &compiler, target, &mut cargo);
}
Mode::Libtest => {
- compile::test_cargo(build, &compiler, target, &mut cargo);
+ compile::test_cargo(builder, &compiler, target, &mut cargo);
}
Mode::Librustc => {
builder.ensure(compile::Rustc { compiler, target });
- compile::rustc_cargo(build, &mut cargo);
+ compile::rustc_cargo(builder, &mut cargo);
}
_ => panic!("can only test libraries"),
};
// Pass in some standard flags then iterate over the graph we've discovered
// in `cargo metadata` with the maps above and figure out what `-p`
// arguments need to get passed.
- if test_kind.subcommand() == "test" && !build.fail_fast {
+ if test_kind.subcommand() == "test" && !builder.fail_fast {
cargo.arg("--no-fail-fast");
}
- if build.doc_tests {
+ if builder.doc_tests {
cargo.arg("--doc");
}
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
cargo.arg("--");
- cargo.args(&build.config.cmd.test_args());
+ cargo.args(&builder.config.cmd.test_args());
- if build.config.quiet_tests {
+ if builder.config.quiet_tests {
cargo.arg("--quiet");
}
if target.contains("emscripten") {
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
- build.config.nodejs.as_ref().expect("nodejs not configured"));
+ builder.config.nodejs.as_ref().expect("nodejs not configured"));
} else if target.starts_with("wasm32") {
// Warn about running tests without the `wasm_syscall` feature enabled.
// The javascript shim implements the syscall interface so that test
// output can be correctly reported.
- if !build.config.wasm_syscall {
- build.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \
+ if !builder.config.wasm_syscall {
+ builder.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \
test output may not be visible."));
}
// incompatible with `-C prefer-dynamic`, so disable that here
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
- let node = build.config.nodejs.as_ref()
+ let node = builder.config.nodejs.as_ref()
.expect("nodejs not configured");
let runner = format!("{} {}/src/etc/wasm32-shim.js",
node.display(),
- build.src.display());
+ builder.src.display());
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner);
- } else if build.remote_tested(target) {
+ } else if builder.remote_tested(target) {
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
format!("{} run",
builder.tool_exe(Tool::RemoteTestClient).display()));
}
- let _folder = build.fold_output(|| {
+ let _folder = builder.fold_output(|| {
format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate)
});
- build.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage,
+ builder.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage,
&compiler.host, target));
- let _time = util::timeit(&build);
- try_run(build, &mut cargo);
+ let _time = util::timeit(&builder);
+ try_run(builder, &mut cargo);
}
}
}
fn run(self, builder: &Builder) {
- let build = builder.build;
let test_kind = self.test_kind;
let compiler = builder.compiler(builder.top_stage, self.host);
target,
test_kind.subcommand(),
"src/tools/rustdoc");
- if test_kind.subcommand() == "test" && !build.fail_fast {
+ if test_kind.subcommand() == "test" && !builder.fail_fast {
cargo.arg("--no-fail-fast");
}
cargo.arg("-p").arg("rustdoc:0.0.0");
cargo.arg("--");
- cargo.args(&build.config.cmd.test_args());
+ cargo.args(&builder.config.cmd.test_args());
- if build.config.quiet_tests {
+ if builder.config.quiet_tests {
cargo.arg("--quiet");
}
- let _folder = build.fold_output(|| {
+ let _folder = builder.fold_output(|| {
format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)
});
- build.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage,
+ builder.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage,
&compiler.host, target));
- let _time = util::timeit(&build);
+ let _time = util::timeit(&builder);
- try_run(build, &mut cargo);
+ try_run(builder, &mut cargo);
}
}
}
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
- if !build.remote_tested(target) {
+ if !builder.remote_tested(target) {
return
}
builder.ensure(compile::Test { compiler, target });
- build.info(&format!("REMOTE copy libs to emulator ({})", target));
- t!(fs::create_dir_all(build.out.join("tmp")));
+ builder.info(&format!("REMOTE copy libs to emulator ({})", target));
+ t!(fs::create_dir_all(builder.out.join("tmp")));
let server = builder.ensure(tool::RemoteTestServer { compiler, target });
cmd.arg("spawn-emulator")
.arg(target)
.arg(&server)
- .arg(build.out.join("tmp"));
- if let Some(rootfs) = build.qemu_rootfs(target) {
+ .arg(builder.out.join("tmp"));
+ if let Some(rootfs) = builder.qemu_rootfs(target) {
cmd.arg(rootfs);
}
- build.run(&mut cmd);
+ builder.run(&mut cmd);
// Push all our dylibs to the emulator
for f in t!(builder.sysroot_libdir(compiler, target).read_dir()) {
let f = t!(f);
let name = f.file_name().into_string().unwrap();
if util::is_dylib(&name) {
- build.run(Command::new(&tool)
+ builder.run(Command::new(&tool)
.arg("push")
.arg(f.path()));
}
/// Run "distcheck", a 'make check' from a tarball
fn run(self, builder: &Builder) {
- let build = builder.build;
-
- build.info(&format!("Distcheck"));
- let dir = build.out.join("tmp").join("distcheck");
+ builder.info(&format!("Distcheck"));
+ let dir = builder.out.join("tmp").join("distcheck");
let _ = fs::remove_dir_all(&dir);
t!(fs::create_dir_all(&dir));
.arg(builder.ensure(dist::PlainSourceTarball))
.arg("--strip-components=1")
.current_dir(&dir);
- build.run(&mut cmd);
- build.run(Command::new("./configure")
- .args(&build.config.configure_args)
+ builder.run(&mut cmd);
+ builder.run(Command::new("./configure")
+ .args(&builder.config.configure_args)
.arg("--enable-vendor")
.current_dir(&dir));
- build.run(Command::new(build_helper::make(&build.build))
+ builder.run(Command::new(build_helper::make(&builder.config.build))
.arg("check")
.current_dir(&dir));
// Now make sure that rust-src has all of libstd's dependencies
- build.info(&format!("Distcheck rust-src"));
- let dir = build.out.join("tmp").join("distcheck-src");
+ builder.info(&format!("Distcheck rust-src"));
+ let dir = builder.out.join("tmp").join("distcheck-src");
let _ = fs::remove_dir_all(&dir);
t!(fs::create_dir_all(&dir));
.arg(builder.ensure(dist::Src))
.arg("--strip-components=1")
.current_dir(&dir);
- build.run(&mut cmd);
+ builder.run(&mut cmd);
let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml");
- build.run(Command::new(&build.initial_cargo)
+ builder.run(Command::new(&builder.initial_cargo)
.arg("generate-lockfile")
.arg("--manifest-path")
.arg(&toml)
/// Test the build system itself
fn run(self, builder: &Builder) {
- let build = builder.build;
- let mut cmd = Command::new(&build.initial_cargo);
+ let mut cmd = Command::new(&builder.initial_cargo);
cmd.arg("test")
- .current_dir(build.src.join("src/bootstrap"))
+ .current_dir(builder.src.join("src/bootstrap"))
.env("RUSTFLAGS", "-Cdebuginfo=2")
- .env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
+ .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
.env("RUSTC_BOOTSTRAP", "1")
- .env("RUSTC", &build.initial_rustc);
+ .env("RUSTC", &builder.initial_rustc);
if let Some(flags) = option_env!("RUSTFLAGS") {
// Use the same rustc flags for testing as for "normal" compilation,
// so that Cargo doesn’t recompile the entire dependency graph every time:
// https://github.com/rust-lang/rust/issues/49215
cmd.env("RUSTFLAGS", flags);
}
- if !build.fail_fast {
+ if !builder.fail_fast {
cmd.arg("--no-fail-fast");
}
- cmd.arg("--").args(&build.config.cmd.test_args());
- try_run(build, &mut cmd);
+ cmd.arg("--").args(&builder.config.cmd.test_args());
+ try_run(builder, &mut cmd);
}
fn should_run(run: ShouldRun) -> ShouldRun {
}
fn run(self, builder: &Builder) {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let mode = self.mode;
// This is for the original compiler, but if we're forced to use stage 1, then
// std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since
// we copy the libs forward.
- let tools_dir = build.stage_out(compiler, Mode::Tool);
+ let tools_dir = builder.stage_out(compiler, Mode::Tool);
let compiler = if builder.force_use_stage1(compiler, target) {
builder.compiler(1, compiler.host)
} else {
for &cur_mode in &[Mode::Libstd, Mode::Libtest, Mode::Librustc] {
let stamp = match cur_mode {
- Mode::Libstd => libstd_stamp(build, compiler, target),
- Mode::Libtest => libtest_stamp(build, compiler, target),
- Mode::Librustc => librustc_stamp(build, compiler, target),
+ Mode::Libstd => libstd_stamp(builder, compiler, target),
+ Mode::Libtest => libtest_stamp(builder, compiler, target),
+ Mode::Librustc => librustc_stamp(builder, compiler, target),
_ => panic!(),
};
- if build.clear_if_dirty(&tools_dir, &stamp) {
+ if builder.clear_if_dirty(&tools_dir, &stamp) {
break;
}
/// This will build the specified tool with the specified `host` compiler in
/// `stage` into the normal cargo output directory.
fn run(self, builder: &Builder) -> Option<PathBuf> {
- let build = builder.build;
let compiler = self.compiler;
let target = self.target;
let tool = self.tool;
let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path);
cargo.arg("--features").arg(self.extra_features.join(" "));
- let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
- build.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
+ let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
+ builder.info(&format!("Building stage{} tool {} ({})", compiler.stage, tool, target));
let mut duplicates = Vec::new();
- let is_expected = compile::stream_cargo(build, &mut cargo, &mut |msg| {
+ let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| {
// Only care about big things like the RLS/Cargo for now
if tool != "rls" && tool != "cargo" {
return
}
}
- let mut artifacts = build.tool_artifacts.borrow_mut();
+ let mut artifacts = builder.tool_artifacts.borrow_mut();
let prev_artifacts = artifacts
.entry(target)
.or_insert_with(Default::default);
panic!("tools should not compile multiple copies of the same crate");
}
- build.save_toolstate(tool, if is_expected {
+ builder.save_toolstate(tool, if is_expected {
ToolState::TestFail
} else {
ToolState::BuildFail
return None;
}
} else {
- let cargo_out = build.cargo_out(compiler, Mode::Tool, target)
+ let cargo_out = builder.cargo_out(compiler, Mode::Tool, target)
.join(exe(tool, &compiler.host));
- let bin = build.tools_dir(compiler).join(exe(tool, &compiler.host));
- build.copy(&cargo_out, &bin);
+ let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host));
+ builder.copy(&cargo_out, &bin);
Some(bin)
}
}
command: &'static str,
path: &'static str,
) -> Command {
- let build = builder.build;
let mut cargo = builder.cargo(compiler, Mode::Tool, target, command);
- let dir = build.src.join(path);
+ let dir = builder.src.join(path);
cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
// We don't want to build tools dynamically as they'll be running across
// stages and such and it's just easier if they're not dynamically linked.
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
- if let Some(dir) = build.openssl_install_dir(target) {
+ if let Some(dir) = builder.openssl_install_dir(target) {
cargo.env("OPENSSL_STATIC", "1");
cargo.env("OPENSSL_DIR", dir);
cargo.env("LIBZ_SYS_STATIC", "1");
// own copy
cargo.env("LZMA_API_STATIC", "1");
- cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);
- cargo.env("CFG_VERSION", build.rust_version());
+ cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel);
+ cargo.env("CFG_VERSION", builder.rust_version());
- let info = GitInfo::new(&build.config, &dir);
+ let info = GitInfo::new(&builder.config, &dir);
if let Some(sha) = info.sha() {
cargo.env("CFG_COMMIT_HASH", sha);
}
match tool {
$(Tool::$name =>
self.ensure($name {
- compiler: self.compiler(stage, self.build.build),
- target: self.build.build,
+ compiler: self.compiler(stage, self.config.build),
+ target: self.config.build,
}),
)+
}
fn make_run(run: RunConfig) {
run.builder.ensure($name {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
fn make_run(run: RunConfig) {
run.builder.ensure(RemoteTestServer {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
}
fn run(self, builder: &Builder) -> PathBuf {
- let build = builder.build;
let target_compiler = builder.compiler(builder.top_stage, self.host);
let target = target_compiler.host;
let build_compiler = if target_compiler.stage == 0 {
- builder.compiler(0, builder.build.build)
+ builder.compiler(0, builder.config.build)
} else if target_compiler.stage >= 2 {
// Past stage 2, we consider the compiler to be ABI-compatible and hence capable of
// building rustdoc itself.
- builder.compiler(target_compiler.stage, builder.build.build)
+ builder.compiler(target_compiler.stage, builder.config.build)
} else {
// Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
// we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage
// compilers, which isn't what we want.
- builder.compiler(target_compiler.stage - 1, builder.build.build)
+ builder.compiler(target_compiler.stage - 1, builder.config.build)
};
builder.ensure(compile::Rustc { compiler: build_compiler, target });
builder.ensure(compile::Rustc {
compiler: build_compiler,
- target: builder.build.build,
+ target: builder.config.build,
});
let mut cargo = prepare_tool_cargo(builder,
cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string())
.env("RUSTC_DEBUGINFO_LINES", builder.config.rust_debuginfo_lines.to_string());
- let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
- build.info(&format!("Building rustdoc for stage{} ({})",
+ let _folder = builder.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
+ builder.info(&format!("Building rustdoc for stage{} ({})",
target_compiler.stage, target_compiler.host));
- build.run(&mut cargo);
+ builder.run(&mut cargo);
// Cargo adds a number of paths to the dylib search path on windows, which results in
// the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
// rustdoc a different name.
- let tool_rustdoc = build.cargo_out(build_compiler, Mode::Tool, target)
+ let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target)
.join(exe("rustdoc-tool-binary", &target_compiler.host));
// don't create a stage0-sysroot/bin directory.
t!(fs::create_dir_all(&bindir));
let bin_rustdoc = bindir.join(exe("rustdoc", &*target_compiler.host));
let _ = fs::remove_file(&bin_rustdoc);
- build.copy(&tool_rustdoc, &bin_rustdoc);
+ builder.copy(&tool_rustdoc, &bin_rustdoc);
bin_rustdoc
} else {
tool_rustdoc
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path("src/tools/cargo").default_condition(builder.build.config.extended)
+ run.path("src/tools/cargo").default_condition(builder.config.extended)
}
fn make_run(run: RunConfig) {
run.builder.ensure(Cargo {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
});
}
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: self.compiler,
- target: builder.build.build,
+ target: builder.config.build,
});
builder.ensure(ToolBuild {
compiler: self.compiler,
fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
- run.path($path).default_condition(builder.build.config.extended)
+ run.path($path).default_condition(builder.config.extended)
}
fn make_run(run: RunConfig) {
run.builder.ensure($name {
- compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
target: run.target,
extra_features: Vec::new(),
});
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: self.compiler,
- target: builder.build.build,
+ target: builder.config.build,
});
};
Miri, miri, "src/tools/miri", "miri", {};
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: self.compiler,
- target: builder.build.build,
+ target: builder.config.build,
});
};
Rustfmt, rustfmt, "src/tools/rustfmt", "rustfmt", {};
/// `host`.
pub fn tool_cmd(&self, tool: Tool) -> Command {
let mut cmd = Command::new(self.tool_exe(tool));
- let compiler = self.compiler(self.tool_default_stage(tool), self.build.build);
+ let compiler = self.compiler(self.tool_default_stage(tool), self.config.build);
self.prepare_tool_cmd(compiler, &mut cmd);
cmd
}
use std::time::{SystemTime, Instant};
use config::Config;
-use Build;
+use builder::Builder;
/// Returns the `name` as the filename of a static library for `target`.
pub fn staticlib(name: &str, target: &str) -> String {
pub struct TimeIt(bool, Instant);
/// Returns an RAII structure that prints out how long it took to drop.
-pub fn timeit(build: &Build) -> TimeIt {
- TimeIt(build.config.dry_run, Instant::now())
+pub fn timeit(builder: &Builder) -> TimeIt {
+ TimeIt(builder.config.dry_run, Instant::now())
}
impl Drop for TimeIt {
--set build.nodejs=/node-v9.2.0-linux-x64/bin/node \
--set rust.lld
+# Some run-make tests have assertions about code size, and enabling debug
+# assertions in libstd causes the binary to be much bigger than it would
+# otherwise normally be. We already test libstd with debug assertions in lots of
+# other contexts as well
+ENV NO_DEBUG_ASSERTIONS=1
+
ENV SCRIPT python2.7 /checkout/x.py test --target $TARGETS \
src/test/run-make \
src/test/ui \
we don't want the reader to see every line every time. Here's what we put in
our source code:
-```text
- First, we set `x` to five:
+``````markdown
+First, we set `x` to five:
- ```
- let x = 5;
- # let y = 6;
- # println!("{}", x + y);
- ```
+```
+let x = 5;
+# let y = 6;
+# println!("{}", x + y);
+```
- Next, we set `y` to six:
+Next, we set `y` to six:
- ```
- # let x = 5;
- let y = 6;
- # println!("{}", x + y);
- ```
+```
+# let x = 5;
+let y = 6;
+# println!("{}", x + y);
+```
- Finally, we print the sum of `x` and `y`:
+Finally, we print the sum of `x` and `y`:
- ```
- # let x = 5;
- # let y = 6;
- println!("{}", x + y);
- ```
```
+# let x = 5;
+# let y = 6;
+println!("{}", x + y);
+```
+``````
By repeating all parts of the example, you can ensure that your example still
compiles, while only showing the parts that are relevant to that part of your
`#[unstable]` attribute to any dependent crate that doesn't have another stability attribute. This
allows `rustdoc` to be able to generate documentation for the compiler crates and the standard
library, as an equivalent command-line argument is provided to `rustc` when building those crates.
+
+### `doc_alias` feature
+
+This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
+`doc(alias)` attribute. Example:
+
+```rust,no_run
+#![feature(doc_alias)]
+
+#[doc(alias = "x")]
+#[doc(alias = "big")]
+pub struct BigX;
+```
+
+Then, when looking for it through the `rustdoc` search, if you enter "x" or
+"big", search will show the `BigX` struct first.
--- /dev/null
+# `doc_alias`
+
+The tracking issue for this feature is: [#50146]
+
+[#50146]: https://github.com/rust-lang/rust/issues/50146
+
+------------------------
+
+You can add alias(es) to an item when using the `rustdoc` search through the
+`doc(alias)` attribute. Example:
+
+```rust,no_run
+#![feature(doc_alias)]
+
+#[doc(alias = "x")]
+#[doc(alias = "big")]
+pub struct BigX;
+```
+
+Then, when looking for it through the `rustdoc` search, if you enter "x" or
+"big", search will show the `BigX` struct first.
+
+Note that this feature is currently hidden behind the `feature(doc_alias)` gate.
+++ /dev/null
-# `slice_rsplit`
-
-The tracking issue for this feature is: [#41020]
-
-[#41020]: https://github.com/rust-lang/rust/issues/41020
-
-------------------------
-
-The `slice_rsplit` feature enables two methods on slices:
-`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`.
#[allocator]
#[rustc_allocator_nounwind]
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
- #[cold]
- #[rustc_allocator_nounwind]
- fn __rust_oom() -> !;
#[rustc_allocator_nounwind]
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
#[rustc_allocator_nounwind]
let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0);
ptr as *mut Opaque
}
-
- #[inline]
- fn oom(&self) -> ! {
- unsafe {
- #[cfg(not(stage0))]
- __rust_oom();
- #[cfg(stage0)]
- __rust_oom(&mut 0);
- }
- }
}
unsafe impl Alloc for Global {
unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
}
-
- #[inline]
- fn oom(&mut self) -> ! {
- GlobalAlloc::oom(self)
- }
}
/// The allocator for unique pointers.
if !ptr.is_null() {
ptr as *mut u8
} else {
- Global.oom()
+ oom()
}
}
}
}
}
+#[cfg(stage0)]
+pub fn oom() -> ! {
+ unsafe { ::core::intrinsics::abort() }
+}
+
+#[cfg(not(stage0))]
+pub fn oom() -> ! {
+ extern {
+ #[lang = "oom"]
+ fn oom_impl() -> !;
+ }
+ unsafe { oom_impl() }
+}
+
#[cfg(test)]
mod tests {
extern crate test;
use self::test::Bencher;
use boxed::Box;
- use alloc::{Global, Alloc, Layout};
+ use alloc::{Global, Alloc, Layout, oom};
#[test]
fn allocate_zeroed() {
unsafe {
let layout = Layout::from_size_align(1024, 1).unwrap();
let ptr = Global.alloc_zeroed(layout.clone())
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
let mut i = ptr.cast::<u8>().as_ptr();
let end = i.offset(layout.size() as isize);
use core::{isize, usize};
use core::convert::From;
-use alloc::{Global, Alloc, Layout, box_free};
+use alloc::{Global, Alloc, Layout, box_free, oom};
use boxed::Box;
use string::String;
use vec::Vec;
let layout = Layout::for_value(&*fake_ptr);
let mem = Global.alloc(layout)
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
// Initialize the real ArcInner
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner<T>;
#[stable(feature = "box_from_slice", since = "1.17.0")]
impl<'a> From<&'a str> for Box<str> {
+ #[inline]
fn from(s: &'a str) -> Box<str> {
unsafe { from_boxed_utf8_unchecked(Box::from(s.as_bytes())) }
}
#[stable(feature = "boxed_str_conv", since = "1.19.0")]
impl From<Box<str>> for Box<[u8]> {
+ #[inline]
fn from(s: Box<str>) -> Self {
unsafe { Box::from_raw(Box::into_raw(s) as *mut [u8]) }
}
#[stable(feature = "btree_drop", since = "1.7.0")]
impl<K, V> Drop for IntoIter<K, V> {
fn drop(&mut self) {
- for _ in &mut *self {
- }
+ self.for_each(drop);
unsafe {
let leaf_node = ptr::read(&self.front).into_node();
if let Some(first_parent) = leaf_node.deallocate_and_ascend() {
/// assert_eq!(map["poneyland"], 43);
/// ```
#[stable(feature = "entry_and_modify", since = "1.26.0")]
- pub fn and_modify<F>(self, mut f: F) -> Self
- where F: FnMut(&mut V)
+ pub fn and_modify<F>(self, f: F) -> Self
+ where F: FnOnce(&mut V)
{
match self {
Occupied(mut entry) => {
}
fn oom(&mut self, _: AllocErr) -> ! {
- CoreAlloc::oom(self)
+ unsafe { ::core::intrinsics::abort() }
}
fn usable_size(&self, layout: &Layout) -> (usize, usize) {
#![deny(missing_debug_implementations)]
#![cfg_attr(test, allow(deprecated))] // rand
-#![cfg_attr(not(test), feature(core_float))]
+#![cfg_attr(all(not(test), stage0), feature(float_internals))]
#![cfg_attr(not(test), feature(exact_size_is_empty))]
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(collections_range)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
+#![cfg_attr(stage0, feature(core_slice_ext))]
+#![cfg_attr(stage0, feature(core_str_ext))]
#![feature(custom_attribute)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(needs_allocator)]
-#![feature(nonnull_cast)]
#![feature(nonzero)]
#![feature(optin_builtin_traits)]
#![feature(pattern)]
#![feature(ptr_offset_from)]
#![feature(rustc_attrs)]
#![feature(slice_get_slice)]
-#![feature(slice_rsplit)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(str_internals)]
#![feature(inclusive_range_fields)]
#![cfg_attr(stage0, feature(generic_param_attrs))]
-#![cfg_attr(not(test), feature(fn_traits, swap_with_slice, i128))]
+#![cfg_attr(not(test), feature(fn_traits, i128))]
#![cfg_attr(test, feature(test))]
// Allow testing this library
where F: FnMut(&mut T) -> bool,
{
fn drop(&mut self) {
- for _ in self { }
+ self.for_each(drop);
}
}
use core::ptr::{self, NonNull, Unique};
use core::slice;
-use alloc::{Alloc, Layout, Global};
+use alloc::{Alloc, Layout, Global, oom};
use alloc::CollectionAllocErr;
use alloc::CollectionAllocErr::*;
use boxed::Box;
unsafe {
let elem_size = mem::size_of::<T>();
- let alloc_size = cap.checked_mul(elem_size).expect("capacity overflow");
- alloc_guard(alloc_size).expect("capacity overflow");
+ let alloc_size = cap.checked_mul(elem_size).unwrap_or_else(|| capacity_overflow());
+ alloc_guard(alloc_size).unwrap_or_else(|_| capacity_overflow());
// handles ZSTs and `cap = 0` alike
let ptr = if alloc_size == 0 {
};
match result {
Ok(ptr) => ptr,
- Err(_) => a.oom(),
+ Err(_) => oom(),
}
};
// `from_size_align_unchecked`.
let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size;
- alloc_guard(new_size).expect("capacity overflow");
+ alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(),
cur,
new_size);
match ptr_res {
Ok(ptr) => (new_cap, ptr.cast().into()),
- Err(_) => self.a.oom(),
+ Err(_) => oom(),
}
}
None => {
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
match self.a.alloc_array::<T>(new_cap) {
Ok(ptr) => (new_cap, ptr.into()),
- Err(_) => self.a.oom(),
+ Err(_) => oom(),
}
}
};
// overflow and the alignment is sufficiently small.
let new_cap = 2 * self.cap;
let new_size = new_cap * elem_size;
- alloc_guard(new_size).expect("capacity overflow");
+ alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) {
Ok(_) => {
// We can't directly divide `size`.
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve_exact(used_cap, needed_extra_cap) {
- Err(CapacityOverflow) => panic!("capacity overflow"),
- Err(AllocErr) => self.a.oom(),
+ Err(CapacityOverflow) => capacity_overflow(),
+ Err(AllocErr) => oom(),
Ok(()) => { /* yay */ }
}
}
/// The same as try_reserve, but errors are lowered to a call to oom().
pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve(used_cap, needed_extra_cap) {
- Err(CapacityOverflow) => panic!("capacity overflow"),
- Err(AllocErr) => self.a.oom(),
+ Err(CapacityOverflow) => capacity_overflow(),
+ Err(AllocErr) => oom(),
Ok(()) => { /* yay */ }
}
}
}
let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)
- .expect("capacity overflow");
+ .unwrap_or_else(|_| capacity_overflow());
// Here, `cap < used_cap + needed_extra_cap <= new_cap`
// (regardless of whether `self.cap - used_cap` wrapped).
let new_layout = Layout::new::<T>().repeat(new_cap).unwrap().0;
// FIXME: may crash and burn on over-reserve
- alloc_guard(new_layout.size()).expect("capacity overflow");
+ alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
match self.a.grow_in_place(
NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(),
) {
old_layout,
new_size) {
Ok(p) => self.ptr = p.cast().into(),
- Err(_) => self.a.oom(),
+ Err(_) => oom(),
}
}
self.cap = amount;
}
}
+// One central function responsible for reporting capacity overflows. This'll
+// ensure that the code generation related to these panics is minimal as there's
+// only one location which panics rather than a bunch throughout the module.
+fn capacity_overflow() -> ! {
+ panic!("capacity overflow")
+}
+
#[cfg(test)]
mod tests {
use super::*;
use core::ptr::{self, NonNull};
use core::convert::From;
-use alloc::{Global, Alloc, Layout, Opaque, box_free};
+use alloc::{Global, Alloc, Layout, Opaque, box_free, oom};
use string::String;
use vec::Vec;
let layout = Layout::for_value(&*fake_ptr);
let mem = Global.alloc(layout)
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
// Initialize the real RcBox
let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox<T>;
use core::mem::size_of;
use core::mem;
use core::ptr;
-use core::slice as core_slice;
+#[cfg(stage0)] use core::slice::SliceExt;
use core::{u8, u16, u32};
use borrow::{Borrow, BorrowMut, ToOwned};
pub use core::slice::{SplitMut, ChunksMut, Split};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
pub use core::slice::{RSplit, RSplitMut};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
}
}
-#[lang = "slice"]
+#[cfg_attr(stage0, lang = "slice")]
+#[cfg_attr(not(stage0), lang = "slice_alloc")]
#[cfg(not(test))]
impl<T> [T] {
- /// Returns the number of elements in the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let a = [1, 2, 3];
- /// assert_eq!(a.len(), 3);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn len(&self) -> usize {
- core_slice::SliceExt::len(self)
- }
-
- /// Returns `true` if the slice has a length of 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let a = [1, 2, 3];
- /// assert!(!a.is_empty());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_empty(&self) -> bool {
- core_slice::SliceExt::is_empty(self)
- }
-
- /// Returns the first element of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&10), v.first());
- ///
- /// let w: &[i32] = &[];
- /// assert_eq!(None, w.first());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn first(&self) -> Option<&T> {
- core_slice::SliceExt::first(self)
- }
-
- /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some(first) = x.first_mut() {
- /// *first = 5;
- /// }
- /// assert_eq!(x, &[5, 1, 2]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn first_mut(&mut self) -> Option<&mut T> {
- core_slice::SliceExt::first_mut(self)
- }
-
- /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[0, 1, 2];
- ///
- /// if let Some((first, elements)) = x.split_first() {
- /// assert_eq!(first, &0);
- /// assert_eq!(elements, &[1, 2]);
- /// }
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_first(&self) -> Option<(&T, &[T])> {
- core_slice::SliceExt::split_first(self)
- }
-
- /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some((first, elements)) = x.split_first_mut() {
- /// *first = 3;
- /// elements[0] = 4;
- /// elements[1] = 5;
- /// }
- /// assert_eq!(x, &[3, 4, 5]);
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
- core_slice::SliceExt::split_first_mut(self)
- }
-
- /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[0, 1, 2];
- ///
- /// if let Some((last, elements)) = x.split_last() {
- /// assert_eq!(last, &2);
- /// assert_eq!(elements, &[0, 1]);
- /// }
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_last(&self) -> Option<(&T, &[T])> {
- core_slice::SliceExt::split_last(self)
-
- }
-
- /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some((last, elements)) = x.split_last_mut() {
- /// *last = 3;
- /// elements[0] = 4;
- /// elements[1] = 5;
- /// }
- /// assert_eq!(x, &[4, 5, 3]);
- /// ```
- #[stable(feature = "slice_splits", since = "1.5.0")]
- #[inline]
- pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
- core_slice::SliceExt::split_last_mut(self)
- }
-
- /// Returns the last element of the slice, or `None` if it is empty.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&30), v.last());
- ///
- /// let w: &[i32] = &[];
- /// assert_eq!(None, w.last());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn last(&self) -> Option<&T> {
- core_slice::SliceExt::last(self)
- }
-
- /// Returns a mutable pointer to the last item in the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some(last) = x.last_mut() {
- /// *last = 10;
- /// }
- /// assert_eq!(x, &[0, 1, 10]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn last_mut(&mut self) -> Option<&mut T> {
- core_slice::SliceExt::last_mut(self)
- }
-
- /// Returns a reference to an element or subslice depending on the type of
- /// index.
- ///
- /// - If given a position, returns a reference to the element at that
- /// position or `None` if out of bounds.
- /// - If given a range, returns the subslice corresponding to that range,
- /// or `None` if out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert_eq!(Some(&40), v.get(1));
- /// assert_eq!(Some(&[10, 40][..]), v.get(0..2));
- /// assert_eq!(None, v.get(3));
- /// assert_eq!(None, v.get(0..4));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn get<I>(&self, index: I) -> Option<&I::Output>
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get(self, index)
- }
-
- /// Returns a mutable reference to an element or subslice depending on the
- /// type of index (see [`get`]) or `None` if the index is out of bounds.
- ///
- /// [`get`]: #method.get
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [0, 1, 2];
- ///
- /// if let Some(elem) = x.get_mut(1) {
- /// *elem = 42;
- /// }
- /// assert_eq!(x, &[0, 42, 2]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get_mut(self, index)
- }
-
- /// Returns a reference to an element or subslice, without doing bounds
- /// checking.
- ///
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`get`].
- ///
- /// [`get`]: #method.get
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[1, 2, 4];
- ///
- /// unsafe {
- /// assert_eq!(x.get_unchecked(1), &2);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get_unchecked(self, index)
- }
-
- /// Returns a mutable reference to an element or subslice, without doing
- /// bounds checking.
- ///
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`get_mut`].
- ///
- /// [`get_mut`]: #method.get_mut
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [1, 2, 4];
- ///
- /// unsafe {
- /// let elem = x.get_unchecked_mut(1);
- /// *elem = 13;
- /// }
- /// assert_eq!(x, &[1, 13, 4]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
- where I: SliceIndex<Self>
- {
- core_slice::SliceExt::get_unchecked_mut(self, index)
- }
-
- /// Returns a raw pointer to the slice's buffer.
- ///
- /// The caller must ensure that the slice outlives the pointer this
- /// function returns, or else it will end up pointing to garbage.
- ///
- /// Modifying the container referenced by this slice may cause its buffer
- /// to be reallocated, which would also make any pointers to it invalid.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[1, 2, 4];
- /// let x_ptr = x.as_ptr();
- ///
- /// unsafe {
- /// for i in 0..x.len() {
- /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize));
- /// }
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_ptr(&self) -> *const T {
- core_slice::SliceExt::as_ptr(self)
- }
-
- /// Returns an unsafe mutable pointer to the slice's buffer.
- ///
- /// The caller must ensure that the slice outlives the pointer this
- /// function returns, or else it will end up pointing to garbage.
- ///
- /// Modifying the container referenced by this slice may cause its buffer
- /// to be reallocated, which would also make any pointers to it invalid.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [1, 2, 4];
- /// let x_ptr = x.as_mut_ptr();
- ///
- /// unsafe {
- /// for i in 0..x.len() {
- /// *x_ptr.offset(i as isize) += 2;
- /// }
- /// }
- /// assert_eq!(x, &[3, 4, 6]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_mut_ptr(&mut self) -> *mut T {
- core_slice::SliceExt::as_mut_ptr(self)
- }
-
- /// Swaps two elements in the slice.
- ///
- /// # Arguments
- ///
- /// * a - The index of the first element
- /// * b - The index of the second element
- ///
- /// # Panics
- ///
- /// Panics if `a` or `b` are out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = ["a", "b", "c", "d"];
- /// v.swap(1, 3);
- /// assert!(v == ["a", "d", "c", "b"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn swap(&mut self, a: usize, b: usize) {
- core_slice::SliceExt::swap(self, a, b)
- }
-
- /// Reverses the order of elements in the slice, in place.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [1, 2, 3];
- /// v.reverse();
- /// assert!(v == [3, 2, 1]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn reverse(&mut self) {
- core_slice::SliceExt::reverse(self)
- }
-
- /// Returns an iterator over the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &[1, 2, 4];
- /// let mut iterator = x.iter();
- ///
- /// assert_eq!(iterator.next(), Some(&1));
- /// assert_eq!(iterator.next(), Some(&2));
- /// assert_eq!(iterator.next(), Some(&4));
- /// assert_eq!(iterator.next(), None);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn iter(&self) -> Iter<T> {
- core_slice::SliceExt::iter(self)
- }
-
- /// Returns an iterator that allows modifying each value.
- ///
- /// # Examples
- ///
- /// ```
- /// let x = &mut [1, 2, 4];
- /// for elem in x.iter_mut() {
- /// *elem += 2;
- /// }
- /// assert_eq!(x, &[3, 4, 6]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn iter_mut(&mut self) -> IterMut<T> {
- core_slice::SliceExt::iter_mut(self)
- }
-
- /// Returns an iterator over all contiguous windows of length
- /// `size`. The windows overlap. If the slice is shorter than
- /// `size`, the iterator returns no values.
- ///
- /// # Panics
- ///
- /// Panics if `size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let slice = ['r', 'u', 's', 't'];
- /// let mut iter = slice.windows(2);
- /// assert_eq!(iter.next().unwrap(), &['r', 'u']);
- /// assert_eq!(iter.next().unwrap(), &['u', 's']);
- /// assert_eq!(iter.next().unwrap(), &['s', 't']);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// If the slice is shorter than `size`:
- ///
- /// ```
- /// let slice = ['f', 'o', 'o'];
- /// let mut iter = slice.windows(4);
- /// assert!(iter.next().is_none());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn windows(&self, size: usize) -> Windows<T> {
- core_slice::SliceExt::windows(self, size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a
- /// time. The chunks are slices and do not overlap. If `chunk_size` does
- /// not divide the length of the slice, then the last chunk will
- /// not have length `chunk_size`.
- ///
- /// See [`exact_chunks`] for a variant of this iterator that returns chunks
- /// of always exactly `chunk_size` elements.
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let slice = ['l', 'o', 'r', 'e', 'm'];
- /// let mut iter = slice.chunks(2);
- /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
- /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
- /// assert_eq!(iter.next().unwrap(), &['m']);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// [`exact_chunks`]: #method.exact_chunks
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
- core_slice::SliceExt::chunks(self, chunk_size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a
- /// time. The chunks are slices and do not overlap. If `chunk_size` does
- /// not divide the length of the slice, then the last up to `chunk_size-1`
- /// elements will be omitted.
- ///
- /// Due to each chunk having exactly `chunk_size` elements, the compiler
- /// can often optimize the resulting code better than in the case of
- /// [`chunks`].
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(exact_chunks)]
- ///
- /// let slice = ['l', 'o', 'r', 'e', 'm'];
- /// let mut iter = slice.exact_chunks(2);
- /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
- /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// [`chunks`]: #method.chunks
- #[unstable(feature = "exact_chunks", issue = "47115")]
- #[inline]
- pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
- core_slice::SliceExt::exact_chunks(self, chunk_size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a time.
- /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
- /// not divide the length of the slice, then the last chunk will not
- /// have length `chunk_size`.
- ///
- /// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks
- /// of always exactly `chunk_size` elements.
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = &mut [0, 0, 0, 0, 0];
- /// let mut count = 1;
- ///
- /// for chunk in v.chunks_mut(2) {
- /// for elem in chunk.iter_mut() {
- /// *elem += count;
- /// }
- /// count += 1;
- /// }
- /// assert_eq!(v, &[1, 1, 2, 2, 3]);
- /// ```
- ///
- /// [`exact_chunks_mut`]: #method.exact_chunks_mut
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
- core_slice::SliceExt::chunks_mut(self, chunk_size)
- }
-
- /// Returns an iterator over `chunk_size` elements of the slice at a time.
- /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
- /// not divide the length of the slice, then the last up to `chunk_size-1`
- /// elements will be omitted.
- ///
- ///
- /// Due to each chunk having exactly `chunk_size` elements, the compiler
- /// can often optimize the resulting code better than in the case of
- /// [`chunks_mut`].
- ///
- /// # Panics
- ///
- /// Panics if `chunk_size` is 0.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(exact_chunks)]
- ///
- /// let v = &mut [0, 0, 0, 0, 0];
- /// let mut count = 1;
- ///
- /// for chunk in v.exact_chunks_mut(2) {
- /// for elem in chunk.iter_mut() {
- /// *elem += count;
- /// }
- /// count += 1;
- /// }
- /// assert_eq!(v, &[1, 1, 2, 2, 0]);
- /// ```
- ///
- /// [`chunks_mut`]: #method.chunks_mut
- #[unstable(feature = "exact_chunks", issue = "47115")]
- #[inline]
- pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
- core_slice::SliceExt::exact_chunks_mut(self, chunk_size)
- }
-
- /// Divides one slice into two at an index.
- ///
- /// The first will contain all indices from `[0, mid)` (excluding
- /// the index `mid` itself) and the second will contain all
- /// indices from `[mid, len)` (excluding the index `len` itself).
- ///
- /// # Panics
- ///
- /// Panics if `mid > len`.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [1, 2, 3, 4, 5, 6];
- ///
- /// {
- /// let (left, right) = v.split_at(0);
- /// assert!(left == []);
- /// assert!(right == [1, 2, 3, 4, 5, 6]);
- /// }
- ///
- /// {
- /// let (left, right) = v.split_at(2);
- /// assert!(left == [1, 2]);
- /// assert!(right == [3, 4, 5, 6]);
- /// }
- ///
- /// {
- /// let (left, right) = v.split_at(6);
- /// assert!(left == [1, 2, 3, 4, 5, 6]);
- /// assert!(right == []);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
- core_slice::SliceExt::split_at(self, mid)
- }
-
- /// Divides one mutable slice into two at an index.
- ///
- /// The first will contain all indices from `[0, mid)` (excluding
- /// the index `mid` itself) and the second will contain all
- /// indices from `[mid, len)` (excluding the index `len` itself).
- ///
- /// # Panics
- ///
- /// Panics if `mid > len`.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [1, 0, 3, 0, 5, 6];
- /// // scoped to restrict the lifetime of the borrows
- /// {
- /// let (left, right) = v.split_at_mut(2);
- /// assert!(left == [1, 0]);
- /// assert!(right == [3, 0, 5, 6]);
- /// left[1] = 2;
- /// right[1] = 4;
- /// }
- /// assert!(v == [1, 2, 3, 4, 5, 6]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
- core_slice::SliceExt::split_at_mut(self, mid)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`. The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- /// let slice = [10, 40, 33, 20];
- /// let mut iter = slice.split(|num| num % 3 == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[10, 40]);
- /// assert_eq!(iter.next().unwrap(), &[20]);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// If the first element is matched, an empty slice will be the first item
- /// returned by the iterator. Similarly, if the last element in the slice
- /// is matched, an empty slice will be the last item returned by the
- /// iterator:
- ///
- /// ```
- /// let slice = [10, 40, 33];
- /// let mut iter = slice.split(|num| num % 3 == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[10, 40]);
- /// assert_eq!(iter.next().unwrap(), &[]);
- /// assert!(iter.next().is_none());
- /// ```
- ///
- /// If two matched elements are directly adjacent, an empty slice will be
- /// present between them:
- ///
- /// ```
- /// let slice = [10, 6, 33, 20];
- /// let mut iter = slice.split(|num| num % 3 == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[10]);
- /// assert_eq!(iter.next().unwrap(), &[]);
- /// assert_eq!(iter.next().unwrap(), &[20]);
- /// assert!(iter.next().is_none());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split<F>(&self, pred: F) -> Split<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::split(self, pred)
- }
-
- /// Returns an iterator over mutable subslices separated by elements that
- /// match `pred`. The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.split_mut(|num| *num % 3 == 0) {
- /// group[0] = 1;
- /// }
- /// assert_eq!(v, [1, 40, 30, 1, 60, 1]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::split_mut(self, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, starting at the end of the slice and working backwards.
- /// The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(slice_rsplit)]
- ///
- /// let slice = [11, 22, 33, 0, 44, 55];
- /// let mut iter = slice.rsplit(|num| *num == 0);
- ///
- /// assert_eq!(iter.next().unwrap(), &[44, 55]);
- /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
- /// assert_eq!(iter.next(), None);
- /// ```
- ///
- /// As with `split()`, if the first or last element is matched, an empty
- /// slice will be the first (or last) item returned by the iterator.
- ///
- /// ```
- /// #![feature(slice_rsplit)]
- ///
- /// let v = &[0, 1, 1, 2, 3, 5, 8];
- /// let mut it = v.rsplit(|n| *n % 2 == 0);
- /// assert_eq!(it.next().unwrap(), &[]);
- /// assert_eq!(it.next().unwrap(), &[3, 5]);
- /// assert_eq!(it.next().unwrap(), &[1, 1]);
- /// assert_eq!(it.next().unwrap(), &[]);
- /// assert_eq!(it.next(), None);
- /// ```
- #[unstable(feature = "slice_rsplit", issue = "41020")]
- #[inline]
- pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplit(self, pred)
- }
-
- /// Returns an iterator over mutable subslices separated by elements that
- /// match `pred`, starting at the end of the slice and working
- /// backwards. The matched element is not contained in the subslices.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(slice_rsplit)]
- ///
- /// let mut v = [100, 400, 300, 200, 600, 500];
- ///
- /// let mut count = 0;
- /// for group in v.rsplit_mut(|num| *num % 3 == 0) {
- /// count += 1;
- /// group[0] = count;
- /// }
- /// assert_eq!(v, [3, 400, 300, 2, 600, 1]);
- /// ```
- ///
- #[unstable(feature = "slice_rsplit", issue = "41020")]
- #[inline]
- pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplit_mut(self, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
- /// not contained in the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
- /// `[20, 60, 50]`):
- ///
- /// ```
- /// let v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.splitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::splitn(self, n, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred`, limited to returning at most `n` items. The matched element is
- /// not contained in the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.splitn_mut(2, |num| *num % 3 == 0) {
- /// group[0] = 1;
- /// }
- /// assert_eq!(v, [1, 40, 30, 1, 60, 50]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::splitn_mut(self, n, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to returning at most `n` items. This starts at the end of
- /// the slice and works backwards. The matched element is not contained in
- /// the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// Print the slice split once, starting from the end, by numbers divisible
- /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
- ///
- /// ```
- /// let v = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
- /// println!("{:?}", group);
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplitn(self, n, pred)
- }
-
- /// Returns an iterator over subslices separated by elements that match
- /// `pred` limited to returning at most `n` items. This starts at the end of
- /// the slice and works backwards. The matched element is not contained in
- /// the subslices.
- ///
- /// The last element returned, if any, will contain the remainder of the
- /// slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut s = [10, 40, 30, 20, 60, 50];
- ///
- /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) {
- /// group[0] = 1;
- /// }
- /// assert_eq!(s, [1, 40, 30, 20, 60, 1]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
- where F: FnMut(&T) -> bool
- {
- core_slice::SliceExt::rsplitn_mut(self, n, pred)
- }
-
- /// Returns `true` if the slice contains an element with the given value.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert!(v.contains(&30));
- /// assert!(!v.contains(&50));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn contains(&self, x: &T) -> bool
- where T: PartialEq
- {
- core_slice::SliceExt::contains(self, x)
- }
-
- /// Returns `true` if `needle` is a prefix of the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert!(v.starts_with(&[10]));
- /// assert!(v.starts_with(&[10, 40]));
- /// assert!(!v.starts_with(&[50]));
- /// assert!(!v.starts_with(&[10, 50]));
- /// ```
- ///
- /// Always returns `true` if `needle` is an empty slice:
- ///
- /// ```
- /// let v = &[10, 40, 30];
- /// assert!(v.starts_with(&[]));
- /// let v: &[u8] = &[];
- /// assert!(v.starts_with(&[]));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn starts_with(&self, needle: &[T]) -> bool
- where T: PartialEq
- {
- core_slice::SliceExt::starts_with(self, needle)
- }
-
- /// Returns `true` if `needle` is a suffix of the slice.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = [10, 40, 30];
- /// assert!(v.ends_with(&[30]));
- /// assert!(v.ends_with(&[40, 30]));
- /// assert!(!v.ends_with(&[50]));
- /// assert!(!v.ends_with(&[50, 30]));
- /// ```
- ///
- /// Always returns `true` if `needle` is an empty slice:
- ///
- /// ```
- /// let v = &[10, 40, 30];
- /// assert!(v.ends_with(&[]));
- /// let v: &[u8] = &[];
- /// assert!(v.ends_with(&[]));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn ends_with(&self, needle: &[T]) -> bool
- where T: PartialEq
- {
- core_slice::SliceExt::ends_with(self, needle)
- }
-
- /// Binary searches this sorted slice for a given element.
- ///
- /// If the value is found then `Ok` is returned, containing the
- /// index of the matching element; if the value is not found then
- /// `Err` is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
- ///
- /// # Examples
- ///
- /// Looks up a series of four elements. The first is found, with a
- /// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1, 4]`.
- ///
- /// ```
- /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- ///
- /// assert_eq!(s.binary_search(&13), Ok(9));
- /// assert_eq!(s.binary_search(&4), Err(7));
- /// assert_eq!(s.binary_search(&100), Err(13));
- /// let r = s.binary_search(&1);
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn binary_search(&self, x: &T) -> Result<usize, usize>
- where T: Ord
- {
- core_slice::SliceExt::binary_search(self, x)
- }
-
- /// Binary searches this sorted slice with a comparator function.
- ///
- /// The comparator function should implement an order consistent
- /// with the sort order of the underlying slice, returning an
- /// order code that indicates whether its argument is `Less`,
- /// `Equal` or `Greater` the desired target.
- ///
- /// If a matching value is found then returns `Ok`, containing
- /// the index for the matched element; if no match is found then
- /// `Err` is returned, containing the index where a matching
- /// element could be inserted while maintaining sorted order.
- ///
- /// # Examples
- ///
- /// Looks up a series of four elements. The first is found, with a
- /// uniquely determined position; the second and third are not
- /// found; the fourth could match any position in `[1, 4]`.
- ///
- /// ```
- /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
- ///
- /// let seek = 13;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
- /// let seek = 4;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
- /// let seek = 100;
- /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
- /// let seek = 1;
- /// let r = s.binary_search_by(|probe| probe.cmp(&seek));
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
- where F: FnMut(&'a T) -> Ordering
- {
- core_slice::SliceExt::binary_search_by(self, f)
- }
-
- /// Binary searches this sorted slice with a key extraction function.
- ///
- /// Assumes that the slice is sorted by the key, for instance with
- /// [`sort_by_key`] using the same key extraction function.
- ///
- /// If a matching value is found then returns `Ok`, containing the
- /// index for the matched element; if no match is found then `Err`
- /// is returned, containing the index where a matching element could
- /// be inserted while maintaining sorted order.
- ///
- /// [`sort_by_key`]: #method.sort_by_key
- ///
- /// # Examples
- ///
- /// Looks up a series of four elements in a slice of pairs sorted by
- /// their second elements. The first is found, with a uniquely
- /// determined position; the second and third are not found; the
- /// fourth could match any position in `[1, 4]`.
- ///
- /// ```
- /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
- /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
- /// (1, 21), (2, 34), (4, 55)];
- ///
- /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9));
- /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7));
- /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13));
- /// let r = s.binary_search_by_key(&1, |&(a,b)| b);
- /// assert!(match r { Ok(1...4) => true, _ => false, });
- /// ```
- #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
- #[inline]
- pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
- where F: FnMut(&'a T) -> B,
- B: Ord
- {
- core_slice::SliceExt::binary_search_by_key(self, b, f)
- }
+ #[cfg(stage0)]
+ slice_core_methods!();
/// Sorts the slice.
///
sort_by_key!(usize, self, f)
}
- /// Sorts the slice, but may not preserve the order of equal elements.
- ///
- /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
- /// and `O(n log n)` worst-case.
- ///
- /// # Current implementation
- ///
- /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
- /// which combines the fast average case of randomized quicksort with the fast worst case of
- /// heapsort, while achieving linear time on slices with certain patterns. It uses some
- /// randomization to avoid degenerate cases, but with a fixed seed to always provide
- /// deterministic behavior.
- ///
- /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
- /// slice consists of several concatenated sorted sequences.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [-5, 4, 1, -3, 2];
- ///
- /// v.sort_unstable();
- /// assert!(v == [-5, -3, 1, 2, 4]);
- /// ```
- ///
- /// [pdqsort]: https://github.com/orlp/pdqsort
- #[stable(feature = "sort_unstable", since = "1.20.0")]
- #[inline]
- pub fn sort_unstable(&mut self)
- where T: Ord
- {
- core_slice::SliceExt::sort_unstable(self);
- }
-
- /// Sorts the slice with a comparator function, but may not preserve the order of equal
- /// elements.
- ///
- /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
- /// and `O(n log n)` worst-case.
- ///
- /// # Current implementation
- ///
- /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
- /// which combines the fast average case of randomized quicksort with the fast worst case of
- /// heapsort, while achieving linear time on slices with certain patterns. It uses some
- /// randomization to avoid degenerate cases, but with a fixed seed to always provide
- /// deterministic behavior.
- ///
- /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
- /// slice consists of several concatenated sorted sequences.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [5, 4, 1, 3, 2];
- /// v.sort_unstable_by(|a, b| a.cmp(b));
- /// assert!(v == [1, 2, 3, 4, 5]);
- ///
- /// // reverse sorting
- /// v.sort_unstable_by(|a, b| b.cmp(a));
- /// assert!(v == [5, 4, 3, 2, 1]);
- /// ```
- ///
- /// [pdqsort]: https://github.com/orlp/pdqsort
- #[stable(feature = "sort_unstable", since = "1.20.0")]
- #[inline]
- pub fn sort_unstable_by<F>(&mut self, compare: F)
- where F: FnMut(&T, &T) -> Ordering
- {
- core_slice::SliceExt::sort_unstable_by(self, compare);
- }
-
- /// Sorts the slice with a key extraction function, but may not preserve the order of equal
- /// elements.
- ///
- /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
- /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`.
- ///
- /// # Current implementation
- ///
- /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
- /// which combines the fast average case of randomized quicksort with the fast worst case of
- /// heapsort, while achieving linear time on slices with certain patterns. It uses some
- /// randomization to avoid degenerate cases, but with a fixed seed to always provide
- /// deterministic behavior.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = [-5i32, 4, 1, -3, 2];
- ///
- /// v.sort_unstable_by_key(|k| k.abs());
- /// assert!(v == [1, 2, -3, 4, -5]);
- /// ```
- ///
- /// [pdqsort]: https://github.com/orlp/pdqsort
- #[stable(feature = "sort_unstable", since = "1.20.0")]
- #[inline]
- pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
- where F: FnMut(&T) -> K, K: Ord
- {
- core_slice::SliceExt::sort_unstable_by_key(self, f);
- }
-
- /// Rotates the slice in-place such that the first `mid` elements of the
- /// slice move to the end while the last `self.len() - mid` elements move to
- /// the front. After calling `rotate_left`, the element previously at index
- /// `mid` will become the first element in the slice.
- ///
- /// # Panics
- ///
- /// This function will panic if `mid` is greater than the length of the
- /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op
- /// rotation.
- ///
- /// # Complexity
- ///
- /// Takes linear (in `self.len()`) time.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a.rotate_left(2);
- /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
- /// ```
- ///
- /// Rotating a subslice:
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a[1..5].rotate_left(1);
- /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
- /// ```
- #[stable(feature = "slice_rotate", since = "1.26.0")]
- pub fn rotate_left(&mut self, mid: usize) {
- core_slice::SliceExt::rotate_left(self, mid);
- }
-
- /// Rotates the slice in-place such that the first `self.len() - k`
- /// elements of the slice move to the end while the last `k` elements move
- /// to the front. After calling `rotate_right`, the element previously at
- /// index `self.len() - k` will become the first element in the slice.
- ///
- /// # Panics
- ///
- /// This function will panic if `k` is greater than the length of the
- /// slice. Note that `k == self.len()` does _not_ panic and is a no-op
- /// rotation.
- ///
- /// # Complexity
- ///
- /// Takes linear (in `self.len()`) time.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a.rotate_right(2);
- /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']);
- /// ```
- ///
- /// Rotate a subslice:
- ///
- /// ```
- /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
- /// a[1..5].rotate_right(1);
- /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
- /// ```
- #[stable(feature = "slice_rotate", since = "1.26.0")]
- pub fn rotate_right(&mut self, k: usize) {
- core_slice::SliceExt::rotate_right(self, k);
- }
-
- /// Copies the elements from `src` into `self`.
- ///
- /// The length of `src` must be the same as `self`.
- ///
- /// If `src` implements `Copy`, it can be more performant to use
- /// [`copy_from_slice`].
- ///
- /// # Panics
- ///
- /// This function will panic if the two slices have different lengths.
- ///
- /// # Examples
- ///
- /// Cloning two elements from a slice into another:
- ///
- /// ```
- /// let src = [1, 2, 3, 4];
- /// let mut dst = [0, 0];
- ///
- /// dst.clone_from_slice(&src[2..]);
- ///
- /// assert_eq!(src, [1, 2, 3, 4]);
- /// assert_eq!(dst, [3, 4]);
- /// ```
- ///
- /// Rust enforces that there can only be one mutable reference with no
- /// immutable references to a particular piece of data in a particular
- /// scope. Because of this, attempting to use `clone_from_slice` on a
- /// single slice will result in a compile failure:
- ///
- /// ```compile_fail
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// slice[..2].clone_from_slice(&slice[3..]); // compile fail!
- /// ```
- ///
- /// To work around this, we can use [`split_at_mut`] to create two distinct
- /// sub-slices from a slice:
- ///
- /// ```
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// {
- /// let (left, right) = slice.split_at_mut(2);
- /// left.clone_from_slice(&right[1..]);
- /// }
- ///
- /// assert_eq!(slice, [4, 5, 3, 4, 5]);
- /// ```
- ///
- /// [`copy_from_slice`]: #method.copy_from_slice
- /// [`split_at_mut`]: #method.split_at_mut
- #[stable(feature = "clone_from_slice", since = "1.7.0")]
- pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
- core_slice::SliceExt::clone_from_slice(self, src)
- }
-
- /// Copies all elements from `src` into `self`, using a memcpy.
- ///
- /// The length of `src` must be the same as `self`.
- ///
- /// If `src` does not implement `Copy`, use [`clone_from_slice`].
- ///
- /// # Panics
- ///
- /// This function will panic if the two slices have different lengths.
- ///
- /// # Examples
- ///
- /// Copying two elements from a slice into another:
- ///
- /// ```
- /// let src = [1, 2, 3, 4];
- /// let mut dst = [0, 0];
- ///
- /// dst.copy_from_slice(&src[2..]);
- ///
- /// assert_eq!(src, [1, 2, 3, 4]);
- /// assert_eq!(dst, [3, 4]);
- /// ```
- ///
- /// Rust enforces that there can only be one mutable reference with no
- /// immutable references to a particular piece of data in a particular
- /// scope. Because of this, attempting to use `copy_from_slice` on a
- /// single slice will result in a compile failure:
- ///
- /// ```compile_fail
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// slice[..2].copy_from_slice(&slice[3..]); // compile fail!
- /// ```
- ///
- /// To work around this, we can use [`split_at_mut`] to create two distinct
- /// sub-slices from a slice:
- ///
- /// ```
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// {
- /// let (left, right) = slice.split_at_mut(2);
- /// left.copy_from_slice(&right[1..]);
- /// }
- ///
- /// assert_eq!(slice, [4, 5, 3, 4, 5]);
- /// ```
- ///
- /// [`clone_from_slice`]: #method.clone_from_slice
- /// [`split_at_mut`]: #method.split_at_mut
- #[stable(feature = "copy_from_slice", since = "1.9.0")]
- pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
- core_slice::SliceExt::copy_from_slice(self, src)
- }
-
- /// Swaps all elements in `self` with those in `other`.
- ///
- /// The length of `other` must be the same as `self`.
- ///
- /// # Panics
- ///
- /// This function will panic if the two slices have different lengths.
- ///
- /// # Example
- ///
- /// Swapping two elements across slices:
- ///
- /// ```
- /// #![feature(swap_with_slice)]
- ///
- /// let mut slice1 = [0, 0];
- /// let mut slice2 = [1, 2, 3, 4];
- ///
- /// slice1.swap_with_slice(&mut slice2[2..]);
- ///
- /// assert_eq!(slice1, [3, 4]);
- /// assert_eq!(slice2, [1, 2, 0, 0]);
- /// ```
- ///
- /// Rust enforces that there can only be one mutable reference to a
- /// particular piece of data in a particular scope. Because of this,
- /// attempting to use `swap_with_slice` on a single slice will result in
- /// a compile failure:
- ///
- /// ```compile_fail
- /// #![feature(swap_with_slice)]
- ///
- /// let mut slice = [1, 2, 3, 4, 5];
- /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail!
- /// ```
- ///
- /// To work around this, we can use [`split_at_mut`] to create two distinct
- /// mutable sub-slices from a slice:
- ///
- /// ```
- /// #![feature(swap_with_slice)]
- ///
- /// let mut slice = [1, 2, 3, 4, 5];
- ///
- /// {
- /// let (left, right) = slice.split_at_mut(2);
- /// left.swap_with_slice(&mut right[1..]);
- /// }
- ///
- /// assert_eq!(slice, [4, 5, 3, 1, 2]);
- /// ```
- ///
- /// [`split_at_mut`]: #method.split_at_mut
- #[unstable(feature = "swap_with_slice", issue = "44030")]
- pub fn swap_with_slice(&mut self, other: &mut [T]) {
- core_slice::SliceExt::swap_with_slice(self, other)
- }
-
/// Copies `self` into a new `Vec`.
///
/// # Examples
}
}
-#[lang = "slice_u8"]
+#[cfg_attr(stage0, lang = "slice_u8")]
+#[cfg_attr(not(stage0), lang = "slice_u8_alloc")]
#[cfg(not(test))]
impl [u8] {
- /// Checks if all bytes in this slice are within the ASCII range.
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn is_ascii(&self) -> bool {
- self.iter().all(|b| b.is_ascii())
- }
-
/// Returns a vector containing a copy of this slice where each byte
/// is mapped to its ASCII upper case equivalent.
///
me
}
- /// Checks that two slices are an ASCII case-insensitive match.
- ///
- /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
- /// but without allocating and copying temporaries.
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
- self.len() == other.len() &&
- self.iter().zip(other).all(|(a, b)| {
- a.eq_ignore_ascii_case(b)
- })
- }
-
- /// Converts this slice to its ASCII upper case equivalent in-place.
- ///
- /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new uppercased value without modifying the existing one, use
- /// [`to_ascii_uppercase`].
- ///
- /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn make_ascii_uppercase(&mut self) {
- for byte in self {
- byte.make_ascii_uppercase();
- }
- }
-
- /// Converts this slice to its ASCII lower case equivalent in-place.
- ///
- /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new lowercased value without modifying the existing one, use
- /// [`to_ascii_lowercase`].
- ///
- /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn make_ascii_lowercase(&mut self) {
- for byte in self {
- byte.make_ascii_lowercase();
- }
- }
+ #[cfg(stage0)]
+ slice_u8_core_methods!();
}
////////////////////////////////////////////////////////////////////////////////
use core::fmt;
use core::str as core_str;
+#[cfg(stage0)] use core::str::StrExt;
use core::str::pattern::Pattern;
use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
use core::mem;
pub use core::str::SplitWhitespace;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::pattern;
-
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+pub use core::str::EncodeUtf16;
#[unstable(feature = "slice_concat_ext",
reason = "trait should not have to exist",
issue = "27747")]
impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
- type Output = String;
-
- fn concat(&self) -> String {
- if self.is_empty() {
- return String::new();
- }
-
- // `len` calculation may overflow but push_str will check boundaries
- let len = self.iter().map(|s| s.borrow().len()).sum();
- let mut result = String::with_capacity(len);
-
- for s in self {
- result.push_str(s.borrow())
- }
-
- result
- }
-
- fn join(&self, sep: &str) -> String {
- if self.is_empty() {
- return String::new();
- }
-
- // concat is faster
- if sep.is_empty() {
- return self.concat();
- }
-
- // this is wrong without the guarantee that `self` is non-empty
- // `len` calculation may overflow but push_str but will check boundaries
- let len = sep.len() * (self.len() - 1) +
- self.iter().map(|s| s.borrow().len()).sum::<usize>();
- let mut result = String::with_capacity(len);
- let mut first = true;
-
- for s in self {
- if first {
- first = false;
- } else {
- result.push_str(sep);
- }
- result.push_str(s.borrow());
- }
- result
- }
-
- fn connect(&self, sep: &str) -> String {
- self.join(sep)
- }
-}
-
-/// An iterator of [`u16`] over the string encoded as UTF-16.
-///
-/// [`u16`]: ../../std/primitive.u16.html
-///
-/// This struct is created by the [`encode_utf16`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16
-/// [`str`]: ../../std/primitive.str.html
-#[derive(Clone)]
-#[stable(feature = "encode_utf16", since = "1.8.0")]
-pub struct EncodeUtf16<'a> {
- chars: Chars<'a>,
- extra: u16,
-}
-
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<'a> fmt::Debug for EncodeUtf16<'a> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.pad("EncodeUtf16 { .. }")
- }
-}
-
-#[stable(feature = "encode_utf16", since = "1.8.0")]
-impl<'a> Iterator for EncodeUtf16<'a> {
- type Item = u16;
-
- #[inline]
- fn next(&mut self) -> Option<u16> {
- if self.extra != 0 {
- let tmp = self.extra;
- self.extra = 0;
- return Some(tmp);
- }
-
- let mut buf = [0; 2];
- self.chars.next().map(|ch| {
- let n = ch.encode_utf16(&mut buf).len();
- if n == 2 {
- self.extra = buf[1];
- }
- buf[0]
- })
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (low, high) = self.chars.size_hint();
- // every char gets either one u16 or two u16,
- // so this iterator is between 1 or 2 times as
- // long as the underlying iterator.
- (low, high.and_then(|n| n.checked_mul(2)))
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<'a> FusedIterator for EncodeUtf16<'a> {}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Borrow<str> for String {
- #[inline]
- fn borrow(&self) -> &str {
- &self[..]
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl ToOwned for str {
- type Owned = String;
- fn to_owned(&self) -> String {
- unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
- }
-
- fn clone_into(&self, target: &mut String) {
- let mut b = mem::replace(target, String::new()).into_bytes();
- self.as_bytes().clone_into(&mut b);
- *target = unsafe { String::from_utf8_unchecked(b) }
- }
-}
-
-/// Methods for string slices.
-#[lang = "str"]
-#[cfg(not(test))]
-impl str {
- /// Returns the length of `self`.
- ///
- /// This length is in bytes, not [`char`]s or graphemes. In other words,
- /// it may not be what a human considers the length of the string.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let len = "foo".len();
- /// assert_eq!(3, len);
- ///
- /// let len = "ƒoo".len(); // fancy f!
- /// assert_eq!(4, len);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn len(&self) -> usize {
- core_str::StrExt::len(self)
- }
-
- /// Returns `true` if `self` has a length of zero bytes.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "";
- /// assert!(s.is_empty());
- ///
- /// let s = "not empty";
- /// assert!(!s.is_empty());
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn is_empty(&self) -> bool {
- core_str::StrExt::is_empty(self)
- }
-
- /// Checks that `index`-th byte lies at the start and/or end of a
- /// UTF-8 code point sequence.
- ///
- /// The start and end of the string (when `index == self.len()`) are
- /// considered to be
- /// boundaries.
- ///
- /// Returns `false` if `index` is greater than `self.len()`.
- ///
- /// # Examples
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- /// assert!(s.is_char_boundary(0));
- /// // start of `老`
- /// assert!(s.is_char_boundary(6));
- /// assert!(s.is_char_boundary(s.len()));
- ///
- /// // second byte of `ö`
- /// assert!(!s.is_char_boundary(2));
- ///
- /// // third byte of `老`
- /// assert!(!s.is_char_boundary(8));
- /// ```
- #[stable(feature = "is_char_boundary", since = "1.9.0")]
- #[inline]
- pub fn is_char_boundary(&self, index: usize) -> bool {
- core_str::StrExt::is_char_boundary(self, index)
- }
-
- /// Converts a string slice to a byte slice. To convert the byte slice back
- /// into a string slice, use the [`str::from_utf8`] function.
- ///
- /// [`str::from_utf8`]: ./str/fn.from_utf8.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bytes = "bors".as_bytes();
- /// assert_eq!(b"bors", bytes);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline(always)]
- pub fn as_bytes(&self) -> &[u8] {
- core_str::StrExt::as_bytes(self)
- }
-
- /// Converts a mutable string slice to a mutable byte slice. To convert the
- /// mutable byte slice back into a mutable string slice, use the
- /// [`str::from_utf8_mut`] function.
- ///
- /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut s = String::from("Hello");
- /// let bytes = unsafe { s.as_bytes_mut() };
- ///
- /// assert_eq!(b"Hello", bytes);
- /// ```
- ///
- /// Mutability:
- ///
- /// ```
- /// let mut s = String::from("🗻∈🌏");
- ///
- /// unsafe {
- /// let bytes = s.as_bytes_mut();
- ///
- /// bytes[0] = 0xF0;
- /// bytes[1] = 0x9F;
- /// bytes[2] = 0x8D;
- /// bytes[3] = 0x94;
- /// }
- ///
- /// assert_eq!("🍔∈🌏", s);
- /// ```
- #[stable(feature = "str_mut_extras", since = "1.20.0")]
- #[inline(always)]
- pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
- core_str::StrExt::as_bytes_mut(self)
- }
-
- /// Converts a string slice to a raw pointer.
- ///
- /// As string slices are a slice of bytes, the raw pointer points to a
- /// [`u8`]. This pointer will be pointing to the first byte of the string
- /// slice.
- ///
- /// [`u8`]: primitive.u8.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "Hello";
- /// let ptr = s.as_ptr();
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn as_ptr(&self) -> *const u8 {
- core_str::StrExt::as_ptr(self)
- }
-
- /// Returns a subslice of `str`.
- ///
- /// This is the non-panicking alternative to indexing the `str`. Returns
- /// [`None`] whenever equivalent indexing operation would panic.
- ///
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// ```
- /// let v = String::from("🗻∈🌏");
- ///
- /// assert_eq!(Some("🗻"), v.get(0..4));
- ///
- /// // indices not on UTF-8 sequence boundaries
- /// assert!(v.get(1..).is_none());
- /// assert!(v.get(..8).is_none());
- ///
- /// // out of bounds
- /// assert!(v.get(..42).is_none());
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
- core_str::StrExt::get(self, i)
- }
-
- /// Returns a mutable subslice of `str`.
- ///
- /// This is the non-panicking alternative to indexing the `str`. Returns
- /// [`None`] whenever equivalent indexing operation would panic.
- ///
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = String::from("hello");
- /// // correct length
- /// assert!(v.get_mut(0..5).is_some());
- /// // out of bounds
- /// assert!(v.get_mut(..42).is_none());
- /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v));
- ///
- /// assert_eq!("hello", v);
- /// {
- /// let s = v.get_mut(0..2);
- /// let s = s.map(|s| {
- /// s.make_ascii_uppercase();
- /// &*s
- /// });
- /// assert_eq!(Some("HE"), s);
- /// }
- /// assert_eq!("HEllo", v);
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
- core_str::StrExt::get_mut(self, i)
- }
-
- /// Returns a unchecked subslice of `str`.
- ///
- /// This is the unchecked alternative to indexing the `str`.
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that these preconditions are
- /// satisfied:
- ///
- /// * The starting index must come before the ending index;
- /// * Indexes must be within bounds of the original slice;
- /// * Indexes must lie on UTF-8 sequence boundaries.
- ///
- /// Failing that, the returned string slice may reference invalid memory or
- /// violate the invariants communicated by the `str` type.
- ///
- /// # Examples
- ///
- /// ```
- /// let v = "🗻∈🌏";
- /// unsafe {
- /// assert_eq!("🗻", v.get_unchecked(0..4));
- /// assert_eq!("∈", v.get_unchecked(4..7));
- /// assert_eq!("🌏", v.get_unchecked(7..11));
- /// }
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
- core_str::StrExt::get_unchecked(self, i)
- }
-
- /// Returns a mutable, unchecked subslice of `str`.
- ///
- /// This is the unchecked alternative to indexing the `str`.
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that these preconditions are
- /// satisfied:
- ///
- /// * The starting index must come before the ending index;
- /// * Indexes must be within bounds of the original slice;
- /// * Indexes must lie on UTF-8 sequence boundaries.
- ///
- /// Failing that, the returned string slice may reference invalid memory or
- /// violate the invariants communicated by the `str` type.
- ///
- /// # Examples
- ///
- /// ```
- /// let mut v = String::from("🗻∈🌏");
- /// unsafe {
- /// assert_eq!("🗻", v.get_unchecked_mut(0..4));
- /// assert_eq!("∈", v.get_unchecked_mut(4..7));
- /// assert_eq!("🌏", v.get_unchecked_mut(7..11));
- /// }
- /// ```
- #[stable(feature = "str_checked_slicing", since = "1.20.0")]
- #[inline]
- pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
- core_str::StrExt::get_unchecked_mut(self, i)
- }
-
- /// Creates a string slice from another string slice, bypassing safety
- /// checks.
- ///
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`str`] and [`Index`].
- ///
- /// [`str`]: primitive.str.html
- /// [`Index`]: ops/trait.Index.html
- ///
- /// This new slice goes from `begin` to `end`, including `begin` but
- /// excluding `end`.
- ///
- /// To get a mutable string slice instead, see the
- /// [`slice_mut_unchecked`] method.
- ///
- /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that three preconditions are
- /// satisfied:
- ///
- /// * `begin` must come before `end`.
- /// * `begin` and `end` must be byte positions within the string slice.
- /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// unsafe {
- /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21));
- /// }
- ///
- /// let s = "Hello, world!";
- ///
- /// unsafe {
- /// assert_eq!("world", s.slice_unchecked(7, 12));
- /// }
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
- core_str::StrExt::slice_unchecked(self, begin, end)
- }
-
- /// Creates a string slice from another string slice, bypassing safety
- /// checks.
- /// This is generally not recommended, use with caution! For a safe
- /// alternative see [`str`] and [`IndexMut`].
- ///
- /// [`str`]: primitive.str.html
- /// [`IndexMut`]: ops/trait.IndexMut.html
- ///
- /// This new slice goes from `begin` to `end`, including `begin` but
- /// excluding `end`.
- ///
- /// To get an immutable string slice instead, see the
- /// [`slice_unchecked`] method.
- ///
- /// [`slice_unchecked`]: #method.slice_unchecked
- ///
- /// # Safety
- ///
- /// Callers of this function are responsible that three preconditions are
- /// satisfied:
- ///
- /// * `begin` must come before `end`.
- /// * `begin` and `end` must be byte positions within the string slice.
- /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
- #[stable(feature = "str_slice_mut", since = "1.5.0")]
- #[inline]
- pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
- core_str::StrExt::slice_mut_unchecked(self, begin, end)
- }
-
- /// Divide one string slice into two at an index.
- ///
- /// The argument, `mid`, should be a byte offset from the start of the
- /// string. It must also be on the boundary of a UTF-8 code point.
- ///
- /// The two slices returned go from the start of the string slice to `mid`,
- /// and from `mid` to the end of the string slice.
- ///
- /// To get mutable string slices instead, see the [`split_at_mut`]
- /// method.
- ///
- /// [`split_at_mut`]: #method.split_at_mut
- ///
- /// # Panics
- ///
- /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
- /// beyond the last code point of the string slice.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = "Per Martin-Löf";
- ///
- /// let (first, last) = s.split_at(3);
- ///
- /// assert_eq!("Per", first);
- /// assert_eq!(" Martin-Löf", last);
- /// ```
- #[inline]
- #[stable(feature = "str_split_at", since = "1.4.0")]
- pub fn split_at(&self, mid: usize) -> (&str, &str) {
- core_str::StrExt::split_at(self, mid)
- }
-
- /// Divide one mutable string slice into two at an index.
- ///
- /// The argument, `mid`, should be a byte offset from the start of the
- /// string. It must also be on the boundary of a UTF-8 code point.
- ///
- /// The two slices returned go from the start of the string slice to `mid`,
- /// and from `mid` to the end of the string slice.
- ///
- /// To get immutable string slices instead, see the [`split_at`] method.
- ///
- /// [`split_at`]: #method.split_at
- ///
- /// # Panics
- ///
- /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
- /// beyond the last code point of the string slice.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut s = "Per Martin-Löf".to_string();
- /// {
- /// let (first, last) = s.split_at_mut(3);
- /// first.make_ascii_uppercase();
- /// assert_eq!("PER", first);
- /// assert_eq!(" Martin-Löf", last);
- /// }
- /// assert_eq!("PER Martin-Löf", s);
- /// ```
- #[inline]
- #[stable(feature = "str_split_at", since = "1.4.0")]
- pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
- core_str::StrExt::split_at_mut(self, mid)
- }
-
- /// Returns an iterator over the [`char`]s of a string slice.
- ///
- /// As a string slice consists of valid UTF-8, we can iterate through a
- /// string slice by [`char`]. This method returns such an iterator.
- ///
- /// It's important to remember that [`char`] represents a Unicode Scalar
- /// Value, and may not match your idea of what a 'character' is. Iteration
- /// over grapheme clusters may be what you actually want.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let word = "goodbye";
- ///
- /// let count = word.chars().count();
- /// assert_eq!(7, count);
- ///
- /// let mut chars = word.chars();
- ///
- /// assert_eq!(Some('g'), chars.next());
- /// assert_eq!(Some('o'), chars.next());
- /// assert_eq!(Some('o'), chars.next());
- /// assert_eq!(Some('d'), chars.next());
- /// assert_eq!(Some('b'), chars.next());
- /// assert_eq!(Some('y'), chars.next());
- /// assert_eq!(Some('e'), chars.next());
- ///
- /// assert_eq!(None, chars.next());
- /// ```
- ///
- /// Remember, [`char`]s may not match your human intuition about characters:
- ///
- /// ```
- /// let y = "y̆";
- ///
- /// let mut chars = y.chars();
- ///
- /// assert_eq!(Some('y'), chars.next()); // not 'y̆'
- /// assert_eq!(Some('\u{0306}'), chars.next());
- ///
- /// assert_eq!(None, chars.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn chars(&self) -> Chars {
- core_str::StrExt::chars(self)
- }
- /// Returns an iterator over the [`char`]s of a string slice, and their
- /// positions.
- ///
- /// As a string slice consists of valid UTF-8, we can iterate through a
- /// string slice by [`char`]. This method returns an iterator of both
- /// these [`char`]s, as well as their byte positions.
- ///
- /// The iterator yields tuples. The position is first, the [`char`] is
- /// second.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let word = "goodbye";
- ///
- /// let count = word.char_indices().count();
- /// assert_eq!(7, count);
- ///
- /// let mut char_indices = word.char_indices();
- ///
- /// assert_eq!(Some((0, 'g')), char_indices.next());
- /// assert_eq!(Some((1, 'o')), char_indices.next());
- /// assert_eq!(Some((2, 'o')), char_indices.next());
- /// assert_eq!(Some((3, 'd')), char_indices.next());
- /// assert_eq!(Some((4, 'b')), char_indices.next());
- /// assert_eq!(Some((5, 'y')), char_indices.next());
- /// assert_eq!(Some((6, 'e')), char_indices.next());
- ///
- /// assert_eq!(None, char_indices.next());
- /// ```
- ///
- /// Remember, [`char`]s may not match your human intuition about characters:
- ///
- /// ```
- /// let yes = "y̆es";
- ///
- /// let mut char_indices = yes.char_indices();
- ///
- /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆')
- /// assert_eq!(Some((1, '\u{0306}')), char_indices.next());
- ///
- /// // note the 3 here - the last character took up two bytes
- /// assert_eq!(Some((3, 'e')), char_indices.next());
- /// assert_eq!(Some((4, 's')), char_indices.next());
- ///
- /// assert_eq!(None, char_indices.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn char_indices(&self) -> CharIndices {
- core_str::StrExt::char_indices(self)
- }
-
- /// An iterator over the bytes of a string slice.
- ///
- /// As a string slice consists of a sequence of bytes, we can iterate
- /// through a string slice by byte. This method returns such an iterator.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut bytes = "bors".bytes();
- ///
- /// assert_eq!(Some(b'b'), bytes.next());
- /// assert_eq!(Some(b'o'), bytes.next());
- /// assert_eq!(Some(b'r'), bytes.next());
- /// assert_eq!(Some(b's'), bytes.next());
- ///
- /// assert_eq!(None, bytes.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn bytes(&self) -> Bytes {
- core_str::StrExt::bytes(self)
- }
-
- /// Split a string slice by whitespace.
- ///
- /// The iterator returned will return string slices that are sub-slices of
- /// the original string slice, separated by any amount of whitespace.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let mut iter = "A few words".split_whitespace();
- ///
- /// assert_eq!(Some("A"), iter.next());
- /// assert_eq!(Some("few"), iter.next());
- /// assert_eq!(Some("words"), iter.next());
- ///
- /// assert_eq!(None, iter.next());
- /// ```
- ///
- /// All kinds of whitespace are considered:
- ///
- /// ```
- /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace();
- /// assert_eq!(Some("Mary"), iter.next());
- /// assert_eq!(Some("had"), iter.next());
- /// assert_eq!(Some("a"), iter.next());
- /// assert_eq!(Some("little"), iter.next());
- /// assert_eq!(Some("lamb"), iter.next());
- ///
- /// assert_eq!(None, iter.next());
- /// ```
- #[stable(feature = "split_whitespace", since = "1.1.0")]
- #[inline]
- pub fn split_whitespace(&self) -> SplitWhitespace {
- StrExt::split_whitespace(self)
- }
-
- /// An iterator over the lines of a string, as string slices.
- ///
- /// Lines are ended with either a newline (`\n`) or a carriage return with
- /// a line feed (`\r\n`).
- ///
- /// The final line ending is optional.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let text = "foo\r\nbar\n\nbaz\n";
- /// let mut lines = text.lines();
- ///
- /// assert_eq!(Some("foo"), lines.next());
- /// assert_eq!(Some("bar"), lines.next());
- /// assert_eq!(Some(""), lines.next());
- /// assert_eq!(Some("baz"), lines.next());
- ///
- /// assert_eq!(None, lines.next());
- /// ```
- ///
- /// The final line ending isn't required:
- ///
- /// ```
- /// let text = "foo\nbar\n\r\nbaz";
- /// let mut lines = text.lines();
- ///
- /// assert_eq!(Some("foo"), lines.next());
- /// assert_eq!(Some("bar"), lines.next());
- /// assert_eq!(Some(""), lines.next());
- /// assert_eq!(Some("baz"), lines.next());
- ///
- /// assert_eq!(None, lines.next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn lines(&self) -> Lines {
- core_str::StrExt::lines(self)
- }
-
- /// An iterator over the lines of a string.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")]
- #[inline]
- #[allow(deprecated)]
- pub fn lines_any(&self) -> LinesAny {
- core_str::StrExt::lines_any(self)
- }
-
- /// Returns an iterator of `u16` over the string encoded as UTF-16.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let text = "Zażółć gęślą jaźń";
- ///
- /// let utf8_len = text.len();
- /// let utf16_len = text.encode_utf16().count();
- ///
- /// assert!(utf16_len <= utf8_len);
- /// ```
- #[stable(feature = "encode_utf16", since = "1.8.0")]
- pub fn encode_utf16(&self) -> EncodeUtf16 {
- EncodeUtf16 { chars: self[..].chars(), extra: 0 }
- }
-
- /// Returns `true` if the given pattern matches a sub-slice of
- /// this string slice.
- ///
- /// Returns `false` if it does not.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bananas = "bananas";
- ///
- /// assert!(bananas.contains("nana"));
- /// assert!(!bananas.contains("apples"));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::contains(self, pat)
- }
-
- /// Returns `true` if the given pattern matches a prefix of this
- /// string slice.
- ///
- /// Returns `false` if it does not.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bananas = "bananas";
- ///
- /// assert!(bananas.starts_with("bana"));
- /// assert!(!bananas.starts_with("nana"));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
- core_str::StrExt::starts_with(self, pat)
- }
-
- /// Returns `true` if the given pattern matches a suffix of this
- /// string slice.
- ///
- /// Returns `false` if it does not.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let bananas = "bananas";
- ///
- /// assert!(bananas.ends_with("anas"));
- /// assert!(!bananas.ends_with("nana"));
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::ends_with(self, pat)
- }
-
- /// Returns the byte index of the first character of this string slice that
- /// matches the pattern.
- ///
- /// Returns [`None`] if the pattern doesn't match.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.find('L'), Some(0));
- /// assert_eq!(s.find('é'), Some(14));
- /// assert_eq!(s.find("Léopard"), Some(13));
- /// ```
- ///
- /// More complex patterns using point-free style and closures:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.find(char::is_whitespace), Some(5));
- /// assert_eq!(s.find(char::is_lowercase), Some(1));
- /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1));
- /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4));
- /// ```
- ///
- /// Not finding the pattern:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- /// let x: &[_] = &['1', '2'];
- ///
- /// assert_eq!(s.find(x), None);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
- core_str::StrExt::find(self, pat)
- }
-
- /// Returns the byte index of the last character of this string slice that
- /// matches the pattern.
- ///
- /// Returns [`None`] if the pattern doesn't match.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- /// [`None`]: option/enum.Option.html#variant.None
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.rfind('L'), Some(13));
- /// assert_eq!(s.rfind('é'), Some(14));
- /// ```
- ///
- /// More complex patterns with closures:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- ///
- /// assert_eq!(s.rfind(char::is_whitespace), Some(12));
- /// assert_eq!(s.rfind(char::is_lowercase), Some(20));
- /// ```
- ///
- /// Not finding the pattern:
- ///
- /// ```
- /// let s = "Löwe 老虎 Léopard";
- /// let x: &[_] = &['1', '2'];
- ///
- /// assert_eq!(s.rfind(x), None);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rfind(self, pat)
- }
-
- /// An iterator over substrings of this string slice, separated by
- /// characters matched by a pattern.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rsplit`] method can be used.
- ///
- /// [`char`]: primitive.char.html
- /// [`rsplit`]: #method.rsplit
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
- /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
- ///
- /// let v: Vec<&str> = "".split('X').collect();
- /// assert_eq!(v, [""]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
- /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
- ///
- /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
- /// assert_eq!(v, ["lion", "tiger", "leopard"]);
- ///
- /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect();
- /// assert_eq!(v, ["abc", "def", "ghi"]);
- ///
- /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect();
- /// assert_eq!(v, ["lion", "tiger", "leopard"]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["abc", "def", "ghi"]);
- /// ```
- ///
- /// If a string contains multiple contiguous separators, you will end up
- /// with empty strings in the output:
- ///
- /// ```
- /// let x = "||||a||b|c".to_string();
- /// let d: Vec<_> = x.split('|').collect();
- ///
- /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
- /// ```
- ///
- /// Contiguous separators are separated by the empty string.
- ///
- /// ```
- /// let x = "(///)".to_string();
- /// let d: Vec<_> = x.split('/').collect();
- ///
- /// assert_eq!(d, &["(", "", "", ")"]);
- /// ```
- ///
- /// Separators at the start or end of a string are neighbored
- /// by empty strings.
- ///
- /// ```
- /// let d: Vec<_> = "010".split("0").collect();
- /// assert_eq!(d, &["", "1", ""]);
- /// ```
- ///
- /// When the empty string is used as a separator, it separates
- /// every character in the string, along with the beginning
- /// and end of the string.
- ///
- /// ```
- /// let f: Vec<_> = "rust".split("").collect();
- /// assert_eq!(f, &["", "r", "u", "s", "t", ""]);
- /// ```
- ///
- /// Contiguous separators can lead to possibly surprising behavior
- /// when whitespace is used as the separator. This code is correct:
- ///
- /// ```
- /// let x = " a b c".to_string();
- /// let d: Vec<_> = x.split(' ').collect();
- ///
- /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
- /// ```
- ///
- /// It does _not_ give you:
- ///
- /// ```,ignore
- /// assert_eq!(d, &["a", "b", "c"]);
- /// ```
- ///
- /// Use [`split_whitespace`] for this behavior.
- ///
- /// [`split_whitespace`]: #method.split_whitespace
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
- core_str::StrExt::split(self, pat)
- }
-
- /// An iterator over substrings of the given string slice, separated by
- /// characters matched by a pattern and yielded in reverse order.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a reverse
- /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
- /// search yields the same elements.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// For iterating from the front, the [`split`] method can be used.
- ///
- /// [`split`]: #method.split
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
- /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
- ///
- /// let v: Vec<&str> = "".rsplit('X').collect();
- /// assert_eq!(v, [""]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect();
- /// assert_eq!(v, ["leopard", "tiger", "", "lion"]);
- ///
- /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
- /// assert_eq!(v, ["leopard", "tiger", "lion"]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["ghi", "def", "abc"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplit(self, pat)
- }
-
- /// An iterator over substrings of the given string slice, separated by
- /// characters matched by a pattern.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// Equivalent to [`split`], except that the trailing substring
- /// is skipped if empty.
- ///
- /// [`split`]: #method.split
- ///
- /// This method can be used for string data that is _terminated_,
- /// rather than _separated_ by a pattern.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- /// [`char`]: primitive.char.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rsplit_terminator`] method can be used.
- ///
- /// [`rsplit_terminator`]: #method.rsplit_terminator
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<&str> = "A.B.".split_terminator('.').collect();
- /// assert_eq!(v, ["A", "B"]);
- ///
- /// let v: Vec<&str> = "A..B..".split_terminator(".").collect();
- /// assert_eq!(v, ["A", "", "B", ""]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
- core_str::StrExt::split_terminator(self, pat)
- }
-
- /// An iterator over substrings of `self`, separated by characters
- /// matched by a pattern and yielded in reverse order.
- ///
- /// The pattern can be a simple `&str`, [`char`], or a closure that
- /// determines the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// Equivalent to [`split`], except that the trailing substring is
- /// skipped if empty.
- ///
- /// [`split`]: #method.split
- ///
- /// This method can be used for string data that is _terminated_,
- /// rather than _separated_ by a pattern.
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a
- /// reverse search, and it will be double ended if a forward/reverse
- /// search yields the same elements.
- ///
- /// For iterating from the front, the [`split_terminator`] method can be
- /// used.
- ///
- /// [`split_terminator`]: #method.split_terminator
- ///
- /// # Examples
- ///
- /// ```
- /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect();
- /// assert_eq!(v, ["B", "A"]);
- ///
- /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect();
- /// assert_eq!(v, ["", "B", "", "A"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplit_terminator(self, pat)
- }
-
- /// An iterator over substrings of the given string slice, separated by a
- /// pattern, restricted to returning at most `n` items.
- ///
- /// If `n` substrings are returned, the last substring (the `n`th substring)
- /// will contain the remainder of the string.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines the
- /// split.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will not be double ended, because it is
- /// not efficient to support.
- ///
- /// If the pattern allows a reverse search, the [`rsplitn`] method can be
- /// used.
- ///
- /// [`rsplitn`]: #method.rsplitn
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect();
- /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect();
- /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
- ///
- /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
- /// assert_eq!(v, ["abcXdef"]);
- ///
- /// let v: Vec<&str> = "".splitn(1, 'X').collect();
- /// assert_eq!(v, [""]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["abc", "defXghi"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
- core_str::StrExt::splitn(self, n, pat)
- }
-
- /// An iterator over substrings of this string slice, separated by a
- /// pattern, starting from the end of the string, restricted to returning
- /// at most `n` items.
- ///
- /// If `n` substrings are returned, the last substring (the `n`th substring)
- /// will contain the remainder of the string.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that
- /// determines the split.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will not be double ended, because it is not
- /// efficient to support.
- ///
- /// For splitting from the front, the [`splitn`] method can be used.
- ///
- /// [`splitn`]: #method.splitn
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
- /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
- ///
- /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect();
- /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
- ///
- /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
- /// assert_eq!(v, ["leopard", "lion::tiger"]);
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect();
- /// assert_eq!(v, ["ghi", "abc1def"]);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rsplitn(self, n, pat)
- }
-
- /// An iterator over the disjoint matches of a pattern within the given string
- /// slice.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that
- /// determines if a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- /// [`char`]: primitive.char.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rmatches`] method can be used.
- ///
- /// [`rmatches`]: #method.rmatches
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();
- /// assert_eq!(v, ["abc", "abc", "abc"]);
- ///
- /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect();
- /// assert_eq!(v, ["1", "2", "3"]);
- /// ```
- #[stable(feature = "str_matches", since = "1.2.0")]
- #[inline]
- pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
- core_str::StrExt::matches(self, pat)
- }
-
- /// An iterator over the disjoint matches of a pattern within this string slice,
- /// yielded in reverse order.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a reverse
- /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
- /// search yields the same elements.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// For iterating from the front, the [`matches`] method can be used.
- ///
- /// [`matches`]: #method.matches
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect();
- /// assert_eq!(v, ["abc", "abc", "abc"]);
- ///
- /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect();
- /// assert_eq!(v, ["3", "2", "1"]);
- /// ```
- #[stable(feature = "str_matches", since = "1.2.0")]
- #[inline]
- pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rmatches(self, pat)
- }
-
- /// An iterator over the disjoint matches of a pattern within this string
- /// slice as well as the index that the match starts at.
- ///
- /// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the first match are returned.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines
- /// if a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
- /// allows a reverse search and forward/reverse search yields the same
- /// elements. This is true for, eg, [`char`] but not for `&str`.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// If the pattern allows a reverse search but its results might differ
- /// from a forward search, the [`rmatch_indices`] method can be used.
- ///
- /// [`rmatch_indices`]: #method.rmatch_indices
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
- /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
- ///
- /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
- /// assert_eq!(v, [(1, "abc"), (4, "abc")]);
- ///
- /// let v: Vec<_> = "ababa".match_indices("aba").collect();
- /// assert_eq!(v, [(0, "aba")]); // only the first `aba`
- /// ```
- #[stable(feature = "str_match_indices", since = "1.5.0")]
- #[inline]
- pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
- core_str::StrExt::match_indices(self, pat)
- }
+ type Output = String;
- /// An iterator over the disjoint matches of a pattern within `self`,
- /// yielded in reverse order along with the index of the match.
- ///
- /// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the last match are returned.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if a
- /// character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Iterator behavior
- ///
- /// The returned iterator requires that the pattern supports a reverse
- /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
- /// search yields the same elements.
- ///
- /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
- ///
- /// For iterating from the front, the [`match_indices`] method can be used.
- ///
- /// [`match_indices`]: #method.match_indices
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]);
- ///
- /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(4, "abc"), (1, "abc")]);
- ///
- /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect();
- /// assert_eq!(v, [(2, "aba")]); // only the last `aba`
- /// ```
- #[stable(feature = "str_match_indices", since = "1.5.0")]
- #[inline]
- pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::rmatch_indices(self, pat)
- }
+ fn concat(&self) -> String {
+ if self.is_empty() {
+ return String::new();
+ }
- /// Returns a string slice with leading and trailing whitespace removed.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = " Hello\tworld\t";
- ///
- /// assert_eq!("Hello\tworld", s.trim());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim(&self) -> &str {
- StrExt::trim(self)
- }
+ // `len` calculation may overflow but push_str will check boundaries
+ let len = self.iter().map(|s| s.borrow().len()).sum();
+ let mut result = String::with_capacity(len);
- /// Returns a string slice with leading whitespace removed.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Left' in this context means the first
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _right_ side, not the left.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = " Hello\tworld\t";
- ///
- /// assert_eq!("Hello\tworld\t", s.trim_left());
- /// ```
- ///
- /// Directionality:
- ///
- /// ```
- /// let s = " English";
- /// assert!(Some('E') == s.trim_left().chars().next());
- ///
- /// let s = " עברית";
- /// assert!(Some('ע') == s.trim_left().chars().next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_left(&self) -> &str {
- StrExt::trim_left(self)
+ for s in self {
+ result.push_str(s.borrow())
+ }
+
+ result
}
- /// Returns a string slice with trailing whitespace removed.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived
- /// Core Property `White_Space`.
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Right' in this context means the last
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _left_ side, not the right.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// let s = " Hello\tworld\t";
- ///
- /// assert_eq!(" Hello\tworld", s.trim_right());
- /// ```
- ///
- /// Directionality:
- ///
- /// ```
- /// let s = "English ";
- /// assert!(Some('h') == s.trim_right().chars().rev().next());
- ///
- /// let s = "עברית ";
- /// assert!(Some('ת') == s.trim_right().chars().rev().next());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_right(&self) -> &str {
- StrExt::trim_right(self)
+ fn join(&self, sep: &str) -> String {
+ if self.is_empty() {
+ return String::new();
+ }
+
+ // concat is faster
+ if sep.is_empty() {
+ return self.concat();
+ }
+
+ // this is wrong without the guarantee that `self` is non-empty
+ // `len` calculation may overflow but push_str but will check boundaries
+ let len = sep.len() * (self.len() - 1) +
+ self.iter().map(|s| s.borrow().len()).sum::<usize>();
+ let mut result = String::with_capacity(len);
+ let mut first = true;
+
+ for s in self {
+ if first {
+ first = false;
+ } else {
+ result.push_str(sep);
+ }
+ result.push_str(s.borrow());
+ }
+ result
}
- /// Returns a string slice with all prefixes and suffixes that match a
- /// pattern repeatedly removed.
- ///
- /// The pattern can be a [`char`] or a closure that determines if a
- /// character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
- /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar");
- ///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
- where P::Searcher: DoubleEndedSearcher<'a>
- {
- core_str::StrExt::trim_matches(self, pat)
+ fn connect(&self, sep: &str) -> String {
+ self.join(sep)
}
+}
- /// Returns a string slice with all prefixes that match a pattern
- /// repeatedly removed.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that determines if
- /// a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Left' in this context means the first
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _right_ side, not the left.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
- /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
- ///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
- core_str::StrExt::trim_left_matches(self, pat)
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Borrow<str> for String {
+ #[inline]
+ fn borrow(&self) -> &str {
+ &self[..]
}
+}
- /// Returns a string slice with all suffixes that match a pattern
- /// repeatedly removed.
- ///
- /// The pattern can be a `&str`, [`char`], or a closure that
- /// determines if a character matches.
- ///
- /// [`char`]: primitive.char.html
- ///
- /// # Text directionality
- ///
- /// A string is a sequence of bytes. 'Right' in this context means the last
- /// position of that byte string; for a language like Arabic or Hebrew
- /// which are 'right to left' rather than 'left to right', this will be
- /// the _left_ side, not the right.
- ///
- /// # Examples
- ///
- /// Simple patterns:
- ///
- /// ```
- /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
- /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
- ///
- /// let x: &[_] = &['1', '2'];
- /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
- /// ```
- ///
- /// A more complex pattern, using a closure:
- ///
- /// ```
- /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
- where P::Searcher: ReverseSearcher<'a>
- {
- core_str::StrExt::trim_right_matches(self, pat)
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToOwned for str {
+ type Owned = String;
+ fn to_owned(&self) -> String {
+ unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
}
- /// Parses this string slice into another type.
- ///
- /// Because `parse` is so general, it can cause problems with type
- /// inference. As such, `parse` is one of the few times you'll see
- /// the syntax affectionately known as the 'turbofish': `::<>`. This
- /// helps the inference algorithm understand specifically which type
- /// you're trying to parse into.
- ///
- /// `parse` can parse any type that implements the [`FromStr`] trait.
- ///
- /// [`FromStr`]: str/trait.FromStr.html
- ///
- /// # Errors
- ///
- /// Will return [`Err`] if it's not possible to parse this string slice into
- /// the desired type.
- ///
- /// [`Err`]: str/trait.FromStr.html#associatedtype.Err
- ///
- /// # Examples
- ///
- /// Basic usage
- ///
- /// ```
- /// let four: u32 = "4".parse().unwrap();
- ///
- /// assert_eq!(4, four);
- /// ```
- ///
- /// Using the 'turbofish' instead of annotating `four`:
- ///
- /// ```
- /// let four = "4".parse::<u32>();
- ///
- /// assert_eq!(Ok(4), four);
- /// ```
- ///
- /// Failing to parse:
- ///
- /// ```
- /// let nope = "j".parse::<u32>();
- ///
- /// assert!(nope.is_err());
- /// ```
- #[inline]
- #[stable(feature = "rust1", since = "1.0.0")]
- pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
- core_str::StrExt::parse(self)
+ fn clone_into(&self, target: &mut String) {
+ let mut b = mem::replace(target, String::new()).into_bytes();
+ self.as_bytes().clone_into(&mut b);
+ *target = unsafe { String::from_utf8_unchecked(b) }
}
+}
+
+/// Methods for string slices.
+#[cfg_attr(stage0, lang = "str")]
+#[cfg_attr(not(stage0), lang = "str_alloc")]
+#[cfg(not(test))]
+impl str {
+ #[cfg(stage0)]
+ str_core_methods!();
/// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating.
///
/// assert_eq!(*boxed_bytes, *s.as_bytes());
/// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
+ #[inline]
pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
self.into()
}
/// assert_eq!(boxed_str.into_string(), string);
/// ```
#[stable(feature = "box_str", since = "1.4.0")]
+ #[inline]
pub fn into_string(self: Box<str>) -> String {
let slice = Box::<[u8]>::from(self);
unsafe { String::from_utf8_unchecked(slice.into_vec()) }
unsafe { String::from_utf8_unchecked(buf) }
}
- /// Returns true if this `str` is entirely whitespace, and false otherwise.
- ///
- /// 'Whitespace' is defined according to the terms of the Unicode Derived Core
- /// Property `White_Space`.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// assert!(" \t ".is_whitespace());
- ///
- /// // a non-breaking space
- /// assert!("\u{A0}".is_whitespace());
- ///
- /// assert!(!" 越".is_whitespace());
- /// ```
- #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
- #[inline]
- pub fn is_whitespace(&self) -> bool {
- StrExt::is_whitespace(self)
- }
-
- /// Returns true if this `str` is entirely alphanumeric, and false otherwise.
- ///
- /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories
- /// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// assert!("٣7৬Kو藏".is_alphanumeric());
- /// assert!(!"¾①".is_alphanumeric());
- /// ```
- #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
- #[inline]
- pub fn is_alphanumeric(&self) -> bool {
- StrExt::is_alphanumeric(self)
- }
-
- /// Checks if all characters in this string are within the ASCII range.
- ///
- /// # Examples
- ///
- /// ```
- /// let ascii = "hello!\n";
- /// let non_ascii = "Grüße, Jürgen ❤";
- ///
- /// assert!(ascii.is_ascii());
- /// assert!(!non_ascii.is_ascii());
- /// ```
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn is_ascii(&self) -> bool {
- // We can treat each byte as character here: all multibyte characters
- // start with a byte that is not in the ascii range, so we will stop
- // there already.
- self.bytes().all(|b| b.is_ascii())
- }
-
/// Returns a copy of this string where each character is mapped to its
/// ASCII upper case equivalent.
///
// make_ascii_lowercase() preserves the UTF-8 invariant.
unsafe { String::from_utf8_unchecked(bytes) }
}
-
- /// Checks that two strings are an ASCII case-insensitive match.
- ///
- /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
- /// but without allocating and copying temporaries.
- ///
- /// # Examples
- ///
- /// ```
- /// assert!("Ferris".eq_ignore_ascii_case("FERRIS"));
- /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS"));
- /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
- /// ```
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
- self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
- }
-
- /// Converts this string to its ASCII upper case equivalent in-place.
- ///
- /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new uppercased value without modifying the existing one, use
- /// [`to_ascii_uppercase`].
- ///
- /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- pub fn make_ascii_uppercase(&mut self) {
- let me = unsafe { self.as_bytes_mut() };
- me.make_ascii_uppercase()
- }
-
- /// Converts this string to its ASCII lower case equivalent in-place.
- ///
- /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new lowercased value without modifying the existing one, use
- /// [`to_ascii_lowercase`].
- ///
- /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- pub fn make_ascii_lowercase(&mut self) {
- let me = unsafe { self.as_bytes_mut() };
- me.make_ascii_lowercase()
- }
}
/// Converts a boxed slice of bytes to a boxed string slice without checking
/// assert_eq!("☺", &*smile);
/// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
+#[inline]
pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box<str> {
Box::from_raw(Box::into_raw(v) as *mut str)
}
/// and replaces it with the given string.
/// The given string doesn't need to be the same length as the range.
///
- /// Note: Unlike [`Vec::splice`], the replacement happens eagerly, and this
- /// method does not return the removed chars.
- ///
/// # Panics
///
/// Panics if the starting point or end point do not lie on a [`char`]
/// let b = s.into_boxed_str();
/// ```
#[stable(feature = "box_str", since = "1.4.0")]
+ #[inline]
pub fn into_boxed_str(self) -> Box<str> {
let slice = self.vec.into_boxed_slice();
unsafe { from_boxed_utf8_unchecked(slice) }
}
}
+#[test]
+fn test_str_slice_rangetoinclusive_ok() {
+ let s = "abcαβγ";
+ assert_eq!(&s[..=2], "abc");
+ assert_eq!(&s[..=4], "abcα");
+}
+
+#[test]
+#[should_panic]
+fn test_str_slice_rangetoinclusive_notok() {
+ let s = "abcαβγ";
+ &s[..=3];
+}
+
+#[test]
+fn test_str_slicemut_rangetoinclusive_ok() {
+ let mut s = "abcαβγ".to_owned();
+ let s: &mut str = &mut s;
+ assert_eq!(&mut s[..=2], "abc");
+ assert_eq!(&mut s[..=4], "abcα");
+}
+
+#[test]
+#[should_panic]
+fn test_str_slicemut_rangetoinclusive_notok() {
+ let mut s = "abcαβγ".to_owned();
+ let s: &mut str = &mut s;
+ &mut s[..=3];
+}
+
#[test]
fn test_is_char_boundary() {
let s = "ศไทย中华Việt Nam β-release 🐱123";
use core::marker::PhantomData;
use core::mem;
#[cfg(not(test))]
+#[cfg(stage0)]
use core::num::Float;
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{Index, IndexMut, RangeBounds};
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn shrink_to_fit(&mut self) {
- self.buf.shrink_to_fit(self.len);
+ if self.capacity() != self.len {
+ self.buf.shrink_to_fit(self.len);
+ }
}
/// Shrinks the capacity of the vector with a lower bound.
impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
// exhaust self first
- while let Some(_) = self.next() {}
+ self.for_each(drop);
if self.tail_len > 0 {
unsafe {
#[stable(feature = "vec_splice", since = "1.21.0")]
impl<'a, I: Iterator> Drop for Splice<'a, I> {
fn drop(&mut self) {
- // exhaust drain first
- while let Some(_) = self.drain.next() {}
-
+ self.drain.by_ref().for_each(drop);
unsafe {
if self.drain.tail_len == 0 {
where F: FnMut(&mut T) -> bool,
{
fn drop(&mut self) {
- for _ in self.by_ref() { }
-
+ self.for_each(drop);
unsafe {
self.vec.set_len(self.old_len - self.del);
}
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
- for _ in self.by_ref() {}
+ self.for_each(drop);
let source_deque = unsafe { self.deque.as_mut() };
doc = false
[dependencies]
-alloc_system = { path = "../liballoc_system" }
core = { path = "../libcore" }
libc = { path = "../rustc/libc_shim" }
compiler_builtins = { path = "../rustc/compiler_builtins_shim" }
reason = "this library is unlikely to be stabilized in its current \
form or name",
issue = "27783")]
-#![feature(alloc_system)]
+#![feature(core_intrinsics)]
#![feature(libc)]
#![feature(linkage)]
#![feature(staged_api)]
#![cfg_attr(not(dummy_jemalloc), feature(allocator_api))]
#![rustc_alloc_kind = "exe"]
-extern crate alloc_system;
extern crate libc;
#[cfg(not(dummy_jemalloc))]
pub use contents::*;
#[cfg(not(dummy_jemalloc))]
mod contents {
- use core::alloc::GlobalAlloc;
- use alloc_system::System;
use libc::{c_int, c_void, size_t};
// Note that the symbols here are prefixed by default on macOS and Windows (we
ptr
}
+ #[cfg(stage0)]
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rde_oom() -> ! {
- System.oom()
+ ::core::intrinsics::abort();
}
#[no_mangle]
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
}
-
- #[inline]
- fn oom(&mut self) -> ! {
- ::oom()
- }
}
#[cfg(stage0)]
new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
}
-
- #[inline]
- fn oom(&mut self) -> ! {
- ::oom()
- }
}
#[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
}
}
}
-
-#[inline]
-fn oom() -> ! {
- write_to_stderr("fatal runtime error: memory allocation failed");
- unsafe {
- ::core::intrinsics::abort();
- }
-}
-
-#[cfg(any(unix, target_os = "redox"))]
-#[inline]
-fn write_to_stderr(s: &str) {
- extern crate libc;
-
- unsafe {
- libc::write(libc::STDERR_FILENO,
- s.as_ptr() as *const libc::c_void,
- s.len());
- }
-}
-
-#[cfg(windows)]
-#[inline]
-fn write_to_stderr(s: &str) {
- use core::ptr;
-
- type LPVOID = *mut u8;
- type HANDLE = LPVOID;
- type DWORD = u32;
- type BOOL = i32;
- type LPDWORD = *mut DWORD;
- type LPOVERLAPPED = *mut u8;
-
- const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
-
- extern "system" {
- fn WriteFile(hFile: HANDLE,
- lpBuffer: LPVOID,
- nNumberOfBytesToWrite: DWORD,
- lpNumberOfBytesWritten: LPDWORD,
- lpOverlapped: LPOVERLAPPED)
- -> BOOL;
- fn GetStdHandle(which: DWORD) -> HANDLE;
- }
-
- unsafe {
- // WriteFile silently fails if it is passed an invalid
- // handle, so there is no need to check the result of
- // GetStdHandle.
- WriteFile(GetStdHandle(STD_ERROR_HANDLE),
- s.as_ptr() as LPVOID,
- s.len() as DWORD,
- ptr::null_mut(),
- ptr::null_mut());
- }
-}
-
-#[cfg(not(any(windows, unix, target_os = "redox")))]
-#[inline]
-fn write_to_stderr(_: &str) {}
name = "arena"
path = "lib.rs"
crate-type = ["dylib"]
+
+[dependencies]
+rustc_data_structures = { path = "../librustc_data_structures" }
\ No newline at end of file
#![allow(deprecated)]
extern crate alloc;
+extern crate rustc_data_structures;
+
+use rustc_data_structures::sync::MTLock;
use std::cell::{Cell, RefCell};
use std::cmp;
chunks: RefCell<Vec<TypedArenaChunk<u8>>>,
}
+unsafe impl Send for DroplessArena {}
+
impl DroplessArena {
pub fn new() -> DroplessArena {
DroplessArena {
}
}
+pub struct SyncTypedArena<T> {
+ lock: MTLock<TypedArena<T>>,
+}
+
+impl<T> SyncTypedArena<T> {
+ #[inline(always)]
+ pub fn new() -> SyncTypedArena<T> {
+ SyncTypedArena {
+ lock: MTLock::new(TypedArena::new())
+ }
+ }
+
+ #[inline(always)]
+ pub fn alloc(&self, object: T) -> &mut T {
+ // Extend the lifetime of the result since it's limited to the lock guard
+ unsafe { &mut *(self.lock.lock().alloc(object) as *mut T) }
+ }
+
+ #[inline(always)]
+ pub fn alloc_slice(&self, slice: &[T]) -> &mut [T]
+ where
+ T: Copy,
+ {
+ // Extend the lifetime of the result since it's limited to the lock guard
+ unsafe { &mut *(self.lock.lock().alloc_slice(slice) as *mut [T]) }
+ }
+
+ #[inline(always)]
+ pub fn clear(&mut self) {
+ self.lock.get_mut().clear();
+ }
+}
+
+pub struct SyncDroplessArena {
+ lock: MTLock<DroplessArena>,
+}
+
+impl SyncDroplessArena {
+ #[inline(always)]
+ pub fn new() -> SyncDroplessArena {
+ SyncDroplessArena {
+ lock: MTLock::new(DroplessArena::new())
+ }
+ }
+
+ #[inline(always)]
+ pub fn in_arena<T: ?Sized>(&self, ptr: *const T) -> bool {
+ self.lock.lock().in_arena(ptr)
+ }
+
+ #[inline(always)]
+ pub fn alloc<T>(&self, object: T) -> &mut T {
+ // Extend the lifetime of the result since it's limited to the lock guard
+ unsafe { &mut *(self.lock.lock().alloc(object) as *mut T) }
+ }
+
+ #[inline(always)]
+ pub fn alloc_slice<T>(&self, slice: &[T]) -> &mut [T]
+ where
+ T: Copy,
+ {
+ // Extend the lifetime of the result since it's limited to the lock guard
+ unsafe { &mut *(self.lock.lock().alloc_slice(slice) as *mut [T]) }
+ }
+}
+
#[cfg(test)]
mod tests {
extern crate test;
/// requests have positive size. A caller to the `Alloc::alloc`
/// method must either ensure that conditions like this are met, or
/// use specific allocators with looser requirements.)
-#[derive(Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Layout {
// size of the requested block of memory, measured in bytes.
size: usize,
}
new_ptr
}
-
- /// Aborts the thread or process, optionally performing
- /// cleanup or logging diagnostic information before panicking or
- /// aborting.
- ///
- /// `oom` is meant to be used by clients unable to cope with an
- /// unsatisfied allocation request, and wish to abandon
- /// computation rather than attempt to recover locally.
- fn oom(&self) -> ! {
- unsafe { ::intrinsics::abort() }
- }
}
/// An implementation of `Alloc` can allocate, reallocate, and
/// to allocate that block of memory.
unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout);
- /// Allocator-specific method for signaling an out-of-memory
- /// condition.
- ///
- /// `oom` aborts the thread or process, optionally performing
- /// cleanup or logging diagnostic information before panicking or
- /// aborting.
- ///
- /// `oom` is meant to be used by clients unable to cope with an
- /// unsatisfied allocation request, and wish to abandon
- /// computation rather than attempt to recover locally.
- ///
- /// Implementations of the `oom` method are discouraged from
- /// infinitely regressing in nested calls to `oom`. In
- /// practice this means implementors should eschew allocating,
- /// especially from `self` (directly or indirectly).
- ///
- /// Implementations of the allocation and reallocation methods
- /// (e.g. `alloc`, `alloc_one`, `realloc`) are discouraged from
- /// panicking (or aborting) in the event of memory exhaustion;
- /// instead they should return an appropriate error from the
- /// invoked method, and let the client decide whether to invoke
- /// this `oom` method in response.
- fn oom(&mut self) -> ! {
- unsafe { ::intrinsics::abort() }
- }
-
// == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS ==
// usable_size
}
/// The error type returned when a conversion from a slice to an array fails.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromSliceError(());
}
}
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl<'a, T> TryFrom<&'a [T]> for &'a [T; $N] {
type Error = TryFromSliceError;
}
}
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl<'a, T> TryFrom<&'a mut [T]> for &'a mut [T; $N] {
type Error = TryFromSliceError;
pub fn get(&self) -> T {
unsafe{ *self.value.get() }
}
+
+ /// Updates the contained value using a function and returns the new value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(cell_update)]
+ ///
+ /// use std::cell::Cell;
+ ///
+ /// let c = Cell::new(5);
+ /// let new = c.update(|x| x + 1);
+ ///
+ /// assert_eq!(new, 6);
+ /// assert_eq!(c.get(), 6);
+ /// ```
+ #[inline]
+ #[unstable(feature = "cell_update", issue = "50186")]
+ pub fn update<F>(&self, f: F) -> T
+ where
+ F: FnOnce(T) -> T,
+ {
+ let old = self.get();
+ let new = f(old);
+ self.set(new);
+ new
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<u32> for char {
type Error = CharTryFromError;
}
/// The error type returned when a conversion from u32 to char fails.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CharTryFromError(());
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl fmt::Display for CharTryFromError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
"converted integer out of range for `char`".fmt(f)
pub use self::convert::from_u32_unchecked;
#[stable(feature = "char_from_str", since = "1.20.0")]
pub use self::convert::ParseCharError;
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
pub use self::convert::CharTryFromError;
#[stable(feature = "decode_utf16", since = "1.9.0")]
pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error};
bool char
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Clone for ! {
#[inline]
fn clone(&self) -> Self {
ord_impl! { char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl PartialEq for ! {
fn eq(&self, _: &!) -> bool {
*self
}
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Eq for ! {}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl PartialOrd for ! {
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
}
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Ord for ! {
fn cmp(&self, _: &!) -> Ordering {
*self
///
/// [`TryFrom`]: trait.TryFrom.html
/// [`Into`]: trait.Into.html
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
pub trait TryInto<T>: Sized {
/// The type returned in the event of a conversion error.
- #[stable(feature = "try_from", since = "1.26.0")]
type Error;
/// Performs the conversion.
- #[stable(feature = "try_from", since = "1.26.0")]
fn try_into(self) -> Result<T, Self::Error>;
}
/// Attempt to construct `Self` via a conversion.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
pub trait TryFrom<T>: Sized {
/// The type returned in the event of a conversion error.
- #[stable(feature = "try_from", since = "1.26.0")]
type Error;
/// Performs the conversion.
- #[stable(feature = "try_from", since = "1.26.0")]
fn try_from(value: T) -> Result<Self, Self::Error>;
}
// TryFrom implies TryInto
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryInto<U> for T where U: TryFrom<T>
{
type Error = U::Error;
// Infallible conversions are semantically equivalent to fallible conversions
// with an uninhabited error type.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl<T, U> TryFrom<U> for T where T: From<U> {
type Error = !;
// truncation. However other flags like `fill`, `width` and `align`
// must act as always.
if let Some((i, _)) = s.char_indices().skip(max).next() {
- &s[..i]
+ // LLVM here can't prove that `..i` won't panic `&s[..i]`, but
+ // we know that it can't panic. Use `get` + `unwrap_or` to avoid
+ // `unsafe` and otherwise don't emit any panic-related code
+ // here.
+ s.get(..i).unwrap_or(&s)
} else {
&s
}
fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
-#[stable(feature = "never_type", since = "1.26.0")]
+#[unstable(feature = "never_type", issue = "35121")]
impl Debug for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
}
}
-#[stable(feature = "never_type", since = "1.26.0")]
+#[unstable(feature = "never_type", issue = "35121")]
impl Display for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
}
}
+#[cfg(stage0)]
+macro_rules! public_in_stage0 {
+ ( { $(#[$attr:meta])* } $($Item: tt)*) => {
+ $(#[$attr])* pub $($Item)*
+ }
+}
+
+#[cfg(not(stage0))]
+macro_rules! public_in_stage0 {
+ ( { $(#[$attr:meta])* } $($Item: tt)*) => {
+ $(#[$attr])* pub(crate) $($Item)*
+ }
+}
/// an extra layer of indirection. `flat_map()` will remove this extra layer
/// on its own.
///
- /// You can think of [`flat_map(f)`][flat_map] as the semantic equivalent
+ /// You can think of `flat_map(f)` as the semantic equivalent
/// of [`map`]ping, and then [`flatten`]ing as in `map(f).flatten()`.
///
/// Another way of thinking about `flat_map()`: [`map`]'s closure returns
#![feature(asm)]
#![feature(associated_type_defaults)]
#![feature(attr_literals)]
-#![feature(cfg_target_feature)]
#![feature(cfg_target_has_atomic)]
#![feature(concat_idents)]
#![feature(const_fn)]
+#![feature(core_float)]
#![feature(custom_attribute)]
#![feature(doc_cfg)]
#![feature(doc_spotlight)]
#![feature(iterator_repeat_with)]
#![feature(lang_items)]
#![feature(link_llvm_intrinsics)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(macro_at_most_once_rep)]
#![feature(no_core)]
#![feature(rustc_attrs)]
#![feature(rustc_const_unstable)]
#![feature(simd_ffi)]
+#![feature(core_slice_ext)]
+#![feature(core_str_ext)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(stmt_expr_attributes)]
-#![feature(target_feature)]
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
+#![feature(doc_alias)]
+
+#![cfg_attr(not(stage0), feature(mmx_target_feature))]
+#![cfg_attr(not(stage0), feature(tbm_target_feature))]
+#![cfg_attr(not(stage0), feature(sse4a_target_feature))]
+#![cfg_attr(not(stage0), feature(arm_target_feature))]
+#![cfg_attr(not(stage0), feature(powerpc_target_feature))]
+#![cfg_attr(not(stage0), feature(mips_target_feature))]
+#![cfg_attr(not(stage0), feature(aarch64_target_feature))]
+
+#![cfg_attr(stage0, feature(target_feature))]
+#![cfg_attr(stage0, feature(cfg_target_feature))]
#[prelude_import]
#[allow(unused)]
// things like SIMD and such. Note that the actual source for all this lies in a
// different repository, rust-lang-nursery/stdsimd. That's why the setup here is
// a bit wonky.
+#[allow(unused_macros)]
+macro_rules! test_v16 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v32 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v64 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v128 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v256 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! test_v512 { ($item:item) => {}; }
+#[allow(unused_macros)]
+macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*);)* } }
#[path = "../stdsimd/coresimd/mod.rs"]
-#[allow(missing_docs, missing_debug_implementations, dead_code)]
+#[allow(missing_docs, missing_debug_implementations, dead_code, unused_imports)]
#[unstable(feature = "stdsimd", issue = "48556")]
#[cfg(not(stage0))] // allow changes to how stdsimd works in stage0
mod coresimd;
#[unstable(feature = "stdsimd", issue = "48556")]
#[cfg(not(stage0))]
pub use coresimd::simd;
-#[unstable(feature = "stdsimd", issue = "48556")]
+#[stable(feature = "simd_arch", since = "1.27.0")]
#[cfg(not(stage0))]
pub use coresimd::arch;
/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "?")]
macro_rules! try {
($expr:expr) => (match $expr {
$crate::result::Result::Ok(val) => val,
bool char
}
- #[stable(feature = "never_type", since = "1.26.0")]
+ #[unstable(feature = "never_type", issue = "35121")]
impl Copy for ! {}
#[stable(feature = "rust1", since = "1.0.0")]
#![stable(feature = "rust1", since = "1.0.0")]
-use intrinsics;
use mem;
use num::Float;
+#[cfg(not(stage0))] use num::FpCategory;
use num::FpCategory as Fp;
/// The radix or base of the internal representation of `f32`.
}
}
- /// Computes the absolute value of `self`. Returns `Float::nan()` if the
- /// number is `Float::nan()`.
- #[inline]
- fn abs(self) -> f32 {
- unsafe { intrinsics::fabsf32(self) }
- }
-
- /// Returns a number that represents the sign of `self`.
- ///
- /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
- /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
- /// - `Float::nan()` if the number is `Float::nan()`
- #[inline]
- fn signum(self) -> f32 {
- if self.is_nan() {
- NAN
- } else {
- unsafe { intrinsics::copysignf32(1.0, self) }
- }
- }
-
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
/// positive sign bit and positive infinity.
#[inline]
1.0 / self
}
- #[inline]
- fn powi(self, n: i32) -> f32 {
- unsafe { intrinsics::powif32(self, n) }
- }
-
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f32 {
unsafe { mem::transmute(v) }
}
}
+
+// FIXME: remove (inline) this macro and the Float trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_float", issue = "32110")]
+macro_rules! f32_core_methods { () => {
+ /// Returns `true` if this value is `NaN` and false otherwise.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let nan = f32::NAN;
+ /// let f = 7.0_f32;
+ ///
+ /// assert!(nan.is_nan());
+ /// assert!(!f.is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_nan(self) -> bool { Float::is_nan(self) }
+
+ /// Returns `true` if this value is positive infinity or negative infinity and
+ /// false otherwise.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 7.0f32;
+ /// let inf = f32::INFINITY;
+ /// let neg_inf = f32::NEG_INFINITY;
+ /// let nan = f32::NAN;
+ ///
+ /// assert!(!f.is_infinite());
+ /// assert!(!nan.is_infinite());
+ ///
+ /// assert!(inf.is_infinite());
+ /// assert!(neg_inf.is_infinite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_infinite(self) -> bool { Float::is_infinite(self) }
+
+ /// Returns `true` if this number is neither infinite nor `NaN`.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let f = 7.0f32;
+ /// let inf = f32::INFINITY;
+ /// let neg_inf = f32::NEG_INFINITY;
+ /// let nan = f32::NAN;
+ ///
+ /// assert!(f.is_finite());
+ ///
+ /// assert!(!nan.is_finite());
+ /// assert!(!inf.is_finite());
+ /// assert!(!neg_inf.is_finite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_finite(self) -> bool { Float::is_finite(self) }
+
+ /// Returns `true` if the number is neither zero, infinite,
+ /// [subnormal][subnormal], or `NaN`.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
+ /// let max = f32::MAX;
+ /// let lower_than_min = 1.0e-40_f32;
+ /// let zero = 0.0_f32;
+ ///
+ /// assert!(min.is_normal());
+ /// assert!(max.is_normal());
+ ///
+ /// assert!(!zero.is_normal());
+ /// assert!(!f32::NAN.is_normal());
+ /// assert!(!f32::INFINITY.is_normal());
+ /// // Values between `0` and `min` are Subnormal.
+ /// assert!(!lower_than_min.is_normal());
+ /// ```
+ /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_normal(self) -> bool { Float::is_normal(self) }
+
+ /// Returns the floating point category of the number. If only one property
+ /// is going to be tested, it is generally faster to use the specific
+ /// predicate instead.
+ ///
+ /// ```
+ /// use std::num::FpCategory;
+ /// use std::f32;
+ ///
+ /// let num = 12.4_f32;
+ /// let inf = f32::INFINITY;
+ ///
+ /// assert_eq!(num.classify(), FpCategory::Normal);
+ /// assert_eq!(inf.classify(), FpCategory::Infinite);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn classify(self) -> FpCategory { Float::classify(self) }
+
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
+ ///
+ /// ```
+ /// let f = 7.0_f32;
+ /// let g = -7.0_f32;
+ ///
+ /// assert!(f.is_sign_positive());
+ /// assert!(!g.is_sign_positive());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) }
+
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
+ ///
+ /// ```
+ /// let f = 7.0f32;
+ /// let g = -7.0f32;
+ ///
+ /// assert!(!f.is_sign_negative());
+ /// assert!(g.is_sign_negative());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) }
+
+ /// Takes the reciprocal (inverse) of a number, `1/x`.
+ ///
+ /// ```
+ /// use std::f32;
+ ///
+ /// let x = 2.0_f32;
+ /// let abs_difference = (x.recip() - (1.0/x)).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn recip(self) -> f32 { Float::recip(self) }
+
+ /// Converts radians to degrees.
+ ///
+ /// ```
+ /// use std::f32::{self, consts};
+ ///
+ /// let angle = consts::PI;
+ ///
+ /// let abs_difference = (angle.to_degrees() - 180.0).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
+ #[inline]
+ pub fn to_degrees(self) -> f32 { Float::to_degrees(self) }
+
+ /// Converts degrees to radians.
+ ///
+ /// ```
+ /// use std::f32::{self, consts};
+ ///
+ /// let angle = 180.0f32;
+ ///
+ /// let abs_difference = (angle.to_radians() - consts::PI).abs();
+ ///
+ /// assert!(abs_difference <= f32::EPSILON);
+ /// ```
+ #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
+ #[inline]
+ pub fn to_radians(self) -> f32 { Float::to_radians(self) }
+
+ /// Returns the maximum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0f32;
+ /// let y = 2.0f32;
+ ///
+ /// assert_eq!(x.max(y), y);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn max(self, other: f32) -> f32 {
+ Float::max(self, other)
+ }
+
+ /// Returns the minimum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0f32;
+ /// let y = 2.0f32;
+ ///
+ /// assert_eq!(x.min(y), x);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn min(self, other: f32) -> f32 {
+ Float::min(self, other)
+ }
+
+ /// Raw transmutation to `u32`.
+ ///
+ /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
+ ///
+ /// See `from_bits` for some discussion of the portability of this operation
+ /// (there are almost no issues).
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting!
+ /// assert_eq!((12.5f32).to_bits(), 0x41480000);
+ ///
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn to_bits(self) -> u32 {
+ Float::to_bits(self)
+ }
+
+ /// Raw transmutation from `u32`.
+ ///
+ /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms.
+ /// It turns out this is incredibly portable, for two reasons:
+ ///
+ /// * Floats and Ints have the same endianness on all supported platforms.
+ /// * IEEE-754 very precisely specifies the bit layout of floats.
+ ///
+ /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+ /// (notably x86 and ARM) picked the interpretation that was ultimately
+ /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+ /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+ ///
+ /// Rather than trying to preserve signaling-ness cross-platform, this
+ /// implementation favours preserving the exact bits. This means that
+ /// any payloads encoded in NaNs will be preserved even if the result of
+ /// this method is sent over the network from an x86 machine to a MIPS one.
+ ///
+ /// If the results of this method are only manipulated by the same
+ /// architecture that produced them, then there is no portability concern.
+ ///
+ /// If the input isn't NaN, then there is no portability concern.
+ ///
+ /// If you don't care about signalingness (very likely), then there is no
+ /// portability concern.
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f32;
+ /// let v = f32::from_bits(0x41480000);
+ /// let difference = (v - 12.5).abs();
+ /// assert!(difference <= 1e-5);
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn from_bits(v: u32) -> Self {
+ Float::from_bits(v)
+ }
+}}
+
+#[lang = "f32"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl f32 {
+ f32_core_methods!();
+}
#![stable(feature = "rust1", since = "1.0.0")]
-use intrinsics;
use mem;
-use num::FpCategory as Fp;
use num::Float;
+#[cfg(not(stage0))] use num::FpCategory;
+use num::FpCategory as Fp;
/// The radix or base of the internal representation of `f64`.
#[stable(feature = "rust1", since = "1.0.0")]
}
}
- /// Computes the absolute value of `self`. Returns `Float::nan()` if the
- /// number is `Float::nan()`.
- #[inline]
- fn abs(self) -> f64 {
- unsafe { intrinsics::fabsf64(self) }
- }
-
- /// Returns a number that represents the sign of `self`.
- ///
- /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
- /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
- /// - `Float::nan()` if the number is `Float::nan()`
- #[inline]
- fn signum(self) -> f64 {
- if self.is_nan() {
- NAN
- } else {
- unsafe { intrinsics::copysignf64(1.0, self) }
- }
- }
-
/// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
/// positive sign bit and positive infinity.
#[inline]
1.0 / self
}
- #[inline]
- fn powi(self, n: i32) -> f64 {
- unsafe { intrinsics::powif64(self, n) }
- }
-
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f64 {
unsafe { mem::transmute(v) }
}
}
+
+// FIXME: remove (inline) this macro and the Float trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_float", issue = "32110")]
+macro_rules! f64_core_methods { () => {
+ /// Returns `true` if this value is `NaN` and false otherwise.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let nan = f64::NAN;
+ /// let f = 7.0_f64;
+ ///
+ /// assert!(nan.is_nan());
+ /// assert!(!f.is_nan());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_nan(self) -> bool { Float::is_nan(self) }
+
+ /// Returns `true` if this value is positive infinity or negative infinity and
+ /// false otherwise.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = 7.0f64;
+ /// let inf = f64::INFINITY;
+ /// let neg_inf = f64::NEG_INFINITY;
+ /// let nan = f64::NAN;
+ ///
+ /// assert!(!f.is_infinite());
+ /// assert!(!nan.is_infinite());
+ ///
+ /// assert!(inf.is_infinite());
+ /// assert!(neg_inf.is_infinite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_infinite(self) -> bool { Float::is_infinite(self) }
+
+ /// Returns `true` if this number is neither infinite nor `NaN`.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let f = 7.0f64;
+ /// let inf: f64 = f64::INFINITY;
+ /// let neg_inf: f64 = f64::NEG_INFINITY;
+ /// let nan: f64 = f64::NAN;
+ ///
+ /// assert!(f.is_finite());
+ ///
+ /// assert!(!nan.is_finite());
+ /// assert!(!inf.is_finite());
+ /// assert!(!neg_inf.is_finite());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_finite(self) -> bool { Float::is_finite(self) }
+
+ /// Returns `true` if the number is neither zero, infinite,
+ /// [subnormal][subnormal], or `NaN`.
+ ///
+ /// ```
+ /// use std::f64;
+ ///
+ /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
+ /// let max = f64::MAX;
+ /// let lower_than_min = 1.0e-308_f64;
+ /// let zero = 0.0f64;
+ ///
+ /// assert!(min.is_normal());
+ /// assert!(max.is_normal());
+ ///
+ /// assert!(!zero.is_normal());
+ /// assert!(!f64::NAN.is_normal());
+ /// assert!(!f64::INFINITY.is_normal());
+ /// // Values between `0` and `min` are Subnormal.
+ /// assert!(!lower_than_min.is_normal());
+ /// ```
+ /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_normal(self) -> bool { Float::is_normal(self) }
+
+ /// Returns the floating point category of the number. If only one property
+ /// is going to be tested, it is generally faster to use the specific
+ /// predicate instead.
+ ///
+ /// ```
+ /// use std::num::FpCategory;
+ /// use std::f64;
+ ///
+ /// let num = 12.4_f64;
+ /// let inf = f64::INFINITY;
+ ///
+ /// assert_eq!(num.classify(), FpCategory::Normal);
+ /// assert_eq!(inf.classify(), FpCategory::Infinite);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn classify(self) -> FpCategory { Float::classify(self) }
+
+ /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
+ /// positive sign bit and positive infinity.
+ ///
+ /// ```
+ /// let f = 7.0_f64;
+ /// let g = -7.0_f64;
+ ///
+ /// assert!(f.is_sign_positive());
+ /// assert!(!g.is_sign_positive());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")]
+ #[inline]
+ #[doc(hidden)]
+ pub fn is_positive(self) -> bool { Float::is_sign_positive(self) }
+
+ /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
+ /// negative sign bit and negative infinity.
+ ///
+ /// ```
+ /// let f = 7.0_f64;
+ /// let g = -7.0_f64;
+ ///
+ /// assert!(!f.is_sign_negative());
+ /// assert!(g.is_sign_negative());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")]
+ #[inline]
+ #[doc(hidden)]
+ pub fn is_negative(self) -> bool { Float::is_sign_negative(self) }
+
+ /// Takes the reciprocal (inverse) of a number, `1/x`.
+ ///
+ /// ```
+ /// let x = 2.0_f64;
+ /// let abs_difference = (x.recip() - (1.0/x)).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn recip(self) -> f64 { Float::recip(self) }
+
+ /// Converts radians to degrees.
+ ///
+ /// ```
+ /// use std::f64::consts;
+ ///
+ /// let angle = consts::PI;
+ ///
+ /// let abs_difference = (angle.to_degrees() - 180.0).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn to_degrees(self) -> f64 { Float::to_degrees(self) }
+
+ /// Converts degrees to radians.
+ ///
+ /// ```
+ /// use std::f64::consts;
+ ///
+ /// let angle = 180.0_f64;
+ ///
+ /// let abs_difference = (angle.to_radians() - consts::PI).abs();
+ ///
+ /// assert!(abs_difference < 1e-10);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn to_radians(self) -> f64 { Float::to_radians(self) }
+
+ /// Returns the maximum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0_f64;
+ /// let y = 2.0_f64;
+ ///
+ /// assert_eq!(x.max(y), y);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn max(self, other: f64) -> f64 {
+ Float::max(self, other)
+ }
+
+ /// Returns the minimum of the two numbers.
+ ///
+ /// ```
+ /// let x = 1.0_f64;
+ /// let y = 2.0_f64;
+ ///
+ /// assert_eq!(x.min(y), x);
+ /// ```
+ ///
+ /// If one of the arguments is NaN, then the other argument is returned.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn min(self, other: f64) -> f64 {
+ Float::min(self, other)
+ }
+
+ /// Raw transmutation to `u64`.
+ ///
+ /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
+ ///
+ /// See `from_bits` for some discussion of the portability of this operation
+ /// (there are almost no issues).
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
+ /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
+ ///
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn to_bits(self) -> u64 {
+ Float::to_bits(self)
+ }
+
+ /// Raw transmutation from `u64`.
+ ///
+ /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms.
+ /// It turns out this is incredibly portable, for two reasons:
+ ///
+ /// * Floats and Ints have the same endianness on all supported platforms.
+ /// * IEEE-754 very precisely specifies the bit layout of floats.
+ ///
+ /// However there is one caveat: prior to the 2008 version of IEEE-754, how
+ /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
+ /// (notably x86 and ARM) picked the interpretation that was ultimately
+ /// standardized in 2008, but some didn't (notably MIPS). As a result, all
+ /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
+ ///
+ /// Rather than trying to preserve signaling-ness cross-platform, this
+ /// implementation favours preserving the exact bits. This means that
+ /// any payloads encoded in NaNs will be preserved even if the result of
+ /// this method is sent over the network from an x86 machine to a MIPS one.
+ ///
+ /// If the results of this method are only manipulated by the same
+ /// architecture that produced them, then there is no portability concern.
+ ///
+ /// If the input isn't NaN, then there is no portability concern.
+ ///
+ /// If you don't care about signalingness (very likely), then there is no
+ /// portability concern.
+ ///
+ /// Note that this function is distinct from `as` casting, which attempts to
+ /// preserve the *numeric* value, and not the bitwise value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::f64;
+ /// let v = f64::from_bits(0x4029000000000000);
+ /// let difference = (v - 12.5).abs();
+ /// assert!(difference <= 1e-5);
+ /// ```
+ #[stable(feature = "float_bits_conv", since = "1.20.0")]
+ #[inline]
+ pub fn from_bits(v: u64) -> Self {
+ Float::from_bits(v)
+ }
+}}
+
+#[lang = "f64"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl f64 {
+ f64_core_methods!();
+}
Normal,
}
-/// A built-in floating point number.
+// Technically private and only exposed for coretests:
#[doc(hidden)]
-#[unstable(feature = "core_float",
- reason = "stable interface is via `impl f{32,64}` in later crates",
- issue = "32110")]
+#[unstable(feature = "float_internals",
+ reason = "internal routines only exposed for testing",
+ issue = "0")]
pub trait Float: Sized {
/// Type used by `to_bits` and `from_bits`.
- #[stable(feature = "core_float_bits", since = "1.25.0")]
type Bits;
/// Returns `true` if this value is NaN and false otherwise.
- #[stable(feature = "core", since = "1.6.0")]
fn is_nan(self) -> bool;
+
/// Returns `true` if this value is positive infinity or negative infinity and
/// false otherwise.
- #[stable(feature = "core", since = "1.6.0")]
fn is_infinite(self) -> bool;
+
/// Returns `true` if this number is neither infinite nor NaN.
- #[stable(feature = "core", since = "1.6.0")]
fn is_finite(self) -> bool;
+
/// Returns `true` if this number is neither zero, infinite, denormal, or NaN.
- #[stable(feature = "core", since = "1.6.0")]
fn is_normal(self) -> bool;
+
/// Returns the category that this number falls into.
- #[stable(feature = "core", since = "1.6.0")]
fn classify(self) -> FpCategory;
- /// Computes the absolute value of `self`. Returns `Float::nan()` if the
- /// number is `Float::nan()`.
- #[stable(feature = "core", since = "1.6.0")]
- fn abs(self) -> Self;
- /// Returns a number that represents the sign of `self`.
- ///
- /// - `1.0` if the number is positive, `+0.0` or `Float::infinity()`
- /// - `-1.0` if the number is negative, `-0.0` or `Float::neg_infinity()`
- /// - `Float::nan()` if the number is `Float::nan()`
- #[stable(feature = "core", since = "1.6.0")]
- fn signum(self) -> Self;
-
/// Returns `true` if `self` is positive, including `+0.0` and
/// `Float::infinity()`.
- #[stable(feature = "core", since = "1.6.0")]
fn is_sign_positive(self) -> bool;
+
/// Returns `true` if `self` is negative, including `-0.0` and
/// `Float::neg_infinity()`.
- #[stable(feature = "core", since = "1.6.0")]
fn is_sign_negative(self) -> bool;
/// Take the reciprocal (inverse) of a number, `1/x`.
- #[stable(feature = "core", since = "1.6.0")]
fn recip(self) -> Self;
- /// Raise a number to an integer power.
- ///
- /// Using this function is generally faster than using `powf`
- #[stable(feature = "core", since = "1.6.0")]
- fn powi(self, n: i32) -> Self;
-
/// Convert radians to degrees.
- #[stable(feature = "deg_rad_conversions", since="1.7.0")]
fn to_degrees(self) -> Self;
+
/// Convert degrees to radians.
- #[stable(feature = "deg_rad_conversions", since="1.7.0")]
fn to_radians(self) -> Self;
/// Returns the maximum of the two numbers.
- #[stable(feature = "core_float_min_max", since="1.20.0")]
fn max(self, other: Self) -> Self;
+
/// Returns the minimum of the two numbers.
- #[stable(feature = "core_float_min_max", since="1.20.0")]
fn min(self, other: Self) -> Self;
/// Raw transmutation to integer.
- #[stable(feature = "core_float_bits", since="1.25.0")]
fn to_bits(self) -> Self::Bits;
+
/// Raw transmutation from integer.
- #[stable(feature = "core_float_bits", since="1.25.0")]
fn from_bits(v: Self::Bits) -> Self;
}
from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
/// The error type returned when a checked integral type conversion fails.
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
#[derive(Debug, Copy, Clone)]
pub struct TryFromIntError(());
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl fmt::Display for TryFromIntError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.__description().fmt(fmt)
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl From<!> for TryFromIntError {
fn from(never: !) -> TryFromIntError {
never
// only negative bounds
macro_rules! try_from_lower_bounded {
($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
// unsigned to signed (only positive bound)
macro_rules! try_from_upper_bounded {
($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
// all other cases
macro_rules! try_from_both_bounded {
($source:ty, $($target:ty),*) => {$(
- #[stable(feature = "try_from", since = "1.26.0")]
+ #[unstable(feature = "try_from", issue = "33417")]
impl TryFrom<$source> for $target {
type Error = TryFromIntError;
message="cannot add `{RHS}` to `{Self}`",
label="no implementation for `{Self} + {RHS}`",
)]
+#[doc(alias = "+")]
pub trait Add<RHS=Self> {
/// The resulting type after applying the `+` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot subtract `{RHS}` from `{Self}`",
label="no implementation for `{Self} - {RHS}`")]
+#[doc(alias = "-")]
pub trait Sub<RHS=Self> {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`",
label="no implementation for `{Self} * {RHS}`")]
+#[doc(alias = "*")]
pub trait Mul<RHS=Self> {
/// The resulting type after applying the `*` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`",
label="no implementation for `{Self} / {RHS}`")]
+#[doc(alias = "/")]
pub trait Div<RHS=Self> {
/// The resulting type after applying the `/` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`",
label="no implementation for `{Self} % {RHS}`")]
+#[doc(alias = "%")]
pub trait Rem<RHS=Self> {
/// The resulting type after applying the `%` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "neg"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "-")]
pub trait Neg {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`",
label="no implementation for `{Self} += {Rhs}`")]
+#[doc(alias = "+")]
+#[doc(alias = "+=")]
pub trait AddAssign<Rhs=Self> {
/// Performs the `+=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot subtract-assign `{Rhs}` from `{Self}`",
label="no implementation for `{Self} -= {Rhs}`")]
+#[doc(alias = "-")]
+#[doc(alias = "-=")]
pub trait SubAssign<Rhs=Self> {
/// Performs the `-=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`",
label="no implementation for `{Self} *= {Rhs}`")]
+#[doc(alias = "*")]
+#[doc(alias = "*=")]
pub trait MulAssign<Rhs=Self> {
/// Performs the `*=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`",
label="no implementation for `{Self} /= {Rhs}`")]
+#[doc(alias = "/")]
+#[doc(alias = "/=")]
pub trait DivAssign<Rhs=Self> {
/// Performs the `/=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``",
label="no implementation for `{Self} %= {Rhs}`")]
+#[doc(alias = "%")]
+#[doc(alias = "%=")]
pub trait RemAssign<Rhs=Self> {
/// Performs the `%=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`",
label="no implementation for `{Self} << {RHS}`")]
-pub trait Shl<RHS> {
+pub trait Shl<RHS=Self> {
/// The resulting type after applying the `<<` operator.
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`",
label="no implementation for `{Self} >> {RHS}`")]
-pub trait Shr<RHS> {
+pub trait Shr<RHS=Self> {
/// The resulting type after applying the `>>` operator.
#[stable(feature = "rust1", since = "1.0.0")]
type Output;
#[stable(feature = "op_assign_traits", since = "1.8.0")]
#[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`",
label="no implementation for `{Self} <<= {Rhs}`")]
-pub trait ShlAssign<Rhs> {
+pub trait ShlAssign<Rhs=Self> {
/// Performs the `<<=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
fn shl_assign(&mut self, rhs: Rhs);
#[lang = "index"]
#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "]")]
+#[doc(alias = "[")]
+#[doc(alias = "[]")]
pub trait Index<Idx: ?Sized> {
/// The returned type after indexing.
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "index_mut"]
#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"]
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(alias = "[")]
+#[doc(alias = "]")]
+#[doc(alias = "[]")]
pub trait IndexMut<Idx: ?Sized>: Index<Idx> {
/// Performs the mutable indexing (`container[index]`) operation.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
/// #![feature(range_contains)]
///
- /// assert!(!(3..5).contains(2));
- /// assert!( (3..5).contains(3));
- /// assert!( (3..5).contains(4));
- /// assert!(!(3..5).contains(5));
+ /// use std::f32;
///
- /// assert!(!(3..3).contains(3));
- /// assert!(!(3..2).contains(3));
+ /// assert!(!(3..5).contains(&2));
+ /// assert!( (3..5).contains(&3));
+ /// assert!( (3..5).contains(&4));
+ /// assert!(!(3..5).contains(&5));
+ ///
+ /// assert!(!(3..3).contains(&3));
+ /// assert!(!(3..2).contains(&3));
+ ///
+ /// assert!( (0.0..1.0).contains(&0.5));
+ /// assert!(!(0.0..1.0).contains(&f32::NAN));
+ /// assert!(!(0.0..f32::NAN).contains(&0.5));
+ /// assert!(!(f32::NAN..1.0).contains(&0.5));
/// ```
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
- pub fn contains(&self, item: Idx) -> bool {
- (self.start <= item) && (item < self.end)
+ pub fn contains<U>(&self, item: &U) -> bool
+ where
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
+ {
+ <Self as RangeBounds<Idx>>::contains(self, item)
}
/// Returns `true` if the range contains no items.
}
}
-#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
impl<Idx: PartialOrd<Idx>> RangeFrom<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// ```
/// #![feature(range_contains)]
///
- /// assert!(!(3..).contains(2));
- /// assert!( (3..).contains(3));
- /// assert!( (3..).contains(1_000_000_000));
+ /// use std::f32;
+ ///
+ /// assert!(!(3..).contains(&2));
+ /// assert!( (3..).contains(&3));
+ /// assert!( (3..).contains(&1_000_000_000));
+ ///
+ /// assert!( (0.0..).contains(&0.5));
+ /// assert!(!(0.0..).contains(&f32::NAN));
+ /// assert!(!(f32::NAN..).contains(&0.5));
/// ```
- pub fn contains(&self, item: Idx) -> bool {
- (self.start <= item)
+ #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+ pub fn contains<U>(&self, item: &U) -> bool
+ where
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
+ {
+ <Self as RangeBounds<Idx>>::contains(self, item)
}
}
}
}
-#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
impl<Idx: PartialOrd<Idx>> RangeTo<Idx> {
/// Returns `true` if `item` is contained in the range.
///
/// ```
/// #![feature(range_contains)]
///
- /// assert!( (..5).contains(-1_000_000_000));
- /// assert!( (..5).contains(4));
- /// assert!(!(..5).contains(5));
+ /// use std::f32;
+ ///
+ /// assert!( (..5).contains(&-1_000_000_000));
+ /// assert!( (..5).contains(&4));
+ /// assert!(!(..5).contains(&5));
+ ///
+ /// assert!( (..1.0).contains(&0.5));
+ /// assert!(!(..1.0).contains(&f32::NAN));
+ /// assert!(!(..f32::NAN).contains(&0.5));
/// ```
- pub fn contains(&self, item: Idx) -> bool {
- (item < self.end)
+ #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+ pub fn contains<U>(&self, item: &U) -> bool
+ where
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
+ {
+ <Self as RangeBounds<Idx>>::contains(self, item)
}
}
/// ```
/// #![feature(range_contains)]
///
- /// assert!(!(3..=5).contains(2));
- /// assert!( (3..=5).contains(3));
- /// assert!( (3..=5).contains(4));
- /// assert!( (3..=5).contains(5));
- /// assert!(!(3..=5).contains(6));
+ /// use std::f32;
+ ///
+ /// assert!(!(3..=5).contains(&2));
+ /// assert!( (3..=5).contains(&3));
+ /// assert!( (3..=5).contains(&4));
+ /// assert!( (3..=5).contains(&5));
+ /// assert!(!(3..=5).contains(&6));
///
- /// assert!( (3..=3).contains(3));
- /// assert!(!(3..=2).contains(3));
+ /// assert!( (3..=3).contains(&3));
+ /// assert!(!(3..=2).contains(&3));
+ ///
+ /// assert!( (0.0..=1.0).contains(&1.0));
+ /// assert!(!(0.0..=1.0).contains(&f32::NAN));
+ /// assert!(!(0.0..=f32::NAN).contains(&0.0));
+ /// assert!(!(f32::NAN..=1.0).contains(&1.0));
/// ```
#[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
- pub fn contains(&self, item: Idx) -> bool {
- self.start <= item && item <= self.end
+ pub fn contains<U>(&self, item: &U) -> bool
+ where
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
+ {
+ <Self as RangeBounds<Idx>>::contains(self, item)
}
/// Returns `true` if the range contains no items.
/// ```
/// #![feature(range_contains)]
///
- /// assert!( (..=5).contains(-1_000_000_000));
- /// assert!( (..=5).contains(5));
- /// assert!(!(..=5).contains(6));
+ /// use std::f32;
+ ///
+ /// assert!( (..=5).contains(&-1_000_000_000));
+ /// assert!( (..=5).contains(&5));
+ /// assert!(!(..=5).contains(&6));
+ ///
+ /// assert!( (..=1.0).contains(&1.0));
+ /// assert!(!(..=1.0).contains(&f32::NAN));
+ /// assert!(!(..=f32::NAN).contains(&0.5));
/// ```
- pub fn contains(&self, item: Idx) -> bool {
- (item <= self.end)
+ #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+ pub fn contains<U>(&self, item: &U) -> bool
+ where
+ Idx: PartialOrd<U>,
+ U: ?Sized + PartialOrd<Idx>,
+ {
+ <Self as RangeBounds<Idx>>::contains(self, item)
}
}
/// # }
/// ```
fn end(&self) -> Bound<&T>;
+
+
+ /// Returns `true` if `item` is contained in the range.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(range_contains)]
+ ///
+ /// use std::f32;
+ ///
+ /// assert!( (3..5).contains(&4));
+ /// assert!(!(3..5).contains(&2));
+ ///
+ /// assert!( (0.0..1.0).contains(&0.5));
+ /// assert!(!(0.0..1.0).contains(&f32::NAN));
+ /// assert!(!(0.0..f32::NAN).contains(&0.5));
+ /// assert!(!(f32::NAN..1.0).contains(&0.5));
+ #[unstable(feature = "range_contains", reason = "recently added as per RFC", issue = "32311")]
+ fn contains<U>(&self, item: &U) -> bool
+ where
+ T: PartialOrd<U>,
+ U: ?Sized + PartialOrd<T>,
+ {
+ (match self.start() {
+ Included(ref start) => *start <= item,
+ Excluded(ref start) => *start < item,
+ Unbounded => true,
+ })
+ &&
+ (match self.end() {
+ Included(ref end) => item <= *end,
+ Excluded(ref end) => item < *end,
+ Unbounded => true,
+ })
+ }
}
use self::Bound::{Excluded, Included, Unbounded};
that implement `{Try}`",
label="the `?` operator cannot be applied to type `{Self}`")
)]
+#[doc(alias = "?")]
pub trait Try {
/// The type of this value when viewed as successful.
#[unstable(feature = "try_trait", issue = "42327")]
and related macros",
issue = "0")]
#[doc(hidden)]
- pub fn internal_constructor(payload: &'a (Any + Send),
- message: Option<&'a fmt::Arguments<'a>>,
+ #[inline]
+ pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>,
location: Location<'a>)
-> Self {
- PanicInfo { payload, location, message }
+ PanicInfo { payload: &(), location, message }
+ }
+
+ #[doc(hidden)]
+ #[inline]
+ pub fn set_payload(&mut self, info: &'a (Any + Send)) {
+ self.payload = info;
}
/// Returns the payload associated with the panic.
write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
}
}
+
+/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
+/// and other panic runtimes. Not intended to be stabilized any time soon, do
+/// not use.
+#[unstable(feature = "std_internals", issue = "0")]
+#[doc(hidden)]
+pub unsafe trait BoxMeUp {
+ fn box_me_up(&mut self) -> *mut (Any + Send);
+ fn get(&mut self) -> &(Any + Send);
+}
// Re-exported extension traits for primitive types
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
+#[cfg(stage0)]
pub use slice::SliceExt;
#[stable(feature = "core_prelude", since = "1.4.0")]
#[doc(no_inline)]
+#[cfg(stage0)]
pub use str::StrExt;
/// Basic usage:
///
/// ```
-/// #![feature(swap_nonoverlapping)]
-///
/// use std::ptr;
///
/// let mut x = [1, 2, 3, 4];
/// assert_eq!(y, [1, 2, 9]);
/// ```
#[inline]
-#[unstable(feature = "swap_nonoverlapping", issue = "42818")]
+#[stable(feature = "swap_nonoverlapping", since = "1.27.0")]
pub unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
let x = x as *mut u8;
let y = y as *mut u8;
}
/// Cast to a pointer of another type
- #[unstable(feature = "nonnull_cast", issue = "47653")]
+ #[stable(feature = "nonnull_cast", since = "1.27.0")]
pub fn cast<U>(self) -> NonNull<U> {
unsafe {
NonNull::new_unchecked(self.as_ptr() as *mut U)
// Extension traits
//
+public_in_stage0! {
+{
/// Extension methods for slices.
#[unstable(feature = "core_slice_ext",
reason = "stable interface provided by `impl [T]` in later crates",
issue = "32110")]
#[allow(missing_docs)] // documented elsewhere
-pub trait SliceExt {
+}
+trait SliceExt {
type Item;
#[stable(feature = "core", since = "1.6.0")]
fn split<P>(&self, pred: P) -> Split<Self::Item, P>
where P: FnMut(&Self::Item) -> bool;
- #[unstable(feature = "slice_rsplit", issue = "41020")]
+ #[stable(feature = "slice_rsplit", since = "1.27.0")]
fn rsplit<P>(&self, pred: P) -> RSplit<Self::Item, P>
where P: FnMut(&Self::Item) -> bool;
fn split_mut<P>(&mut self, pred: P) -> SplitMut<Self::Item, P>
where P: FnMut(&Self::Item) -> bool;
- #[unstable(feature = "slice_rsplit", issue = "41020")]
+ #[stable(feature = "slice_rsplit", since = "1.27.0")]
fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<Self::Item, P>
where P: FnMut(&Self::Item) -> bool;
#[stable(feature = "copy_from_slice", since = "1.9.0")]
fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy;
- #[unstable(feature = "swap_with_slice", issue = "44030")]
+ #[stable(feature = "swap_with_slice", since = "1.27.0")]
fn swap_with_slice(&mut self, src: &mut [Self::Item]);
#[stable(feature = "sort_unstable", since = "1.20.0")]
fn sort_unstable_by_key<B, F>(&mut self, f: F)
where F: FnMut(&Self::Item) -> B,
B: Ord;
-}
+}}
// Use macros to be generic over const/mut
macro_rules! slice_offset {
}
}
+// FIXME: remove (inline) this macro and the SliceExt trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_slice_ext", issue = "32110")]
+macro_rules! slice_core_methods { () => {
+ /// Returns the number of elements in the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let a = [1, 2, 3];
+ /// assert_eq!(a.len(), 3);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn len(&self) -> usize {
+ SliceExt::len(self)
+ }
+
+ /// Returns `true` if the slice has a length of 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let a = [1, 2, 3];
+ /// assert!(!a.is_empty());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ SliceExt::is_empty(self)
+ }
+
+ /// Returns the first element of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&10), v.first());
+ ///
+ /// let w: &[i32] = &[];
+ /// assert_eq!(None, w.first());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn first(&self) -> Option<&T> {
+ SliceExt::first(self)
+ }
+
+ /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(first) = x.first_mut() {
+ /// *first = 5;
+ /// }
+ /// assert_eq!(x, &[5, 1, 2]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn first_mut(&mut self) -> Option<&mut T> {
+ SliceExt::first_mut(self)
+ }
+
+ /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first() {
+ /// assert_eq!(first, &0);
+ /// assert_eq!(elements, &[1, 2]);
+ /// }
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_first(&self) -> Option<(&T, &[T])> {
+ SliceExt::split_first(self)
+ }
+
+ /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((first, elements)) = x.split_first_mut() {
+ /// *first = 3;
+ /// elements[0] = 4;
+ /// elements[1] = 5;
+ /// }
+ /// assert_eq!(x, &[3, 4, 5]);
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
+ SliceExt::split_first_mut(self)
+ }
+
+ /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last() {
+ /// assert_eq!(last, &2);
+ /// assert_eq!(elements, &[0, 1]);
+ /// }
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_last(&self) -> Option<(&T, &[T])> {
+ SliceExt::split_last(self)
+
+ }
+
+ /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some((last, elements)) = x.split_last_mut() {
+ /// *last = 3;
+ /// elements[0] = 4;
+ /// elements[1] = 5;
+ /// }
+ /// assert_eq!(x, &[4, 5, 3]);
+ /// ```
+ #[stable(feature = "slice_splits", since = "1.5.0")]
+ #[inline]
+ pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
+ SliceExt::split_last_mut(self)
+ }
+
+ /// Returns the last element of the slice, or `None` if it is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&30), v.last());
+ ///
+ /// let w: &[i32] = &[];
+ /// assert_eq!(None, w.last());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn last(&self) -> Option<&T> {
+ SliceExt::last(self)
+ }
+
+ /// Returns a mutable pointer to the last item in the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(last) = x.last_mut() {
+ /// *last = 10;
+ /// }
+ /// assert_eq!(x, &[0, 1, 10]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn last_mut(&mut self) -> Option<&mut T> {
+ SliceExt::last_mut(self)
+ }
+
+ /// Returns a reference to an element or subslice depending on the type of
+ /// index.
+ ///
+ /// - If given a position, returns a reference to the element at that
+ /// position or `None` if out of bounds.
+ /// - If given a range, returns the subslice corresponding to that range,
+ /// or `None` if out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert_eq!(Some(&40), v.get(1));
+ /// assert_eq!(Some(&[10, 40][..]), v.get(0..2));
+ /// assert_eq!(None, v.get(3));
+ /// assert_eq!(None, v.get(0..4));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn get<I>(&self, index: I) -> Option<&I::Output>
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get(self, index)
+ }
+
+ /// Returns a mutable reference to an element or subslice depending on the
+ /// type of index (see [`get`]) or `None` if the index is out of bounds.
+ ///
+ /// [`get`]: #method.get
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [0, 1, 2];
+ ///
+ /// if let Some(elem) = x.get_mut(1) {
+ /// *elem = 42;
+ /// }
+ /// assert_eq!(x, &[0, 42, 2]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn get_mut<I>(&mut self, index: I) -> Option<&mut I::Output>
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get_mut(self, index)
+ }
+
+ /// Returns a reference to an element or subslice, without doing bounds
+ /// checking.
+ ///
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`get`].
+ ///
+ /// [`get`]: #method.get
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ ///
+ /// unsafe {
+ /// assert_eq!(x.get_unchecked(1), &2);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get_unchecked(self, index)
+ }
+
+ /// Returns a mutable reference to an element or subslice, without doing
+ /// bounds checking.
+ ///
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`get_mut`].
+ ///
+ /// [`get_mut`]: #method.get_mut
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ ///
+ /// unsafe {
+ /// let elem = x.get_unchecked_mut(1);
+ /// *elem = 13;
+ /// }
+ /// assert_eq!(x, &[1, 13, 4]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
+ where I: SliceIndex<Self>
+ {
+ SliceExt::get_unchecked_mut(self, index)
+ }
+
+ /// Returns a raw pointer to the slice's buffer.
+ ///
+ /// The caller must ensure that the slice outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ ///
+ /// Modifying the container referenced by this slice may cause its buffer
+ /// to be reallocated, which would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ /// let x_ptr = x.as_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// assert_eq!(x.get_unchecked(i), &*x_ptr.offset(i as isize));
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn as_ptr(&self) -> *const T {
+ SliceExt::as_ptr(self)
+ }
+
+ /// Returns an unsafe mutable pointer to the slice's buffer.
+ ///
+ /// The caller must ensure that the slice outlives the pointer this
+ /// function returns, or else it will end up pointing to garbage.
+ ///
+ /// Modifying the container referenced by this slice may cause its buffer
+ /// to be reallocated, which would also make any pointers to it invalid.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ /// let x_ptr = x.as_mut_ptr();
+ ///
+ /// unsafe {
+ /// for i in 0..x.len() {
+ /// *x_ptr.offset(i as isize) += 2;
+ /// }
+ /// }
+ /// assert_eq!(x, &[3, 4, 6]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut T {
+ SliceExt::as_mut_ptr(self)
+ }
+
+ /// Swaps two elements in the slice.
+ ///
+ /// # Arguments
+ ///
+ /// * a - The index of the first element
+ /// * b - The index of the second element
+ ///
+ /// # Panics
+ ///
+ /// Panics if `a` or `b` are out of bounds.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = ["a", "b", "c", "d"];
+ /// v.swap(1, 3);
+ /// assert!(v == ["a", "d", "c", "b"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn swap(&mut self, a: usize, b: usize) {
+ SliceExt::swap(self, a, b)
+ }
+
+ /// Reverses the order of elements in the slice, in place.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [1, 2, 3];
+ /// v.reverse();
+ /// assert!(v == [3, 2, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn reverse(&mut self) {
+ SliceExt::reverse(self)
+ }
+
+ /// Returns an iterator over the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &[1, 2, 4];
+ /// let mut iterator = x.iter();
+ ///
+ /// assert_eq!(iterator.next(), Some(&1));
+ /// assert_eq!(iterator.next(), Some(&2));
+ /// assert_eq!(iterator.next(), Some(&4));
+ /// assert_eq!(iterator.next(), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn iter(&self) -> Iter<T> {
+ SliceExt::iter(self)
+ }
+
+ /// Returns an iterator that allows modifying each value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let x = &mut [1, 2, 4];
+ /// for elem in x.iter_mut() {
+ /// *elem += 2;
+ /// }
+ /// assert_eq!(x, &[3, 4, 6]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn iter_mut(&mut self) -> IterMut<T> {
+ SliceExt::iter_mut(self)
+ }
+
+ /// Returns an iterator over all contiguous windows of length
+ /// `size`. The windows overlap. If the slice is shorter than
+ /// `size`, the iterator returns no values.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = ['r', 'u', 's', 't'];
+ /// let mut iter = slice.windows(2);
+ /// assert_eq!(iter.next().unwrap(), &['r', 'u']);
+ /// assert_eq!(iter.next().unwrap(), &['u', 's']);
+ /// assert_eq!(iter.next().unwrap(), &['s', 't']);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If the slice is shorter than `size`:
+ ///
+ /// ```
+ /// let slice = ['f', 'o', 'o'];
+ /// let mut iter = slice.windows(4);
+ /// assert!(iter.next().is_none());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn windows(&self, size: usize) -> Windows<T> {
+ SliceExt::windows(self, size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a
+ /// time. The chunks are slices and do not overlap. If `chunk_size` does
+ /// not divide the length of the slice, then the last chunk will
+ /// not have length `chunk_size`.
+ ///
+ /// See [`exact_chunks`] for a variant of this iterator that returns chunks
+ /// of always exactly `chunk_size` elements.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = ['l', 'o', 'r', 'e', 'm'];
+ /// let mut iter = slice.chunks(2);
+ /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
+ /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
+ /// assert_eq!(iter.next().unwrap(), &['m']);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// [`exact_chunks`]: #method.exact_chunks
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn chunks(&self, chunk_size: usize) -> Chunks<T> {
+ SliceExt::chunks(self, chunk_size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a
+ /// time. The chunks are slices and do not overlap. If `chunk_size` does
+ /// not divide the length of the slice, then the last up to `chunk_size-1`
+ /// elements will be omitted.
+ ///
+ /// Due to each chunk having exactly `chunk_size` elements, the compiler
+ /// can often optimize the resulting code better than in the case of
+ /// [`chunks`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(exact_chunks)]
+ ///
+ /// let slice = ['l', 'o', 'r', 'e', 'm'];
+ /// let mut iter = slice.exact_chunks(2);
+ /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
+ /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// [`chunks`]: #method.chunks
+ #[unstable(feature = "exact_chunks", issue = "47115")]
+ #[inline]
+ pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks<T> {
+ SliceExt::exact_chunks(self, chunk_size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a time.
+ /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
+ /// not divide the length of the slice, then the last chunk will not
+ /// have length `chunk_size`.
+ ///
+ /// See [`exact_chunks_mut`] for a variant of this iterator that returns chunks
+ /// of always exactly `chunk_size` elements.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = &mut [0, 0, 0, 0, 0];
+ /// let mut count = 1;
+ ///
+ /// for chunk in v.chunks_mut(2) {
+ /// for elem in chunk.iter_mut() {
+ /// *elem += count;
+ /// }
+ /// count += 1;
+ /// }
+ /// assert_eq!(v, &[1, 1, 2, 2, 3]);
+ /// ```
+ ///
+ /// [`exact_chunks_mut`]: #method.exact_chunks_mut
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<T> {
+ SliceExt::chunks_mut(self, chunk_size)
+ }
+
+ /// Returns an iterator over `chunk_size` elements of the slice at a time.
+ /// The chunks are mutable slices, and do not overlap. If `chunk_size` does
+ /// not divide the length of the slice, then the last up to `chunk_size-1`
+ /// elements will be omitted.
+ ///
+ ///
+ /// Due to each chunk having exactly `chunk_size` elements, the compiler
+ /// can often optimize the resulting code better than in the case of
+ /// [`chunks_mut`].
+ ///
+ /// # Panics
+ ///
+ /// Panics if `chunk_size` is 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(exact_chunks)]
+ ///
+ /// let v = &mut [0, 0, 0, 0, 0];
+ /// let mut count = 1;
+ ///
+ /// for chunk in v.exact_chunks_mut(2) {
+ /// for elem in chunk.iter_mut() {
+ /// *elem += count;
+ /// }
+ /// count += 1;
+ /// }
+ /// assert_eq!(v, &[1, 1, 2, 2, 0]);
+ /// ```
+ ///
+ /// [`chunks_mut`]: #method.chunks_mut
+ #[unstable(feature = "exact_chunks", issue = "47115")]
+ #[inline]
+ pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut<T> {
+ SliceExt::exact_chunks_mut(self, chunk_size)
+ }
+
+ /// Divides one slice into two at an index.
+ ///
+ /// The first will contain all indices from `[0, mid)` (excluding
+ /// the index `mid` itself) and the second will contain all
+ /// indices from `[mid, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [1, 2, 3, 4, 5, 6];
+ ///
+ /// {
+ /// let (left, right) = v.split_at(0);
+ /// assert!(left == []);
+ /// assert!(right == [1, 2, 3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_at(2);
+ /// assert!(left == [1, 2]);
+ /// assert!(right == [3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_at(6);
+ /// assert!(left == [1, 2, 3, 4, 5, 6]);
+ /// assert!(right == []);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
+ SliceExt::split_at(self, mid)
+ }
+
+ /// Divides one mutable slice into two at an index.
+ ///
+ /// The first will contain all indices from `[0, mid)` (excluding
+ /// the index `mid` itself) and the second will contain all
+ /// indices from `[mid, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [1, 0, 3, 0, 5, 6];
+ /// // scoped to restrict the lifetime of the borrows
+ /// {
+ /// let (left, right) = v.split_at_mut(2);
+ /// assert!(left == [1, 0]);
+ /// assert!(right == [3, 0, 5, 6]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// }
+ /// assert!(v == [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
+ SliceExt::split_at_mut(self, mid)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`. The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = [10, 40, 33, 20];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10, 40]);
+ /// assert_eq!(iter.next().unwrap(), &[20]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If the first element is matched, an empty slice will be the first item
+ /// returned by the iterator. Similarly, if the last element in the slice
+ /// is matched, an empty slice will be the last item returned by the
+ /// iterator:
+ ///
+ /// ```
+ /// let slice = [10, 40, 33];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10, 40]);
+ /// assert_eq!(iter.next().unwrap(), &[]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// If two matched elements are directly adjacent, an empty slice will be
+ /// present between them:
+ ///
+ /// ```
+ /// let slice = [10, 6, 33, 20];
+ /// let mut iter = slice.split(|num| num % 3 == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[10]);
+ /// assert_eq!(iter.next().unwrap(), &[]);
+ /// assert_eq!(iter.next().unwrap(), &[20]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split<F>(&self, pred: F) -> Split<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::split(self, pred)
+ }
+
+ /// Returns an iterator over mutable subslices separated by elements that
+ /// match `pred`. The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.split_mut(|num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(v, [1, 40, 30, 1, 60, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_mut<F>(&mut self, pred: F) -> SplitMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::split_mut(self, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, starting at the end of the slice and working backwards.
+ /// The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let slice = [11, 22, 33, 0, 44, 55];
+ /// let mut iter = slice.rsplit(|num| *num == 0);
+ ///
+ /// assert_eq!(iter.next().unwrap(), &[44, 55]);
+ /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
+ /// assert_eq!(iter.next(), None);
+ /// ```
+ ///
+ /// As with `split()`, if the first or last element is matched, an empty
+ /// slice will be the first (or last) item returned by the iterator.
+ ///
+ /// ```
+ /// let v = &[0, 1, 1, 2, 3, 5, 8];
+ /// let mut it = v.rsplit(|n| *n % 2 == 0);
+ /// assert_eq!(it.next().unwrap(), &[]);
+ /// assert_eq!(it.next().unwrap(), &[3, 5]);
+ /// assert_eq!(it.next().unwrap(), &[1, 1]);
+ /// assert_eq!(it.next().unwrap(), &[]);
+ /// assert_eq!(it.next(), None);
+ /// ```
+ #[stable(feature = "slice_rsplit", since = "1.27.0")]
+ #[inline]
+ pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplit(self, pred)
+ }
+
+ /// Returns an iterator over mutable subslices separated by elements that
+ /// match `pred`, starting at the end of the slice and working
+ /// backwards. The matched element is not contained in the subslices.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [100, 400, 300, 200, 600, 500];
+ ///
+ /// let mut count = 0;
+ /// for group in v.rsplit_mut(|num| *num % 3 == 0) {
+ /// count += 1;
+ /// group[0] = count;
+ /// }
+ /// assert_eq!(v, [3, 400, 300, 2, 600, 1]);
+ /// ```
+ ///
+ #[stable(feature = "slice_rsplit", since = "1.27.0")]
+ #[inline]
+ pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplit_mut(self, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, limited to returning at most `n` items. The matched element is
+ /// not contained in the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
+ /// `[20, 60, 50]`):
+ ///
+ /// ```
+ /// let v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.splitn(2, |num| *num % 3 == 0) {
+ /// println!("{:?}", group);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::splitn(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred`, limited to returning at most `n` items. The matched element is
+ /// not contained in the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.splitn_mut(2, |num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(v, [1, 40, 30, 1, 60, 50]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::splitn_mut(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred` limited to returning at most `n` items. This starts at the end of
+ /// the slice and works backwards. The matched element is not contained in
+ /// the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// Print the slice split once, starting from the end, by numbers divisible
+ /// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
+ ///
+ /// ```
+ /// let v = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in v.rsplitn(2, |num| *num % 3 == 0) {
+ /// println!("{:?}", group);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplitn(self, n, pred)
+ }
+
+ /// Returns an iterator over subslices separated by elements that match
+ /// `pred` limited to returning at most `n` items. This starts at the end of
+ /// the slice and works backwards. The matched element is not contained in
+ /// the subslices.
+ ///
+ /// The last element returned, if any, will contain the remainder of the
+ /// slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut s = [10, 40, 30, 20, 60, 50];
+ ///
+ /// for group in s.rsplitn_mut(2, |num| *num % 3 == 0) {
+ /// group[0] = 1;
+ /// }
+ /// assert_eq!(s, [1, 40, 30, 20, 60, 1]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
+ where F: FnMut(&T) -> bool
+ {
+ SliceExt::rsplitn_mut(self, n, pred)
+ }
+
+ /// Returns `true` if the slice contains an element with the given value.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.contains(&30));
+ /// assert!(!v.contains(&50));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn contains(&self, x: &T) -> bool
+ where T: PartialEq
+ {
+ SliceExt::contains(self, x)
+ }
+
+ /// Returns `true` if `needle` is a prefix of the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.starts_with(&[10]));
+ /// assert!(v.starts_with(&[10, 40]));
+ /// assert!(!v.starts_with(&[50]));
+ /// assert!(!v.starts_with(&[10, 50]));
+ /// ```
+ ///
+ /// Always returns `true` if `needle` is an empty slice:
+ ///
+ /// ```
+ /// let v = &[10, 40, 30];
+ /// assert!(v.starts_with(&[]));
+ /// let v: &[u8] = &[];
+ /// assert!(v.starts_with(&[]));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn starts_with(&self, needle: &[T]) -> bool
+ where T: PartialEq
+ {
+ SliceExt::starts_with(self, needle)
+ }
+
+ /// Returns `true` if `needle` is a suffix of the slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = [10, 40, 30];
+ /// assert!(v.ends_with(&[30]));
+ /// assert!(v.ends_with(&[40, 30]));
+ /// assert!(!v.ends_with(&[50]));
+ /// assert!(!v.ends_with(&[50, 30]));
+ /// ```
+ ///
+ /// Always returns `true` if `needle` is an empty slice:
+ ///
+ /// ```
+ /// let v = &[10, 40, 30];
+ /// assert!(v.ends_with(&[]));
+ /// let v: &[u8] = &[];
+ /// assert!(v.ends_with(&[]));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ends_with(&self, needle: &[T]) -> bool
+ where T: PartialEq
+ {
+ SliceExt::ends_with(self, needle)
+ }
+
+ /// Binary searches this sorted slice for a given element.
+ ///
+ /// If the value is found then `Ok` is returned, containing the
+ /// index of the matching element; if the value is not found then
+ /// `Err` is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
+ ///
+ /// # Examples
+ ///
+ /// Looks up a series of four elements. The first is found, with a
+ /// uniquely determined position; the second and third are not
+ /// found; the fourth could match any position in `[1, 4]`.
+ ///
+ /// ```
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ ///
+ /// assert_eq!(s.binary_search(&13), Ok(9));
+ /// assert_eq!(s.binary_search(&4), Err(7));
+ /// assert_eq!(s.binary_search(&100), Err(13));
+ /// let r = s.binary_search(&1);
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
+ where T: Ord
+ {
+ SliceExt::binary_search(self, x)
+ }
+
+ /// Binary searches this sorted slice with a comparator function.
+ ///
+ /// The comparator function should implement an order consistent
+ /// with the sort order of the underlying slice, returning an
+ /// order code that indicates whether its argument is `Less`,
+ /// `Equal` or `Greater` the desired target.
+ ///
+ /// If a matching value is found then returns `Ok`, containing
+ /// the index for the matched element; if no match is found then
+ /// `Err` is returned, containing the index where a matching
+ /// element could be inserted while maintaining sorted order.
+ ///
+ /// # Examples
+ ///
+ /// Looks up a series of four elements. The first is found, with a
+ /// uniquely determined position; the second and third are not
+ /// found; the fourth could match any position in `[1, 4]`.
+ ///
+ /// ```
+ /// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+ ///
+ /// let seek = 13;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
+ /// let seek = 4;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
+ /// let seek = 100;
+ /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
+ /// let seek = 1;
+ /// let r = s.binary_search_by(|probe| probe.cmp(&seek));
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
+ where F: FnMut(&'a T) -> Ordering
+ {
+ SliceExt::binary_search_by(self, f)
+ }
+
+ /// Binary searches this sorted slice with a key extraction function.
+ ///
+ /// Assumes that the slice is sorted by the key, for instance with
+ /// [`sort_by_key`] using the same key extraction function.
+ ///
+ /// If a matching value is found then returns `Ok`, containing the
+ /// index for the matched element; if no match is found then `Err`
+ /// is returned, containing the index where a matching element could
+ /// be inserted while maintaining sorted order.
+ ///
+ /// [`sort_by_key`]: #method.sort_by_key
+ ///
+ /// # Examples
+ ///
+ /// Looks up a series of four elements in a slice of pairs sorted by
+ /// their second elements. The first is found, with a uniquely
+ /// determined position; the second and third are not found; the
+ /// fourth could match any position in `[1, 4]`.
+ ///
+ /// ```
+ /// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
+ /// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
+ /// (1, 21), (2, 34), (4, 55)];
+ ///
+ /// assert_eq!(s.binary_search_by_key(&13, |&(a,b)| b), Ok(9));
+ /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7));
+ /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13));
+ /// let r = s.binary_search_by_key(&1, |&(a,b)| b);
+ /// assert!(match r { Ok(1...4) => true, _ => false, });
+ /// ```
+ #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
+ #[inline]
+ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result<usize, usize>
+ where F: FnMut(&'a T) -> B,
+ B: Ord
+ {
+ SliceExt::binary_search_by_key(self, b, f)
+ }
+
+ /// Sorts the slice, but may not preserve the order of equal elements.
+ ///
+ /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
+ /// and `O(n log n)` worst-case.
+ ///
+ /// # Current implementation
+ ///
+ /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
+ /// which combines the fast average case of randomized quicksort with the fast worst case of
+ /// heapsort, while achieving linear time on slices with certain patterns. It uses some
+ /// randomization to avoid degenerate cases, but with a fixed seed to always provide
+ /// deterministic behavior.
+ ///
+ /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
+ /// slice consists of several concatenated sorted sequences.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [-5, 4, 1, -3, 2];
+ ///
+ /// v.sort_unstable();
+ /// assert!(v == [-5, -3, 1, 2, 4]);
+ /// ```
+ ///
+ /// [pdqsort]: https://github.com/orlp/pdqsort
+ #[stable(feature = "sort_unstable", since = "1.20.0")]
+ #[inline]
+ pub fn sort_unstable(&mut self)
+ where T: Ord
+ {
+ SliceExt::sort_unstable(self);
+ }
+
+ /// Sorts the slice with a comparator function, but may not preserve the order of equal
+ /// elements.
+ ///
+ /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
+ /// and `O(n log n)` worst-case.
+ ///
+ /// # Current implementation
+ ///
+ /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
+ /// which combines the fast average case of randomized quicksort with the fast worst case of
+ /// heapsort, while achieving linear time on slices with certain patterns. It uses some
+ /// randomization to avoid degenerate cases, but with a fixed seed to always provide
+ /// deterministic behavior.
+ ///
+ /// It is typically faster than stable sorting, except in a few special cases, e.g. when the
+ /// slice consists of several concatenated sorted sequences.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [5, 4, 1, 3, 2];
+ /// v.sort_unstable_by(|a, b| a.cmp(b));
+ /// assert!(v == [1, 2, 3, 4, 5]);
+ ///
+ /// // reverse sorting
+ /// v.sort_unstable_by(|a, b| b.cmp(a));
+ /// assert!(v == [5, 4, 3, 2, 1]);
+ /// ```
+ ///
+ /// [pdqsort]: https://github.com/orlp/pdqsort
+ #[stable(feature = "sort_unstable", since = "1.20.0")]
+ #[inline]
+ pub fn sort_unstable_by<F>(&mut self, compare: F)
+ where F: FnMut(&T, &T) -> Ordering
+ {
+ SliceExt::sort_unstable_by(self, compare);
+ }
+
+ /// Sorts the slice with a key extraction function, but may not preserve the order of equal
+ /// elements.
+ ///
+ /// This sort is unstable (i.e. may reorder equal elements), in-place (i.e. does not allocate),
+ /// and `O(m n log(m n))` worst-case, where the key function is `O(m)`.
+ ///
+ /// # Current implementation
+ ///
+ /// The current algorithm is based on [pattern-defeating quicksort][pdqsort] by Orson Peters,
+ /// which combines the fast average case of randomized quicksort with the fast worst case of
+ /// heapsort, while achieving linear time on slices with certain patterns. It uses some
+ /// randomization to avoid degenerate cases, but with a fixed seed to always provide
+ /// deterministic behavior.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = [-5i32, 4, 1, -3, 2];
+ ///
+ /// v.sort_unstable_by_key(|k| k.abs());
+ /// assert!(v == [1, 2, -3, 4, -5]);
+ /// ```
+ ///
+ /// [pdqsort]: https://github.com/orlp/pdqsort
+ #[stable(feature = "sort_unstable", since = "1.20.0")]
+ #[inline]
+ pub fn sort_unstable_by_key<K, F>(&mut self, f: F)
+ where F: FnMut(&T) -> K, K: Ord
+ {
+ SliceExt::sort_unstable_by_key(self, f);
+ }
+
+ /// Rotates the slice in-place such that the first `mid` elements of the
+ /// slice move to the end while the last `self.len() - mid` elements move to
+ /// the front. After calling `rotate_left`, the element previously at index
+ /// `mid` will become the first element in the slice.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `mid` is greater than the length of the
+ /// slice. Note that `mid == self.len()` does _not_ panic and is a no-op
+ /// rotation.
+ ///
+ /// # Complexity
+ ///
+ /// Takes linear (in `self.len()`) time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a.rotate_left(2);
+ /// assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
+ /// ```
+ ///
+ /// Rotating a subslice:
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a[1..5].rotate_left(1);
+ /// assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
+ /// ```
+ #[stable(feature = "slice_rotate", since = "1.26.0")]
+ pub fn rotate_left(&mut self, mid: usize) {
+ SliceExt::rotate_left(self, mid);
+ }
+
+ /// Rotates the slice in-place such that the first `self.len() - k`
+ /// elements of the slice move to the end while the last `k` elements move
+ /// to the front. After calling `rotate_right`, the element previously at
+ /// index `self.len() - k` will become the first element in the slice.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if `k` is greater than the length of the
+ /// slice. Note that `k == self.len()` does _not_ panic and is a no-op
+ /// rotation.
+ ///
+ /// # Complexity
+ ///
+ /// Takes linear (in `self.len()`) time.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a.rotate_right(2);
+ /// assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']);
+ /// ```
+ ///
+ /// Rotate a subslice:
+ ///
+ /// ```
+ /// let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+ /// a[1..5].rotate_right(1);
+ /// assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
+ /// ```
+ #[stable(feature = "slice_rotate", since = "1.26.0")]
+ pub fn rotate_right(&mut self, k: usize) {
+ SliceExt::rotate_right(self, k);
+ }
+
+ /// Copies the elements from `src` into `self`.
+ ///
+ /// The length of `src` must be the same as `self`.
+ ///
+ /// If `src` implements `Copy`, it can be more performant to use
+ /// [`copy_from_slice`].
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the two slices have different lengths.
+ ///
+ /// # Examples
+ ///
+ /// Cloning two elements from a slice into another:
+ ///
+ /// ```
+ /// let src = [1, 2, 3, 4];
+ /// let mut dst = [0, 0];
+ ///
+ /// dst.clone_from_slice(&src[2..]);
+ ///
+ /// assert_eq!(src, [1, 2, 3, 4]);
+ /// assert_eq!(dst, [3, 4]);
+ /// ```
+ ///
+ /// Rust enforces that there can only be one mutable reference with no
+ /// immutable references to a particular piece of data in a particular
+ /// scope. Because of this, attempting to use `clone_from_slice` on a
+ /// single slice will result in a compile failure:
+ ///
+ /// ```compile_fail
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// slice[..2].clone_from_slice(&slice[3..]); // compile fail!
+ /// ```
+ ///
+ /// To work around this, we can use [`split_at_mut`] to create two distinct
+ /// sub-slices from a slice:
+ ///
+ /// ```
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// {
+ /// let (left, right) = slice.split_at_mut(2);
+ /// left.clone_from_slice(&right[1..]);
+ /// }
+ ///
+ /// assert_eq!(slice, [4, 5, 3, 4, 5]);
+ /// ```
+ ///
+ /// [`copy_from_slice`]: #method.copy_from_slice
+ /// [`split_at_mut`]: #method.split_at_mut
+ #[stable(feature = "clone_from_slice", since = "1.7.0")]
+ pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone {
+ SliceExt::clone_from_slice(self, src)
+ }
+
+ /// Copies all elements from `src` into `self`, using a memcpy.
+ ///
+ /// The length of `src` must be the same as `self`.
+ ///
+ /// If `src` does not implement `Copy`, use [`clone_from_slice`].
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the two slices have different lengths.
+ ///
+ /// # Examples
+ ///
+ /// Copying two elements from a slice into another:
+ ///
+ /// ```
+ /// let src = [1, 2, 3, 4];
+ /// let mut dst = [0, 0];
+ ///
+ /// dst.copy_from_slice(&src[2..]);
+ ///
+ /// assert_eq!(src, [1, 2, 3, 4]);
+ /// assert_eq!(dst, [3, 4]);
+ /// ```
+ ///
+ /// Rust enforces that there can only be one mutable reference with no
+ /// immutable references to a particular piece of data in a particular
+ /// scope. Because of this, attempting to use `copy_from_slice` on a
+ /// single slice will result in a compile failure:
+ ///
+ /// ```compile_fail
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// slice[..2].copy_from_slice(&slice[3..]); // compile fail!
+ /// ```
+ ///
+ /// To work around this, we can use [`split_at_mut`] to create two distinct
+ /// sub-slices from a slice:
+ ///
+ /// ```
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// {
+ /// let (left, right) = slice.split_at_mut(2);
+ /// left.copy_from_slice(&right[1..]);
+ /// }
+ ///
+ /// assert_eq!(slice, [4, 5, 3, 4, 5]);
+ /// ```
+ ///
+ /// [`clone_from_slice`]: #method.clone_from_slice
+ /// [`split_at_mut`]: #method.split_at_mut
+ #[stable(feature = "copy_from_slice", since = "1.9.0")]
+ pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy {
+ SliceExt::copy_from_slice(self, src)
+ }
+
+ /// Swaps all elements in `self` with those in `other`.
+ ///
+ /// The length of `other` must be the same as `self`.
+ ///
+ /// # Panics
+ ///
+ /// This function will panic if the two slices have different lengths.
+ ///
+ /// # Example
+ ///
+ /// Swapping two elements across slices:
+ ///
+ /// ```
+ /// let mut slice1 = [0, 0];
+ /// let mut slice2 = [1, 2, 3, 4];
+ ///
+ /// slice1.swap_with_slice(&mut slice2[2..]);
+ ///
+ /// assert_eq!(slice1, [3, 4]);
+ /// assert_eq!(slice2, [1, 2, 0, 0]);
+ /// ```
+ ///
+ /// Rust enforces that there can only be one mutable reference to a
+ /// particular piece of data in a particular scope. Because of this,
+ /// attempting to use `swap_with_slice` on a single slice will result in
+ /// a compile failure:
+ ///
+ /// ```compile_fail
+ /// let mut slice = [1, 2, 3, 4, 5];
+ /// slice[..2].swap_with_slice(&mut slice[3..]); // compile fail!
+ /// ```
+ ///
+ /// To work around this, we can use [`split_at_mut`] to create two distinct
+ /// mutable sub-slices from a slice:
+ ///
+ /// ```
+ /// let mut slice = [1, 2, 3, 4, 5];
+ ///
+ /// {
+ /// let (left, right) = slice.split_at_mut(2);
+ /// left.swap_with_slice(&mut right[1..]);
+ /// }
+ ///
+ /// assert_eq!(slice, [4, 5, 3, 1, 2]);
+ /// ```
+ ///
+ /// [`split_at_mut`]: #method.split_at_mut
+ #[stable(feature = "swap_with_slice", since = "1.27.0")]
+ pub fn swap_with_slice(&mut self, other: &mut [T]) {
+ SliceExt::swap_with_slice(self, other)
+ }
+}}
+
+#[lang = "slice"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl<T> [T] {
+ slice_core_methods!();
+}
+
+// FIXME: remove (inline) this macro
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_slice_ext", issue = "32110")]
+macro_rules! slice_u8_core_methods { () => {
+ /// Checks if all bytes in this slice are within the ASCII range.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ self.iter().all(|b| b.is_ascii())
+ }
+
+ /// Checks that two slices are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
+ self.len() == other.len() &&
+ self.iter().zip(other).all(|(a, b)| {
+ a.eq_ignore_ascii_case(b)
+ })
+ }
+
+ /// Converts this slice to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn make_ascii_uppercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_uppercase();
+ }
+ }
+
+ /// Converts this slice to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn make_ascii_lowercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_lowercase();
+ }
+ }
+}}
+
+#[lang = "slice_u8"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl [u8] {
+ slice_u8_core_methods!();
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
impl<T, I> ops::Index<I> for [T]
///
/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit
/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool {
inner: Split<'a, T, P>
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RSplit")
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
type Item = &'a [T];
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
#[inline]
fn next_back(&mut self) -> Option<&'a [T]> {
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
#[inline]
fn finish(&mut self) -> Option<&'a [T]> {
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {}
/// An iterator over the subslices of the vector which are separated
///
/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut
/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool {
inner: SplitMut<'a, T, P>
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RSplitMut")
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
#[inline]
fn finish(&mut self) -> Option<&'a mut [T]> {
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
type Item = &'a mut [T];
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where
P: FnMut(&T) -> bool,
{
}
}
-#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {}
/// An private iterator over subslices separated by elements that
fn index(self, slice: &str) -> &Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
- let end = self.end + 1;
- self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
+ (..self.end+1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
assert!(self.end != usize::max_value(),
"attempted to index str up to maximum usize");
- if slice.is_char_boundary(self.end) {
- unsafe { self.get_unchecked_mut(slice) }
- } else {
- super::slice_error_fail(slice, 0, self.end + 1)
- }
+ (..self.end+1).index_mut(slice)
}
}
}
-
+public_in_stage0! {
+{
/// Methods for string slices
#[allow(missing_docs)]
#[doc(hidden)]
#[unstable(feature = "core_str_ext",
reason = "stable interface provided by `impl str` in later crates",
issue = "32110")]
-pub trait StrExt {
+}
+trait StrExt {
// NB there are no docs here are they're all located on the StrExt trait in
// liballoc, not here.
fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
#[stable(feature = "split_whitespace", since = "1.1.0")]
fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>;
- #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
- fn is_whitespace(&self) -> bool;
- #[stable(feature = "unicode_methods_on_intrinsics", since = "1.27.0")]
- fn is_alphanumeric(&self) -> bool;
#[stable(feature = "rust1", since = "1.0.0")]
fn trim(&self) -> &str;
#[stable(feature = "rust1", since = "1.0.0")]
fn trim_left(&self) -> &str;
#[stable(feature = "rust1", since = "1.0.0")]
fn trim_right(&self) -> &str;
-}
+}}
// truncate `&str` to length at most equal to `max`
// return `true` if it were truncated, and the new str.
SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) }
}
- #[inline]
- fn is_whitespace(&self) -> bool {
- self.chars().all(|c| c.is_whitespace())
- }
-
- #[inline]
- fn is_alphanumeric(&self) -> bool {
- self.chars().all(|c| c.is_alphanumeric())
- }
-
#[inline]
fn trim(&self) -> &str {
self.trim_matches(|c: char| c.is_whitespace())
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl AsRef<[u8]> for str {
+// FIXME: remove (inline) this macro and the SliceExt trait
+// when updating to a bootstrap compiler that has the new lang items.
+#[cfg_attr(stage0, macro_export)]
+#[unstable(feature = "core_str_ext", issue = "32110")]
+macro_rules! str_core_methods { () => {
+ /// Returns the length of `self`.
+ ///
+ /// This length is in bytes, not [`char`]s or graphemes. In other words,
+ /// it may not be what a human considers the length of the string.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let len = "foo".len();
+ /// assert_eq!(3, len);
+ ///
+ /// let len = "ƒoo".len(); // fancy f!
+ /// assert_eq!(4, len);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- fn as_ref(&self) -> &[u8] {
- self.as_bytes()
+ pub fn len(&self) -> usize {
+ StrExt::len(self)
}
-}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Default for &'a str {
- /// Creates an empty str
- fn default() -> &'a str { "" }
-}
+ /// Returns `true` if `self` has a length of zero bytes.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "";
+ /// assert!(s.is_empty());
+ ///
+ /// let s = "not empty";
+ /// assert!(!s.is_empty());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ StrExt::is_empty(self)
+ }
-/// An iterator over the non-whitespace substrings of a string,
-/// separated by any amount of whitespace.
-///
-/// This struct is created by the [`split_whitespace`] method on [`str`].
-/// See its documentation for more.
-///
-/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace
-/// [`str`]: ../../std/primitive.str.html
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-#[derive(Clone, Debug)]
-pub struct SplitWhitespace<'a> {
- inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>,
-}
+ /// Checks that `index`-th byte lies at the start and/or end of a
+ /// UTF-8 code point sequence.
+ ///
+ /// The start and end of the string (when `index == self.len()`) are
+ /// considered to be
+ /// boundaries.
+ ///
+ /// Returns `false` if `index` is greater than `self.len()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// assert!(s.is_char_boundary(0));
+ /// // start of `老`
+ /// assert!(s.is_char_boundary(6));
+ /// assert!(s.is_char_boundary(s.len()));
+ ///
+ /// // second byte of `ö`
+ /// assert!(!s.is_char_boundary(2));
+ ///
+ /// // third byte of `老`
+ /// assert!(!s.is_char_boundary(8));
+ /// ```
+ #[stable(feature = "is_char_boundary", since = "1.9.0")]
+ #[inline]
+ pub fn is_char_boundary(&self, index: usize) -> bool {
+ StrExt::is_char_boundary(self, index)
+ }
-#[derive(Clone)]
-struct IsWhitespace;
+ /// Converts a string slice to a byte slice. To convert the byte slice back
+ /// into a string slice, use the [`str::from_utf8`] function.
+ ///
+ /// [`str::from_utf8`]: ./str/fn.from_utf8.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bytes = "bors".as_bytes();
+ /// assert_eq!(b"bors", bytes);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline(always)]
+ pub fn as_bytes(&self) -> &[u8] {
+ StrExt::as_bytes(self)
+ }
-impl FnOnce<(char, )> for IsWhitespace {
- type Output = bool;
+ /// Converts a mutable string slice to a mutable byte slice. To convert the
+ /// mutable byte slice back into a mutable string slice, use the
+ /// [`str::from_utf8_mut`] function.
+ ///
+ /// [`str::from_utf8_mut`]: ./str/fn.from_utf8_mut.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut s = String::from("Hello");
+ /// let bytes = unsafe { s.as_bytes_mut() };
+ ///
+ /// assert_eq!(b"Hello", bytes);
+ /// ```
+ ///
+ /// Mutability:
+ ///
+ /// ```
+ /// let mut s = String::from("🗻∈🌏");
+ ///
+ /// unsafe {
+ /// let bytes = s.as_bytes_mut();
+ ///
+ /// bytes[0] = 0xF0;
+ /// bytes[1] = 0x9F;
+ /// bytes[2] = 0x8D;
+ /// bytes[3] = 0x94;
+ /// }
+ ///
+ /// assert_eq!("🍔∈🌏", s);
+ /// ```
+ #[stable(feature = "str_mut_extras", since = "1.20.0")]
+ #[inline(always)]
+ pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+ StrExt::as_bytes_mut(self)
+ }
+ /// Converts a string slice to a raw pointer.
+ ///
+ /// As string slices are a slice of bytes, the raw pointer points to a
+ /// [`u8`]. This pointer will be pointing to the first byte of the string
+ /// slice.
+ ///
+ /// [`u8`]: primitive.u8.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "Hello";
+ /// let ptr = s.as_ptr();
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool {
- self.call_mut(arg)
+ pub fn as_ptr(&self) -> *const u8 {
+ StrExt::as_ptr(self)
}
-}
-impl FnMut<(char, )> for IsWhitespace {
+ /// Returns a subslice of `str`.
+ ///
+ /// This is the non-panicking alternative to indexing the `str`. Returns
+ /// [`None`] whenever equivalent indexing operation would panic.
+ ///
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = String::from("🗻∈🌏");
+ ///
+ /// assert_eq!(Some("🗻"), v.get(0..4));
+ ///
+ /// // indices not on UTF-8 sequence boundaries
+ /// assert!(v.get(1..).is_none());
+ /// assert!(v.get(..8).is_none());
+ ///
+ /// // out of bounds
+ /// assert!(v.get(..42).is_none());
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
- extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool {
- arg.0.is_whitespace()
+ pub fn get<I: SliceIndex<str>>(&self, i: I) -> Option<&I::Output> {
+ StrExt::get(self, i)
}
-}
-
-#[derive(Clone)]
-struct IsNotEmpty;
-impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty {
- type Output = bool;
+ /// Returns a mutable subslice of `str`.
+ ///
+ /// This is the non-panicking alternative to indexing the `str`. Returns
+ /// [`None`] whenever equivalent indexing operation would panic.
+ ///
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = String::from("hello");
+ /// // correct length
+ /// assert!(v.get_mut(0..5).is_some());
+ /// // out of bounds
+ /// assert!(v.get_mut(..42).is_none());
+ /// assert_eq!(Some("he"), v.get_mut(0..2).map(|v| &*v));
+ ///
+ /// assert_eq!("hello", v);
+ /// {
+ /// let s = v.get_mut(0..2);
+ /// let s = s.map(|s| {
+ /// s.make_ascii_uppercase();
+ /// &*s
+ /// });
+ /// assert_eq!(Some("HE"), s);
+ /// }
+ /// assert_eq!("HEllo", v);
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
+ #[inline]
+ pub fn get_mut<I: SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output> {
+ StrExt::get_mut(self, i)
+ }
+ /// Returns a unchecked subslice of `str`.
+ ///
+ /// This is the unchecked alternative to indexing the `str`.
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that these preconditions are
+ /// satisfied:
+ ///
+ /// * The starting index must come before the ending index;
+ /// * Indexes must be within bounds of the original slice;
+ /// * Indexes must lie on UTF-8 sequence boundaries.
+ ///
+ /// Failing that, the returned string slice may reference invalid memory or
+ /// violate the invariants communicated by the `str` type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v = "🗻∈🌏";
+ /// unsafe {
+ /// assert_eq!("🗻", v.get_unchecked(0..4));
+ /// assert_eq!("∈", v.get_unchecked(4..7));
+ /// assert_eq!("🌏", v.get_unchecked(7..11));
+ /// }
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
- extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool {
- self.call_mut(arg)
+ pub unsafe fn get_unchecked<I: SliceIndex<str>>(&self, i: I) -> &I::Output {
+ StrExt::get_unchecked(self, i)
}
-}
-impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty {
+ /// Returns a mutable, unchecked subslice of `str`.
+ ///
+ /// This is the unchecked alternative to indexing the `str`.
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that these preconditions are
+ /// satisfied:
+ ///
+ /// * The starting index must come before the ending index;
+ /// * Indexes must be within bounds of the original slice;
+ /// * Indexes must lie on UTF-8 sequence boundaries.
+ ///
+ /// Failing that, the returned string slice may reference invalid memory or
+ /// violate the invariants communicated by the `str` type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let mut v = String::from("🗻∈🌏");
+ /// unsafe {
+ /// assert_eq!("🗻", v.get_unchecked_mut(0..4));
+ /// assert_eq!("∈", v.get_unchecked_mut(4..7));
+ /// assert_eq!("🌏", v.get_unchecked_mut(7..11));
+ /// }
+ /// ```
+ #[stable(feature = "str_checked_slicing", since = "1.20.0")]
#[inline]
- extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool {
- !arg.0.is_empty()
+ pub unsafe fn get_unchecked_mut<I: SliceIndex<str>>(&mut self, i: I) -> &mut I::Output {
+ StrExt::get_unchecked_mut(self, i)
}
-}
+ /// Creates a string slice from another string slice, bypassing safety
+ /// checks.
+ ///
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`str`] and [`Index`].
+ ///
+ /// [`str`]: primitive.str.html
+ /// [`Index`]: ops/trait.Index.html
+ ///
+ /// This new slice goes from `begin` to `end`, including `begin` but
+ /// excluding `end`.
+ ///
+ /// To get a mutable string slice instead, see the
+ /// [`slice_mut_unchecked`] method.
+ ///
+ /// [`slice_mut_unchecked`]: #method.slice_mut_unchecked
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that three preconditions are
+ /// satisfied:
+ ///
+ /// * `begin` must come before `end`.
+ /// * `begin` and `end` must be byte positions within the string slice.
+ /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// unsafe {
+ /// assert_eq!("Löwe 老虎 Léopard", s.slice_unchecked(0, 21));
+ /// }
+ ///
+ /// let s = "Hello, world!";
+ ///
+ /// unsafe {
+ /// assert_eq!("world", s.slice_unchecked(7, 12));
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
+ StrExt::slice_unchecked(self, begin, end)
+ }
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-impl<'a> Iterator for SplitWhitespace<'a> {
- type Item = &'a str;
+ /// Creates a string slice from another string slice, bypassing safety
+ /// checks.
+ /// This is generally not recommended, use with caution! For a safe
+ /// alternative see [`str`] and [`IndexMut`].
+ ///
+ /// [`str`]: primitive.str.html
+ /// [`IndexMut`]: ops/trait.IndexMut.html
+ ///
+ /// This new slice goes from `begin` to `end`, including `begin` but
+ /// excluding `end`.
+ ///
+ /// To get an immutable string slice instead, see the
+ /// [`slice_unchecked`] method.
+ ///
+ /// [`slice_unchecked`]: #method.slice_unchecked
+ ///
+ /// # Safety
+ ///
+ /// Callers of this function are responsible that three preconditions are
+ /// satisfied:
+ ///
+ /// * `begin` must come before `end`.
+ /// * `begin` and `end` must be byte positions within the string slice.
+ /// * `begin` and `end` must lie on UTF-8 sequence boundaries.
+ #[stable(feature = "str_slice_mut", since = "1.5.0")]
+ #[inline]
+ pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
+ StrExt::slice_mut_unchecked(self, begin, end)
+ }
- fn next(&mut self) -> Option<&'a str> {
- self.inner.next()
+ /// Divide one string slice into two at an index.
+ ///
+ /// The argument, `mid`, should be a byte offset from the start of the
+ /// string. It must also be on the boundary of a UTF-8 code point.
+ ///
+ /// The two slices returned go from the start of the string slice to `mid`,
+ /// and from `mid` to the end of the string slice.
+ ///
+ /// To get mutable string slices instead, see the [`split_at_mut`]
+ /// method.
+ ///
+ /// [`split_at_mut`]: #method.split_at_mut
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
+ /// beyond the last code point of the string slice.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = "Per Martin-Löf";
+ ///
+ /// let (first, last) = s.split_at(3);
+ ///
+ /// assert_eq!("Per", first);
+ /// assert_eq!(" Martin-Löf", last);
+ /// ```
+ #[inline]
+ #[stable(feature = "str_split_at", since = "1.4.0")]
+ pub fn split_at(&self, mid: usize) -> (&str, &str) {
+ StrExt::split_at(self, mid)
}
-}
-#[stable(feature = "split_whitespace", since = "1.1.0")]
-impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
- fn next_back(&mut self) -> Option<&'a str> {
- self.inner.next_back()
+ /// Divide one mutable string slice into two at an index.
+ ///
+ /// The argument, `mid`, should be a byte offset from the start of the
+ /// string. It must also be on the boundary of a UTF-8 code point.
+ ///
+ /// The two slices returned go from the start of the string slice to `mid`,
+ /// and from `mid` to the end of the string slice.
+ ///
+ /// To get immutable string slices instead, see the [`split_at`] method.
+ ///
+ /// [`split_at`]: #method.split_at
+ ///
+ /// # Panics
+ ///
+ /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is
+ /// beyond the last code point of the string slice.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut s = "Per Martin-Löf".to_string();
+ /// {
+ /// let (first, last) = s.split_at_mut(3);
+ /// first.make_ascii_uppercase();
+ /// assert_eq!("PER", first);
+ /// assert_eq!(" Martin-Löf", last);
+ /// }
+ /// assert_eq!("PER Martin-Löf", s);
+ /// ```
+ #[inline]
+ #[stable(feature = "str_split_at", since = "1.4.0")]
+ pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
+ StrExt::split_at_mut(self, mid)
}
-}
-#[stable(feature = "fused", since = "1.26.0")]
-impl<'a> FusedIterator for SplitWhitespace<'a> {}
+ /// Returns an iterator over the [`char`]s of a string slice.
+ ///
+ /// As a string slice consists of valid UTF-8, we can iterate through a
+ /// string slice by [`char`]. This method returns such an iterator.
+ ///
+ /// It's important to remember that [`char`] represents a Unicode Scalar
+ /// Value, and may not match your idea of what a 'character' is. Iteration
+ /// over grapheme clusters may be what you actually want.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let word = "goodbye";
+ ///
+ /// let count = word.chars().count();
+ /// assert_eq!(7, count);
+ ///
+ /// let mut chars = word.chars();
+ ///
+ /// assert_eq!(Some('g'), chars.next());
+ /// assert_eq!(Some('o'), chars.next());
+ /// assert_eq!(Some('o'), chars.next());
+ /// assert_eq!(Some('d'), chars.next());
+ /// assert_eq!(Some('b'), chars.next());
+ /// assert_eq!(Some('y'), chars.next());
+ /// assert_eq!(Some('e'), chars.next());
+ ///
+ /// assert_eq!(None, chars.next());
+ /// ```
+ ///
+ /// Remember, [`char`]s may not match your human intuition about characters:
+ ///
+ /// ```
+ /// let y = "y̆";
+ ///
+ /// let mut chars = y.chars();
+ ///
+ /// assert_eq!(Some('y'), chars.next()); // not 'y̆'
+ /// assert_eq!(Some('\u{0306}'), chars.next());
+ ///
+ /// assert_eq!(None, chars.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn chars(&self) -> Chars {
+ StrExt::chars(self)
+ }
+ /// Returns an iterator over the [`char`]s of a string slice, and their
+ /// positions.
+ ///
+ /// As a string slice consists of valid UTF-8, we can iterate through a
+ /// string slice by [`char`]. This method returns an iterator of both
+ /// these [`char`]s, as well as their byte positions.
+ ///
+ /// The iterator yields tuples. The position is first, the [`char`] is
+ /// second.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let word = "goodbye";
+ ///
+ /// let count = word.char_indices().count();
+ /// assert_eq!(7, count);
+ ///
+ /// let mut char_indices = word.char_indices();
+ ///
+ /// assert_eq!(Some((0, 'g')), char_indices.next());
+ /// assert_eq!(Some((1, 'o')), char_indices.next());
+ /// assert_eq!(Some((2, 'o')), char_indices.next());
+ /// assert_eq!(Some((3, 'd')), char_indices.next());
+ /// assert_eq!(Some((4, 'b')), char_indices.next());
+ /// assert_eq!(Some((5, 'y')), char_indices.next());
+ /// assert_eq!(Some((6, 'e')), char_indices.next());
+ ///
+ /// assert_eq!(None, char_indices.next());
+ /// ```
+ ///
+ /// Remember, [`char`]s may not match your human intuition about characters:
+ ///
+ /// ```
+ /// let yes = "y̆es";
+ ///
+ /// let mut char_indices = yes.char_indices();
+ ///
+ /// assert_eq!(Some((0, 'y')), char_indices.next()); // not (0, 'y̆')
+ /// assert_eq!(Some((1, '\u{0306}')), char_indices.next());
+ ///
+ /// // note the 3 here - the last character took up two bytes
+ /// assert_eq!(Some((3, 'e')), char_indices.next());
+ /// assert_eq!(Some((4, 's')), char_indices.next());
+ ///
+ /// assert_eq!(None, char_indices.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn char_indices(&self) -> CharIndices {
+ StrExt::char_indices(self)
+ }
+
+ /// An iterator over the bytes of a string slice.
+ ///
+ /// As a string slice consists of a sequence of bytes, we can iterate
+ /// through a string slice by byte. This method returns such an iterator.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut bytes = "bors".bytes();
+ ///
+ /// assert_eq!(Some(b'b'), bytes.next());
+ /// assert_eq!(Some(b'o'), bytes.next());
+ /// assert_eq!(Some(b'r'), bytes.next());
+ /// assert_eq!(Some(b's'), bytes.next());
+ ///
+ /// assert_eq!(None, bytes.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn bytes(&self) -> Bytes {
+ StrExt::bytes(self)
+ }
+
+ /// Split a string slice by whitespace.
+ ///
+ /// The iterator returned will return string slices that are sub-slices of
+ /// the original string slice, separated by any amount of whitespace.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let mut iter = "A few words".split_whitespace();
+ ///
+ /// assert_eq!(Some("A"), iter.next());
+ /// assert_eq!(Some("few"), iter.next());
+ /// assert_eq!(Some("words"), iter.next());
+ ///
+ /// assert_eq!(None, iter.next());
+ /// ```
+ ///
+ /// All kinds of whitespace are considered:
+ ///
+ /// ```
+ /// let mut iter = " Mary had\ta\u{2009}little \n\t lamb".split_whitespace();
+ /// assert_eq!(Some("Mary"), iter.next());
+ /// assert_eq!(Some("had"), iter.next());
+ /// assert_eq!(Some("a"), iter.next());
+ /// assert_eq!(Some("little"), iter.next());
+ /// assert_eq!(Some("lamb"), iter.next());
+ ///
+ /// assert_eq!(None, iter.next());
+ /// ```
+ #[stable(feature = "split_whitespace", since = "1.1.0")]
+ #[inline]
+ pub fn split_whitespace(&self) -> SplitWhitespace {
+ StrExt::split_whitespace(self)
+ }
+
+ /// An iterator over the lines of a string, as string slices.
+ ///
+ /// Lines are ended with either a newline (`\n`) or a carriage return with
+ /// a line feed (`\r\n`).
+ ///
+ /// The final line ending is optional.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let text = "foo\r\nbar\n\nbaz\n";
+ /// let mut lines = text.lines();
+ ///
+ /// assert_eq!(Some("foo"), lines.next());
+ /// assert_eq!(Some("bar"), lines.next());
+ /// assert_eq!(Some(""), lines.next());
+ /// assert_eq!(Some("baz"), lines.next());
+ ///
+ /// assert_eq!(None, lines.next());
+ /// ```
+ ///
+ /// The final line ending isn't required:
+ ///
+ /// ```
+ /// let text = "foo\nbar\n\r\nbaz";
+ /// let mut lines = text.lines();
+ ///
+ /// assert_eq!(Some("foo"), lines.next());
+ /// assert_eq!(Some("bar"), lines.next());
+ /// assert_eq!(Some(""), lines.next());
+ /// assert_eq!(Some("baz"), lines.next());
+ ///
+ /// assert_eq!(None, lines.next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn lines(&self) -> Lines {
+ StrExt::lines(self)
+ }
+
+ /// An iterator over the lines of a string.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_deprecated(since = "1.4.0", reason = "use lines() instead now")]
+ #[inline]
+ #[allow(deprecated)]
+ pub fn lines_any(&self) -> LinesAny {
+ StrExt::lines_any(self)
+ }
+
+ /// Returns an iterator of `u16` over the string encoded as UTF-16.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let text = "Zażółć gęślą jaźń";
+ ///
+ /// let utf8_len = text.len();
+ /// let utf16_len = text.encode_utf16().count();
+ ///
+ /// assert!(utf16_len <= utf8_len);
+ /// ```
+ #[stable(feature = "encode_utf16", since = "1.8.0")]
+ pub fn encode_utf16(&self) -> EncodeUtf16 {
+ EncodeUtf16::new(self)
+ }
+
+ /// Returns `true` if the given pattern matches a sub-slice of
+ /// this string slice.
+ ///
+ /// Returns `false` if it does not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bananas = "bananas";
+ ///
+ /// assert!(bananas.contains("nana"));
+ /// assert!(!bananas.contains("apples"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ StrExt::contains(self, pat)
+ }
+
+ /// Returns `true` if the given pattern matches a prefix of this
+ /// string slice.
+ ///
+ /// Returns `false` if it does not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bananas = "bananas";
+ ///
+ /// assert!(bananas.starts_with("bana"));
+ /// assert!(!bananas.starts_with("nana"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
+ StrExt::starts_with(self, pat)
+ }
+
+ /// Returns `true` if the given pattern matches a suffix of this
+ /// string slice.
+ ///
+ /// Returns `false` if it does not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let bananas = "bananas";
+ ///
+ /// assert!(bananas.ends_with("anas"));
+ /// assert!(!bananas.ends_with("nana"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::ends_with(self, pat)
+ }
+
+ /// Returns the byte index of the first character of this string slice that
+ /// matches the pattern.
+ ///
+ /// Returns [`None`] if the pattern doesn't match.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.find('L'), Some(0));
+ /// assert_eq!(s.find('é'), Some(14));
+ /// assert_eq!(s.find("Léopard"), Some(13));
+ /// ```
+ ///
+ /// More complex patterns using point-free style and closures:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.find(char::is_whitespace), Some(5));
+ /// assert_eq!(s.find(char::is_lowercase), Some(1));
+ /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1));
+ /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4));
+ /// ```
+ ///
+ /// Not finding the pattern:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// let x: &[_] = &['1', '2'];
+ ///
+ /// assert_eq!(s.find(x), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
+ StrExt::find(self, pat)
+ }
+
+ /// Returns the byte index of the last character of this string slice that
+ /// matches the pattern.
+ ///
+ /// Returns [`None`] if the pattern doesn't match.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ /// [`None`]: option/enum.Option.html#variant.None
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.rfind('L'), Some(13));
+ /// assert_eq!(s.rfind('é'), Some(14));
+ /// ```
+ ///
+ /// More complex patterns with closures:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ ///
+ /// assert_eq!(s.rfind(char::is_whitespace), Some(12));
+ /// assert_eq!(s.rfind(char::is_lowercase), Some(20));
+ /// ```
+ ///
+ /// Not finding the pattern:
+ ///
+ /// ```
+ /// let s = "Löwe 老虎 Léopard";
+ /// let x: &[_] = &['1', '2'];
+ ///
+ /// assert_eq!(s.rfind(x), None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rfind(self, pat)
+ }
+
+ /// An iterator over substrings of this string slice, separated by
+ /// characters matched by a pattern.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rsplit`] method can be used.
+ ///
+ /// [`char`]: primitive.char.html
+ /// [`rsplit`]: #method.rsplit
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".split(' ').collect();
+ /// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
+ ///
+ /// let v: Vec<&str> = "".split('X').collect();
+ /// assert_eq!(v, [""]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".split('X').collect();
+ /// assert_eq!(v, ["lion", "", "tiger", "leopard"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".split("::").collect();
+ /// assert_eq!(v, ["lion", "tiger", "leopard"]);
+ ///
+ /// let v: Vec<&str> = "abc1def2ghi".split(char::is_numeric).collect();
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
+ ///
+ /// let v: Vec<&str> = "lionXtigerXleopard".split(char::is_uppercase).collect();
+ /// assert_eq!(v, ["lion", "tiger", "leopard"]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".split(|c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["abc", "def", "ghi"]);
+ /// ```
+ ///
+ /// If a string contains multiple contiguous separators, you will end up
+ /// with empty strings in the output:
+ ///
+ /// ```
+ /// let x = "||||a||b|c".to_string();
+ /// let d: Vec<_> = x.split('|').collect();
+ ///
+ /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
+ /// ```
+ ///
+ /// Contiguous separators are separated by the empty string.
+ ///
+ /// ```
+ /// let x = "(///)".to_string();
+ /// let d: Vec<_> = x.split('/').collect();
+ ///
+ /// assert_eq!(d, &["(", "", "", ")"]);
+ /// ```
+ ///
+ /// Separators at the start or end of a string are neighbored
+ /// by empty strings.
+ ///
+ /// ```
+ /// let d: Vec<_> = "010".split("0").collect();
+ /// assert_eq!(d, &["", "1", ""]);
+ /// ```
+ ///
+ /// When the empty string is used as a separator, it separates
+ /// every character in the string, along with the beginning
+ /// and end of the string.
+ ///
+ /// ```
+ /// let f: Vec<_> = "rust".split("").collect();
+ /// assert_eq!(f, &["", "r", "u", "s", "t", ""]);
+ /// ```
+ ///
+ /// Contiguous separators can lead to possibly surprising behavior
+ /// when whitespace is used as the separator. This code is correct:
+ ///
+ /// ```
+ /// let x = " a b c".to_string();
+ /// let d: Vec<_> = x.split(' ').collect();
+ ///
+ /// assert_eq!(d, &["", "", "", "", "a", "", "b", "c"]);
+ /// ```
+ ///
+ /// It does _not_ give you:
+ ///
+ /// ```,ignore
+ /// assert_eq!(d, &["a", "b", "c"]);
+ /// ```
+ ///
+ /// Use [`split_whitespace`] for this behavior.
+ ///
+ /// [`split_whitespace`]: #method.split_whitespace
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
+ StrExt::split(self, pat)
+ }
+
+ /// An iterator over substrings of the given string slice, separated by
+ /// characters matched by a pattern and yielded in reverse order.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a reverse
+ /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// For iterating from the front, the [`split`] method can be used.
+ ///
+ /// [`split`]: #method.split
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
+ /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
+ ///
+ /// let v: Vec<&str> = "".rsplit('X').collect();
+ /// assert_eq!(v, [""]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect();
+ /// assert_eq!(v, ["leopard", "tiger", "", "lion"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
+ /// assert_eq!(v, ["leopard", "tiger", "lion"]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["ghi", "def", "abc"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rsplit(self, pat)
+ }
+
+ /// An iterator over substrings of the given string slice, separated by
+ /// characters matched by a pattern.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// Equivalent to [`split`], except that the trailing substring
+ /// is skipped if empty.
+ ///
+ /// [`split`]: #method.split
+ ///
+ /// This method can be used for string data that is _terminated_,
+ /// rather than _separated_ by a pattern.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ /// [`char`]: primitive.char.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rsplit_terminator`] method can be used.
+ ///
+ /// [`rsplit_terminator`]: #method.rsplit_terminator
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "A.B.".split_terminator('.').collect();
+ /// assert_eq!(v, ["A", "B"]);
+ ///
+ /// let v: Vec<&str> = "A..B..".split_terminator(".").collect();
+ /// assert_eq!(v, ["A", "", "B", ""]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
+ StrExt::split_terminator(self, pat)
+ }
+
+ /// An iterator over substrings of `self`, separated by characters
+ /// matched by a pattern and yielded in reverse order.
+ ///
+ /// The pattern can be a simple `&str`, [`char`], or a closure that
+ /// determines the split.
+ /// Additional libraries might provide more complex patterns like
+ /// regular expressions.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// Equivalent to [`split`], except that the trailing substring is
+ /// skipped if empty.
+ ///
+ /// [`split`]: #method.split
+ ///
+ /// This method can be used for string data that is _terminated_,
+ /// rather than _separated_ by a pattern.
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a
+ /// reverse search, and it will be double ended if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// For iterating from the front, the [`split_terminator`] method can be
+ /// used.
+ ///
+ /// [`split_terminator`]: #method.split_terminator
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let v: Vec<&str> = "A.B.".rsplit_terminator('.').collect();
+ /// assert_eq!(v, ["B", "A"]);
+ ///
+ /// let v: Vec<&str> = "A..B..".rsplit_terminator(".").collect();
+ /// assert_eq!(v, ["", "B", "", "A"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rsplit_terminator(self, pat)
+ }
+
+ /// An iterator over substrings of the given string slice, separated by a
+ /// pattern, restricted to returning at most `n` items.
+ ///
+ /// If `n` substrings are returned, the last substring (the `n`th substring)
+ /// will contain the remainder of the string.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines the
+ /// split.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will not be double ended, because it is
+ /// not efficient to support.
+ ///
+ /// If the pattern allows a reverse search, the [`rsplitn`] method can be
+ /// used.
+ ///
+ /// [`rsplitn`]: #method.rsplitn
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lambda".splitn(3, ' ').collect();
+ /// assert_eq!(v, ["Mary", "had", "a little lambda"]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(3, "X").collect();
+ /// assert_eq!(v, ["lion", "", "tigerXleopard"]);
+ ///
+ /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
+ /// assert_eq!(v, ["abcXdef"]);
+ ///
+ /// let v: Vec<&str> = "".splitn(1, 'X').collect();
+ /// assert_eq!(v, [""]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".splitn(2, |c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["abc", "defXghi"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
+ StrExt::splitn(self, n, pat)
+ }
+
+ /// An iterator over substrings of this string slice, separated by a
+ /// pattern, starting from the end of the string, restricted to returning
+ /// at most `n` items.
+ ///
+ /// If `n` substrings are returned, the last substring (the `n`th substring)
+ /// will contain the remainder of the string.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that
+ /// determines the split.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will not be double ended, because it is not
+ /// efficient to support.
+ ///
+ /// For splitting from the front, the [`splitn`] method can be used.
+ ///
+ /// [`splitn`]: #method.splitn
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
+ /// assert_eq!(v, ["lamb", "little", "Mary had a"]);
+ ///
+ /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(3, 'X').collect();
+ /// assert_eq!(v, ["leopard", "tiger", "lionX"]);
+ ///
+ /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
+ /// assert_eq!(v, ["leopard", "lion::tiger"]);
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abc1defXghi".rsplitn(2, |c| c == '1' || c == 'X').collect();
+ /// assert_eq!(v, ["ghi", "abc1def"]);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rsplitn(self, n, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within the given string
+ /// slice.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that
+ /// determines if a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ /// [`char`]: primitive.char.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rmatches`] method can be used.
+ ///
+ /// [`rmatches`]: #method.rmatches
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abcXXXabcYYYabc".matches("abc").collect();
+ /// assert_eq!(v, ["abc", "abc", "abc"]);
+ ///
+ /// let v: Vec<&str> = "1abc2abc3".matches(char::is_numeric).collect();
+ /// assert_eq!(v, ["1", "2", "3"]);
+ /// ```
+ #[stable(feature = "str_matches", since = "1.2.0")]
+ #[inline]
+ pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
+ StrExt::matches(self, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within this string slice,
+ /// yielded in reverse order.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a reverse
+ /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// For iterating from the front, the [`matches`] method can be used.
+ ///
+ /// [`matches`]: #method.matches
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<&str> = "abcXXXabcYYYabc".rmatches("abc").collect();
+ /// assert_eq!(v, ["abc", "abc", "abc"]);
+ ///
+ /// let v: Vec<&str> = "1abc2abc3".rmatches(char::is_numeric).collect();
+ /// assert_eq!(v, ["3", "2", "1"]);
+ /// ```
+ #[stable(feature = "str_matches", since = "1.2.0")]
+ #[inline]
+ pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rmatches(self, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within this string
+ /// slice as well as the index that the match starts at.
+ ///
+ /// For matches of `pat` within `self` that overlap, only the indices
+ /// corresponding to the first match are returned.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines
+ /// if a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern
+ /// allows a reverse search and forward/reverse search yields the same
+ /// elements. This is true for, eg, [`char`] but not for `&str`.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// If the pattern allows a reverse search but its results might differ
+ /// from a forward search, the [`rmatch_indices`] method can be used.
+ ///
+ /// [`rmatch_indices`]: #method.rmatch_indices
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
+ /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
+ ///
+ /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
+ /// assert_eq!(v, [(1, "abc"), (4, "abc")]);
+ ///
+ /// let v: Vec<_> = "ababa".match_indices("aba").collect();
+ /// assert_eq!(v, [(0, "aba")]); // only the first `aba`
+ /// ```
+ #[stable(feature = "str_match_indices", since = "1.5.0")]
+ #[inline]
+ pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
+ StrExt::match_indices(self, pat)
+ }
+
+ /// An iterator over the disjoint matches of a pattern within `self`,
+ /// yielded in reverse order along with the index of the match.
+ ///
+ /// For matches of `pat` within `self` that overlap, only the indices
+ /// corresponding to the last match are returned.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if a
+ /// character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Iterator behavior
+ ///
+ /// The returned iterator requires that the pattern supports a reverse
+ /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse
+ /// search yields the same elements.
+ ///
+ /// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html
+ ///
+ /// For iterating from the front, the [`match_indices`] method can be used.
+ ///
+ /// [`match_indices`]: #method.match_indices
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]);
+ ///
+ /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(4, "abc"), (1, "abc")]);
+ ///
+ /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect();
+ /// assert_eq!(v, [(2, "aba")]); // only the last `aba`
+ /// ```
+ #[stable(feature = "str_match_indices", since = "1.5.0")]
+ #[inline]
+ pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::rmatch_indices(self, pat)
+ }
+
+ /// Returns a string slice with leading and trailing whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ ///
+ /// assert_eq!("Hello\tworld", s.trim());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim(&self) -> &str {
+ StrExt::trim(self)
+ }
+
+ /// Returns a string slice with leading whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Left' in this context means the first
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _right_ side, not the left.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ ///
+ /// assert_eq!("Hello\tworld\t", s.trim_left());
+ /// ```
+ ///
+ /// Directionality:
+ ///
+ /// ```
+ /// let s = " English";
+ /// assert!(Some('E') == s.trim_left().chars().next());
+ ///
+ /// let s = " עברית";
+ /// assert!(Some('ע') == s.trim_left().chars().next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_left(&self) -> &str {
+ StrExt::trim_left(self)
+ }
+
+ /// Returns a string slice with trailing whitespace removed.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived
+ /// Core Property `White_Space`.
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Right' in this context means the last
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _left_ side, not the right.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let s = " Hello\tworld\t";
+ ///
+ /// assert_eq!(" Hello\tworld", s.trim_right());
+ /// ```
+ ///
+ /// Directionality:
+ ///
+ /// ```
+ /// let s = "English ";
+ /// assert!(Some('h') == s.trim_right().chars().rev().next());
+ ///
+ /// let s = "עברית ";
+ /// assert!(Some('ת') == s.trim_right().chars().rev().next());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_right(&self) -> &str {
+ StrExt::trim_right(self)
+ }
+
+ /// Returns a string slice with all prefixes and suffixes that match a
+ /// pattern repeatedly removed.
+ ///
+ /// The pattern can be a [`char`] or a closure that determines if a
+ /// character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_matches('1'), "foo1bar");
+ /// assert_eq!("123foo1bar123".trim_matches(char::is_numeric), "foo1bar");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_matches(x), "foo1bar");
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// assert_eq!("1foo1barXX".trim_matches(|c| c == '1' || c == 'X'), "foo1bar");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: DoubleEndedSearcher<'a>
+ {
+ StrExt::trim_matches(self, pat)
+ }
+
+ /// Returns a string slice with all prefixes that match a pattern
+ /// repeatedly removed.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that determines if
+ /// a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Left' in this context means the first
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _right_ side, not the left.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_left_matches('1'), "foo1bar11");
+ /// assert_eq!("123foo1bar123".trim_left_matches(char::is_numeric), "foo1bar123");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_left_matches(x), "foo1bar12");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str {
+ StrExt::trim_left_matches(self, pat)
+ }
+
+ /// Returns a string slice with all suffixes that match a pattern
+ /// repeatedly removed.
+ ///
+ /// The pattern can be a `&str`, [`char`], or a closure that
+ /// determines if a character matches.
+ ///
+ /// [`char`]: primitive.char.html
+ ///
+ /// # Text directionality
+ ///
+ /// A string is a sequence of bytes. 'Right' in this context means the last
+ /// position of that byte string; for a language like Arabic or Hebrew
+ /// which are 'right to left' rather than 'left to right', this will be
+ /// the _left_ side, not the right.
+ ///
+ /// # Examples
+ ///
+ /// Simple patterns:
+ ///
+ /// ```
+ /// assert_eq!("11foo1bar11".trim_right_matches('1'), "11foo1bar");
+ /// assert_eq!("123foo1bar123".trim_right_matches(char::is_numeric), "123foo1bar");
+ ///
+ /// let x: &[_] = &['1', '2'];
+ /// assert_eq!("12foo1bar12".trim_right_matches(x), "12foo1bar");
+ /// ```
+ ///
+ /// A more complex pattern, using a closure:
+ ///
+ /// ```
+ /// assert_eq!("1fooX".trim_right_matches(|c| c == '1' || c == 'X'), "1foo");
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
+ where P::Searcher: ReverseSearcher<'a>
+ {
+ StrExt::trim_right_matches(self, pat)
+ }
+
+ /// Parses this string slice into another type.
+ ///
+ /// Because `parse` is so general, it can cause problems with type
+ /// inference. As such, `parse` is one of the few times you'll see
+ /// the syntax affectionately known as the 'turbofish': `::<>`. This
+ /// helps the inference algorithm understand specifically which type
+ /// you're trying to parse into.
+ ///
+ /// `parse` can parse any type that implements the [`FromStr`] trait.
+ ///
+ /// [`FromStr`]: str/trait.FromStr.html
+ ///
+ /// # Errors
+ ///
+ /// Will return [`Err`] if it's not possible to parse this string slice into
+ /// the desired type.
+ ///
+ /// [`Err`]: str/trait.FromStr.html#associatedtype.Err
+ ///
+ /// # Examples
+ ///
+ /// Basic usage
+ ///
+ /// ```
+ /// let four: u32 = "4".parse().unwrap();
+ ///
+ /// assert_eq!(4, four);
+ /// ```
+ ///
+ /// Using the 'turbofish' instead of annotating `four`:
+ ///
+ /// ```
+ /// let four = "4".parse::<u32>();
+ ///
+ /// assert_eq!(Ok(4), four);
+ /// ```
+ ///
+ /// Failing to parse:
+ ///
+ /// ```
+ /// let nope = "j".parse::<u32>();
+ ///
+ /// assert!(nope.is_err());
+ /// ```
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> {
+ StrExt::parse(self)
+ }
+
+ /// Checks if all characters in this string are within the ASCII range.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// let ascii = "hello!\n";
+ /// let non_ascii = "Grüße, Jürgen ❤";
+ ///
+ /// assert!(ascii.is_ascii());
+ /// assert!(!non_ascii.is_ascii());
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ // We can treat each byte as character here: all multibyte characters
+ // start with a byte that is not in the ascii range, so we will stop
+ // there already.
+ self.bytes().all(|b| b.is_ascii())
+ }
+
+ /// Checks that two strings are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// assert!("Ferris".eq_ignore_ascii_case("FERRIS"));
+ /// assert!("Ferrös".eq_ignore_ascii_case("FERRöS"));
+ /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
+ /// ```
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
+ self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
+ }
+
+ /// Converts this string to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ pub fn make_ascii_uppercase(&mut self) {
+ let me = unsafe { self.as_bytes_mut() };
+ me.make_ascii_uppercase()
+ }
+
+ /// Converts this string to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ pub fn make_ascii_lowercase(&mut self) {
+ let me = unsafe { self.as_bytes_mut() };
+ me.make_ascii_lowercase()
+ }
+}}
+
+#[lang = "str"]
+#[cfg(not(test))]
+#[cfg(not(stage0))]
+impl str {
+ str_core_methods!();
+}
+
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef<[u8]> for str {
+ #[inline]
+ fn as_ref(&self) -> &[u8] {
+ self.as_bytes()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a> Default for &'a str {
+ /// Creates an empty str
+ fn default() -> &'a str { "" }
+}
+
+/// An iterator over the non-whitespace substrings of a string,
+/// separated by any amount of whitespace.
+///
+/// This struct is created by the [`split_whitespace`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace
+/// [`str`]: ../../std/primitive.str.html
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+#[derive(Clone, Debug)]
+pub struct SplitWhitespace<'a> {
+ inner: Filter<Split<'a, IsWhitespace>, IsNotEmpty>,
+}
+
+#[derive(Clone)]
+struct IsWhitespace;
+
+impl FnOnce<(char, )> for IsWhitespace {
+ type Output = bool;
+
+ #[inline]
+ extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool {
+ self.call_mut(arg)
+ }
+}
+
+impl FnMut<(char, )> for IsWhitespace {
+ #[inline]
+ extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool {
+ arg.0.is_whitespace()
+ }
+}
+
+#[derive(Clone)]
+struct IsNotEmpty;
+
+impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty {
+ type Output = bool;
+
+ #[inline]
+ extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool {
+ self.call_mut(arg)
+ }
+}
+
+impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty {
+ #[inline]
+ extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool {
+ !arg.0.is_empty()
+ }
+}
+
+
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+impl<'a> Iterator for SplitWhitespace<'a> {
+ type Item = &'a str;
+
+ fn next(&mut self) -> Option<&'a str> {
+ self.inner.next()
+ }
+}
+
+#[stable(feature = "split_whitespace", since = "1.1.0")]
+impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
+ fn next_back(&mut self) -> Option<&'a str> {
+ self.inner.next_back()
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<'a> FusedIterator for SplitWhitespace<'a> {}
+
+/// An iterator of [`u16`] over the string encoded as UTF-16.
+///
+/// [`u16`]: ../../std/primitive.u16.html
+///
+/// This struct is created by the [`encode_utf16`] method on [`str`].
+/// See its documentation for more.
+///
+/// [`encode_utf16`]: ../../std/primitive.str.html#method.encode_utf16
+/// [`str`]: ../../std/primitive.str.html
+#[derive(Clone)]
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+pub struct EncodeUtf16<'a> {
+ chars: Chars<'a>,
+ extra: u16,
+}
+
+// FIXME: remove (inline) this method
+// when updating to a bootstrap compiler that has the new lang items.
+// For grepping purpose: #[cfg(stage0)]
+impl<'a> EncodeUtf16<'a> {
+ #[unstable(feature = "core_str_ext", issue = "32110")]
+ #[doc(hidden)]
+ pub fn new(s: &'a str) -> Self {
+ EncodeUtf16 { chars: s.chars(), extra: 0 }
+ }
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<'a> fmt::Debug for EncodeUtf16<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("EncodeUtf16 { .. }")
+ }
+}
+
+#[stable(feature = "encode_utf16", since = "1.8.0")]
+impl<'a> Iterator for EncodeUtf16<'a> {
+ type Item = u16;
+
+ #[inline]
+ fn next(&mut self) -> Option<u16> {
+ if self.extra != 0 {
+ let tmp = self.extra;
+ self.extra = 0;
+ return Some(tmp);
+ }
+
+ let mut buf = [0; 2];
+ self.chars.next().map(|ch| {
+ let n = ch.encode_utf16(&mut buf).len();
+ if n == 2 {
+ self.extra = buf[1];
+ }
+ buf[0]
+ })
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (low, high) = self.chars.size_hint();
+ // every char gets either one u16 or two u16,
+ // so this iterator is between 1 or 2 times as
+ // long as the underlying iterator.
+ (low, high.and_then(|n| n.checked_mul(2)))
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<'a> FusedIterator for EncodeUtf16<'a> {}
/// `finger` is the current byte index of the forward search.
/// Imagine that it exists before the byte at its index, i.e.
- /// haystack[finger] is the first byte of the slice we must inspect during
+ /// `haystack[finger]` is the first byte of the slice we must inspect during
/// forward searching
finger: usize,
/// `finger_back` is the current byte index of the reverse search.
#[$stable_debug]
impl fmt::Debug for $atomic_type {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_tuple(stringify!($atomic_type))
- .field(&self.load(Ordering::SeqCst))
- .finish()
+ fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
}
}
# Examples
```
-", $extra_feature, "#![feature(atomic_nand)]
-
+", $extra_feature, "
use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
let foo = ", stringify!($atomic_type), "::new(0x13);
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"i8", "../../../std/primitive.i8.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"u8", "../../../std/primitive.u8.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"i16", "../../../std/primitive.i16.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"u16", "../../../std/primitive.u16.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"i32", "../../../std/primitive.i32.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"u32", "../../../std/primitive.u32.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"i64", "../../../std/primitive.i64.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
unstable(feature = "integer_atomics", issue = "32976"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ unstable(feature = "integer_atomics", issue = "32976"),
"u64", "../../../std/primitive.u64.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
stable(feature = "atomic_debug", since = "1.3.0"),
stable(feature = "atomic_access", since = "1.15.0"),
stable(feature = "atomic_from", since = "1.23.0"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ stable(feature = "atomic_nand", since = "1.27.0"),
"isize", "../../../std/primitive.isize.html",
"",
atomic_min, atomic_max,
stable(feature = "atomic_debug", since = "1.3.0"),
stable(feature = "atomic_access", since = "1.15.0"),
stable(feature = "atomic_from", since = "1.23.0"),
- unstable(feature = "atomic_nand", issue = "13226"),
+ stable(feature = "atomic_nand", since = "1.27.0"),
"usize", "../../../std/primitive.usize.html",
"",
atomic_umin, atomic_umax,
#[stable(feature = "atomic_debug", since = "1.3.0")]
impl fmt::Debug for AtomicBool {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_tuple("AtomicBool").field(&self.load(Ordering::SeqCst)).finish()
+ fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
}
}
#[stable(feature = "atomic_debug", since = "1.3.0")]
impl<T> fmt::Debug for AtomicPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_tuple("AtomicPtr").field(&self.load(Ordering::SeqCst)).finish()
+ fmt::Debug::fmt(&self.load(Ordering::SeqCst), f)
}
}
assert!(y.get() == (30, 40));
}
+#[test]
+fn cell_update() {
+ let x = Cell::new(10);
+
+ assert_eq!(x.update(|x| x + 5), 15);
+ assert_eq!(x.get(), 15);
+
+ assert_eq!(x.update(|x| x / 3), 5);
+ assert_eq!(x.get(), 5);
+}
+
#[test]
fn cell_has_sensible_show() {
let x = Cell::new("foo bar");
#![feature(ascii_ctype)]
#![feature(box_syntax)]
+#![feature(cell_update)]
#![feature(core_float)]
#![feature(core_private_bignum)]
#![feature(core_private_diy_float)]
#![feature(decode_utf8)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
+#![feature(float_internals)]
#![feature(flt2dec)]
#![feature(fmt_internals)]
#![feature(hashmap_internals)]
#![feature(str_internals)]
#![feature(test)]
#![feature(trusted_len)]
+#![feature(try_from)]
#![feature(try_trait)]
#![feature(exact_chunks)]
-#![feature(atomic_nand)]
+#![cfg_attr(stage0, feature(atomic_nand))]
#![feature(reverse_bits)]
#![feature(inclusive_range_fields)]
#![feature(iterator_find_map)]
/// # Examples
///
/// ```
- /// #![feature(duration_from_micros)]
/// use std::time::Duration;
///
/// let duration = Duration::from_micros(1_000_002);
/// assert_eq!(1, duration.as_secs());
/// assert_eq!(2000, duration.subsec_nanos());
/// ```
- #[unstable(feature = "duration_from_micros", issue = "44400")]
+ #[stable(feature = "duration_from_micros", since = "1.27.0")]
#[inline]
pub const fn from_micros(micros: u64) -> Duration {
Duration {
/// # Examples
///
/// ```
- /// #![feature(duration_extras)]
/// use std::time::Duration;
///
/// let duration = Duration::from_nanos(1_000_000_123);
/// assert_eq!(1, duration.as_secs());
/// assert_eq!(123, duration.subsec_nanos());
/// ```
- #[unstable(feature = "duration_extras", issue = "46507")]
+ #[stable(feature = "duration_extras", since = "1.27.0")]
#[inline]
pub const fn from_nanos(nanos: u64) -> Duration {
Duration {
/// # Examples
///
/// ```
- /// #![feature(duration_extras)]
/// use std::time::Duration;
///
/// let duration = Duration::from_millis(5432);
/// assert_eq!(duration.as_secs(), 5);
/// assert_eq!(duration.subsec_millis(), 432);
/// ```
- #[unstable(feature = "duration_extras", issue = "46507")]
+ #[stable(feature = "duration_extras", since = "1.27.0")]
#[inline]
pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
/// # Examples
///
/// ```
- /// #![feature(duration_extras, duration_from_micros)]
/// use std::time::Duration;
///
/// let duration = Duration::from_micros(1_234_567);
/// assert_eq!(duration.as_secs(), 1);
/// assert_eq!(duration.subsec_micros(), 234_567);
/// ```
- #[unstable(feature = "duration_extras", issue = "46507")]
+ #[stable(feature = "duration_extras", since = "1.27.0")]
#[inline]
pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
// now hopefully.
#[no_mangle]
#[rustc_std_internal_symbol]
-pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 {
+pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
abort();
#[cfg(any(unix, target_os = "cloudabi"))]
html_root_url = "https://doc.rust-lang.org/nightly/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
+#![feature(allocator_api)]
#![feature(alloc)]
#![feature(core_intrinsics)]
#![feature(lang_items)]
#![feature(panic_unwind)]
#![feature(raw)]
#![feature(staged_api)]
+#![feature(std_internals)]
#![feature(unwind_attributes)]
#![cfg_attr(target_env = "msvc", feature(raw))]
#[cfg(not(any(target_env = "msvc", all(windows, target_arch = "x86_64", target_env = "gnu"))))]
extern crate unwind;
+use alloc::boxed::Box;
use core::intrinsics;
use core::mem;
use core::raw;
+use core::panic::BoxMeUp;
// Rust runtime's startup objects depend on these symbols, so make them public.
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
// implementation.
#[no_mangle]
#[unwind(allowed)]
-pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
- imp::panic(mem::transmute(raw::TraitObject {
- data: data as *mut (),
- vtable: vtable as *mut (),
- }))
+pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 {
+ let payload = payload as *mut &mut BoxMeUp;
+ imp::panic(Box::from_raw((*payload).box_me_up()))
}
}
}
-impl Quote for usize {
+impl Quote for u16 {
fn quote(self) -> TokenStream {
- TokenTree::from(Literal::usize_unsuffixed(self)).into()
+ TokenTree::from(Literal::u16_unsuffixed(self)).into()
}
}
($($i:ident),*; $($raw:ident),*) => {
pub enum LiteralKind {
$($i,)*
- $($raw(usize),)*
+ $($raw(u16),)*
}
impl LiteralKind {
[input] DefSpan(DefId),
[] LookupStability(DefId),
[] LookupDeprecationEntry(DefId),
- [] ItemBodyNestedBodies(DefId),
[] ConstIsRvaluePromotableToStatic(DefId),
[] RvaluePromotableMap(DefId),
[] ImplParent(DefId),
[] ItemAttrs(DefId),
[] TransFnAttrs(DefId),
[] FnArgNames(DefId),
+ [] RenderedConst(DefId),
[] DylibDepFormats(CrateNum),
[] IsPanicRuntime(CrateNum),
[] IsCompilerBuiltins(CrateNum),
[input] GetLangItems,
[] DefinedLangItems(CrateNum),
[] MissingLangItems(CrateNum),
- [] ExternConstBody(DefId),
[] VisibleParentMap,
[input] MissingExternCrateItem(CrateNum),
[input] UsedCrateSource(CrateNum),
use hir::*;
use hir::print::Nested;
use hir::svh::Svh;
-use util::nodemap::{DefIdMap, FxHashMap};
+use util::nodemap::FxHashMap;
-use arena::TypedArena;
use std::io;
use ty::TyCtxt;
-use rustc_data_structures::sync::Lock;
-
pub mod blocks;
mod collector;
mod def_collector;
pub struct Forest {
krate: Crate,
pub dep_graph: DepGraph,
- inlined_bodies: TypedArena<Body>
}
impl Forest {
Forest {
krate,
dep_graph: dep_graph.clone(),
- inlined_bodies: TypedArena::new()
}
}
definitions: &'hir Definitions,
- /// Bodies inlined from other crates are cached here.
- inlined_bodies: Lock<DefIdMap<&'hir Body>>,
-
/// The reverse mapping of `node_to_hir_id`.
hir_to_node_id: FxHashMap<HirId, NodeId>,
}
}
}
- pub fn get_inlined_body_untracked(&self, def_id: DefId) -> Option<&'hir Body> {
- self.inlined_bodies.borrow().get(&def_id).cloned()
- }
-
- pub fn intern_inlined_body(&self, def_id: DefId, body: Body) -> &'hir Body {
- let mut inlined_bodies = self.inlined_bodies.borrow_mut();
- if let Some(&b) = inlined_bodies.get(&def_id) {
- debug_assert_eq!(&body, b);
- return b;
- }
- let body = self.forest.inlined_bodies.alloc(body);
- inlined_bodies.insert(def_id, body);
- body
- }
-
/// Returns the name associated with the given NodeId's AST.
pub fn name(&self, id: NodeId) -> Name {
match self.get(id) {
map,
hir_to_node_id,
definitions,
- inlined_bodies: Lock::new(DefIdMap()),
};
hir_id_validator::check_crate(&map);
const NAKED = 0b0001_0000;
const NO_MANGLE = 0b0010_0000;
const RUSTC_STD_INTERNAL_SYMBOL = 0b0100_0000;
+ const NO_DEBUG = 0b1000_0000;
}
}
//! This module contains `HashStable` implementations for various data types
//! from rustc::middle::cstore in no particular order.
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
-
use middle;
impl_stable_hash_for!(enum middle::cstore::DepKind {
rlib,
rmeta
});
-
-impl<HCX> HashStable<HCX> for middle::cstore::ExternBodyNestedBodies {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut HCX,
- hasher: &mut StableHasher<W>) {
- let middle::cstore::ExternBodyNestedBodies {
- nested_bodies: _,
- fingerprint,
- } = *self;
-
- fingerprint.hash_stable(hcx, hasher);
- }
-}
-
-impl<'a, HCX> HashStable<HCX> for middle::cstore::ExternConstBody<'a> {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut HCX,
- hasher: &mut StableHasher<W>) {
- let middle::cstore::ExternConstBody {
- body: _,
- fingerprint,
- } = *self;
-
- fingerprint.hash_stable(hcx, hasher);
- }
-}
FromEnv(where_clause) => where_clause.hash_stable(hcx, hasher),
WellFormedTy(ty) => ty.hash_stable(hcx, hasher),
+ Normalize(projection) => projection.hash_stable(hcx, hasher),
FromEnvTy(ty) => ty.hash_stable(hcx, hasher),
RegionOutlives(predicate) => predicate.hash_stable(hcx, hasher),
TypeOutlives(predicate) => predicate.hash_stable(hcx, hasher),
) {
debug!("report_region_errors(): {} errors to start", errors.len());
- if will_later_be_reported_by_nll && self.tcx.nll() {
+ if will_later_be_reported_by_nll && self.tcx.use_mir_borrowck() {
// With `#![feature(nll)]`, we want to present a nice user
// experience, so don't even mention the errors from the
// AST checker.
return;
}
- // But with -Znll, it's nice to have some note for later.
+ // But with nll, it's nice to have some note for later.
for error in errors {
match *error {
RegionResolutionError::ConcreteFailure(ref origin, ..)
| RegionResolutionError::GenericBoundFailure(ref origin, ..) => {
self.tcx
.sess
- .span_warn(origin.span(), "not reporting region error due to -Znll");
+ .span_warn(origin.span(), "not reporting region error due to nll");
}
RegionResolutionError::SubSupConflict(ref rvo, ..) => {
self.tcx
.sess
- .span_warn(rvo.span(), "not reporting region error due to -Znll");
+ .span_warn(rvo.span(), "not reporting region error due to nll");
}
}
}
use syntax_pos::{self, Span};
use syntax_pos::symbol::InternedString;
use util::nodemap::FxHashMap;
-use arena::DroplessArena;
+use arena::SyncDroplessArena;
use self::combine::CombineFields;
use self::higher_ranked::HrMatchResult;
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(InferCtxt<'b, 'gcx, 'tcx>).
pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
global_tcx: TyCtxt<'a, 'gcx, 'gcx>,
- arena: DroplessArena,
+ arena: SyncDroplessArena,
fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
}
pub fn infer_ctxt(self) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
InferCtxtBuilder {
global_tcx: self,
- arena: DroplessArena::new(),
+ arena: SyncDroplessArena::new(),
fresh_tables: None,
}
#![cfg_attr(windows, feature(libc))]
#![feature(macro_lifetime_matcher)]
#![feature(macro_vis_matcher)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(non_exhaustive)]
#![feature(nonzero)]
use self::TargetLint::*;
use std::slice;
+use rustc_data_structures::sync::{RwLock, ReadGuard};
use lint::{EarlyLintPassObject, LateLintPassObject};
use lint::{Level, Lint, LintId, LintPass, LintBuffer};
use lint::builtin::BuiltinLintDiagnostics;
use util::nodemap::FxHashMap;
use std::default::Default as StdDefault;
-use std::cell::{Ref, RefCell};
use syntax::ast;
use syntax::edition;
use syntax_pos::{MultiSpan, Span};
pub struct LintSession<'a, PassObject> {
/// Reference to the store of registered lints.
- lints: Ref<'a, LintStore>,
+ lints: ReadGuard<'a, LintStore>,
/// Trait objects for each lint pass.
passes: Option<Vec<PassObject>>,
/// Creates a new `LintSession`, by moving out the `LintStore`'s initial
/// lint levels and pass objects. These can be restored using the `restore`
/// method.
- fn new(store: &'a RefCell<LintStore>) -> LintSession<'a, PassObject> {
+ fn new(store: &'a RwLock<LintStore>) -> LintSession<'a, PassObject> {
let mut s = store.borrow_mut();
let passes = PassObject::take_passes(&mut *s);
drop(s);
}
/// Restores the levels back to the original lint store.
- fn restore(self, store: &RefCell<LintStore>) {
+ fn restore(self, store: &RwLock<LintStore>) {
drop(self.lints);
let mut s = store.borrow_mut();
PassObject::restore_passes(&mut *s, self.passes);
//! are *mostly* used as a part of that interface, but these should
//! probably get a better home if someone can find one.
-use hir;
use hir::def;
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use hir::map as hir_map;
use hir::map::definitions::{Definitions, DefKey, DefPathTable};
use hir::svh::Svh;
-use ich;
use ty::{self, TyCtxt};
use session::{Session, CrateDisambiguator};
use session::search_paths::PathKind;
use std::any::Any;
-use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use syntax::ast;
use syntax::ext::base::SyntaxExtension;
-> Result<MetadataRef, String>;
}
-#[derive(Clone)]
-pub struct ExternConstBody<'tcx> {
- pub body: &'tcx hir::Body,
-
- // It would require a lot of infrastructure to enable stable-hashing Bodies
- // from other crates, so we hash on export and just store the fingerprint
- // with them.
- pub fingerprint: ich::Fingerprint,
-}
-
-#[derive(Clone)]
-pub struct ExternBodyNestedBodies {
- pub nested_bodies: Lrc<BTreeMap<hir::BodyId, hir::Body>>,
-
- // It would require a lot of infrastructure to enable stable-hashing Bodies
- // from other crates, so we hash on export and just store the fingerprint
- // with them.
- pub fingerprint: ich::Fingerprint,
-}
-
/// A store of Rust crates, through with their metadata
/// can be accessed.
///
StrImplItem, "str", str_impl;
SliceImplItem, "slice", slice_impl;
SliceU8ImplItem, "slice_u8", slice_u8_impl;
+ StrAllocImplItem, "str_alloc", str_alloc_impl;
+ SliceAllocImplItem, "slice_alloc", slice_alloc_impl;
+ SliceU8AllocImplItem, "slice_u8_alloc", slice_u8_alloc_impl;
ConstPtrImplItem, "const_ptr", const_ptr_impl;
MutPtrImplItem, "mut_ptr", mut_ptr_impl;
I8ImplItem, "i8", i8_impl;
UsizeImplItem, "usize", usize_impl;
F32ImplItem, "f32", f32_impl;
F64ImplItem, "f64", f64_impl;
+ F32RuntimeImplItem, "f32_runtime", f32_runtime_impl;
+ F64RuntimeImplItem, "f64_runtime", f64_runtime_impl;
SizedTraitLangItem, "sized", sized_trait;
UnsizeTraitLangItem, "unsize", unsize_trait;
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
BoxFreeFnLangItem, "box_free", box_free_fn;
- DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
+ DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn;
+ OomLangItem, "oom", oom;
StartFnLangItem, "start", start_fn;
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
+ oom, OomLangItem, rust_oom;
}
Location { block: self.block, statement_index: self.statement_index + 1 }
}
- pub fn dominates(&self, other: &Location, dominators: &Dominators<BasicBlock>) -> bool {
+ pub fn dominates(&self, other: Location, dominators: &Dominators<BasicBlock>) -> bool {
if self.block == other.block {
self.statement_index <= other.statement_index
} else {
pub use self::Passes::*;
pub use self::DebugInfoLevel::*;
+use std::str::FromStr;
+
use session::{early_error, early_warn, Session};
use session::search_paths::SearchPaths;
use syntax::ast::{self, IntTy, UintTy};
use syntax::codemap::{FileName, FilePathMapping};
-use syntax::edition::Edition;
+use syntax::edition::{Edition, EDITION_NAME_LIST, DEFAULT_EDITION};
use syntax::parse::token;
use syntax::parse;
use syntax::symbol::Symbol;
self.0.values()
}
+ pub fn len(&self) -> usize {
+ self.0.len()
+ }
+
// True if any of the output types require codegen or linking.
pub fn should_trans(&self) -> bool {
self.0.keys().any(|k| match *k {
// Remap source path prefixes in all output (messages, object files, debug, etc)
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+ edition: Edition [TRACKED],
}
);
cli_forced_codegen_units: None,
cli_forced_thinlto_off: false,
remap_path_prefix: Vec::new(),
+ edition: DEFAULT_EDITION,
}
}
Some("`string` or `string=string`");
pub const parse_lto: Option<&'static str> =
Some("one of `thin`, `fat`, or omitted");
- pub const parse_edition: Option<&'static str> =
- Some("one of: `2015`, `2018`");
}
#[allow(dead_code)]
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel};
use std::path::PathBuf;
- use syntax::edition::Edition;
$(
pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
true
}
- fn parse_edition(slot: &mut Edition, v: Option<&str>) -> bool {
- match v {
- Some(s) => {
- let edition = s.parse();
- if let Ok(parsed) = edition {
- *slot = parsed;
- true
- } else {
- false
- }
- }
- _ => false,
- }
- }
}
) }
useful for profiling / PGO."),
relro_level: Option<RelroLevel> = (None, parse_relro_level, [TRACKED],
"choose which RELRO level to use"),
- nll: bool = (false, parse_bool, [UNTRACKED],
- "run the non-lexical lifetimes MIR pass"),
+ nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED],
+ "when tracking region error causes, accept subminimal results for faster execution."),
disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED],
"disable user provided type assertion in NLL"),
trans_time_graph: bool = (false, parse_bool, [UNTRACKED],
`everybody_loops` (all function bodies replaced with `loop {}`),
`hir` (the HIR), `hir,identified`, or
`hir,typed` (HIR with types for each node)."),
- edition: Edition = (Edition::Edition2015, parse_edition, [TRACKED],
- "The edition to build Rust with. Newer editions may include features
- that require breaking changes. The default edition is 2015 (the first
- edition). Crates compiled with different editions can be linked together."),
run_dsymutil: Option<bool> = (None, parse_opt_bool, [TRACKED],
"run `dsymutil` and delete intermediate object files"),
ui_testing: bool = (false, parse_bool, [UNTRACKED],
`expanded,identified` (fully parenthesized, AST nodes with IDs).",
"TYPE",
),
+ opt::opt_s(
+ "",
+ "edition",
+ "Specify which edition of the compiler to use when compiling code.",
+ EDITION_NAME_LIST,
+ ),
opt::multi_s(
"",
"remap-path-prefix",
),
};
+ let edition = match matches.opt_str("edition") {
+ Some(arg) => match Edition::from_str(&arg){
+ Ok(edition) => edition,
+ Err(_) => early_error(
+ ErrorOutputType::default(),
+ &format!(
+ "argument for --edition must be one of: \
+ {}. (instead was `{}`)",
+ EDITION_NAME_LIST,
+ arg
+ ),
+ ),
+ }
+ None => DEFAULT_EDITION,
+ };
+
+ if !edition.is_stable() && !nightly_options::is_nightly_build() {
+ early_error(
+ ErrorOutputType::default(),
+ &format!(
+ "Edition {} is unstable an only\
+ available for nightly builds of rustc.",
+ edition,
+ )
+ )
+ }
+
+
// We need the opts_present check because the driver will send us Matches
// with only stable options if no unstable options are used. Since error-format
// is unstable, it will not be present. We have to use opts_present not
cli_forced_codegen_units: codegen_units,
cli_forced_thinlto_off: disable_thinlto,
remap_path_prefix,
+ edition,
},
cfg,
)
use std::hash::Hash;
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
- use super::{CrateType, DebugInfoLevel, Edition, ErrorOutputType, Lto, OptLevel, OutputTypes,
+ use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
Passes, Sanitizer};
use syntax::feature_gate::UnstableFeatures;
use rustc_back::{PanicStrategy, RelroLevel};
use rustc_back::target::TargetTriple;
+ use syntax::edition::Edition;
pub trait DepTrackingHash {
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
impl_dep_tracking_hash_via_hash!(Sanitizer);
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
- impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_via_hash!(TargetTriple);
+ impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
use super::{Externs, OutputType, OutputTypes};
use rustc_back::{PanicStrategy, RelroLevel};
use syntax::symbol::Symbol;
+ use syntax::edition::{Edition, DEFAULT_EDITION};
use syntax;
fn optgroups() -> getopts::Options {
opts.debugging_opts.relro_level = Some(RelroLevel::Full);
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
}
+
+ #[test]
+ fn test_edition_parsing() {
+ // test default edition
+ let options = super::basic_options();
+ assert!(options.edition == DEFAULT_EDITION);
+
+ let matches = optgroups()
+ .parse(&["--edition=2018".to_string()])
+ .unwrap();
+ let (sessopts, _) = build_session_options_and_crate_config(&matches);
+ assert!(sessopts.edition == Edition::Edition2018)
+ }
}
use util::common::{duration_to_secs_str, ErrorReported};
use util::common::ProfileQueriesMsg;
-use rustc_data_structures::sync::{Lrc, Lock, LockCell, OneThread, Once};
+use rustc_data_structures::sync::{self, Lrc, Lock, LockCell, OneThread, Once, RwLock};
use syntax::ast::NodeId;
use errors::{self, DiagnosticBuilder, DiagnosticId};
// FIXME: lint_store and buffered_lints are not thread-safe,
// but are only used in a single thread
- pub lint_store: OneThread<RefCell<lint::LintStore>>,
- pub buffered_lints: OneThread<RefCell<Option<lint::LintBuffer>>>,
+ pub lint_store: RwLock<lint::LintStore>,
+ pub buffered_lints: Lock<Option<lint::LintBuffer>>,
/// Set of (DiagnosticId, Option<Span>, message) tuples tracking
/// (sub)diagnostics that have been set once, but should not be set again,
/// in order to avoid redundantly verbose output (Issue #24690, #44953).
- pub one_time_diagnostics: RefCell<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
+ pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>,
pub plugin_llvm_passes: OneThread<RefCell<Vec<String>>>,
pub plugin_attributes: OneThread<RefCell<Vec<(String, AttributeType)>>>,
pub crate_types: Once<Vec<config::CrateType>>,
}
pub fn teach(&self, code: &DiagnosticId) -> bool {
- self.opts.debugging_opts.teach && !self.parse_sess.span_diagnostic.code_emitted(code)
+ self.opts.debugging_opts.teach && self.parse_sess.span_diagnostic.must_teach(code)
}
/// Are we allowed to use features from the Rust 2018 edition?
pub fn rust_2018(&self) -> bool {
- self.opts.debugging_opts.edition >= Edition::Edition2018
+ self.opts.edition >= Edition::Edition2018
}
pub fn edition(&self) -> Edition {
- self.opts.debugging_opts.edition
+ self.opts.edition
}
}
let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace;
- let emitter: Box<dyn Emitter> =
+ let emitter: Box<dyn Emitter + sync::Send> =
match (sopts.error_format, emitter_dest) {
(config::ErrorOutputType::HumanReadable(color_config), None) => Box::new(
EmitterWriter::stderr(
default_sysroot,
local_crate_source_file,
working_dir,
- lint_store: OneThread::new(RefCell::new(lint::LintStore::new())),
- buffered_lints: OneThread::new(RefCell::new(Some(lint::LintBuffer::new()))),
- one_time_diagnostics: RefCell::new(FxHashSet()),
+ lint_store: RwLock::new(lint::LintStore::new()),
+ buffered_lints: Lock::new(Some(lint::LintBuffer::new())),
+ one_time_diagnostics: Lock::new(FxHashSet()),
plugin_llvm_passes: OneThread::new(RefCell::new(Vec::new())),
plugin_attributes: OneThread::new(RefCell::new(Vec::new())),
crate_types: Once::new(),
}
pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
- let emitter: Box<dyn Emitter> = match output {
+ let emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, false, false))
}
}
pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
- let emitter: Box<dyn Emitter> = match output {
+ let emitter: Box<dyn Emitter + sync::Send> = match output {
config::ErrorOutputType::HumanReadable(color_config) => {
Box::new(EmitterWriter::stderr(color_config, None, false, false))
}
WellFormed(WhereClauseAtom<'tcx>),
FromEnv(WhereClauseAtom<'tcx>),
WellFormedTy(Ty<'tcx>),
+ Normalize(ty::ProjectionPredicate<'tcx>),
FromEnvTy(Ty<'tcx>),
RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
FromEnv(Implemented(trait_ref)) => write!(fmt, "FromEnv({})", trait_ref),
FromEnv(ProjectionEq(projection)) => write!(fmt, "FromEnv({})", projection),
WellFormedTy(ty) => write!(fmt, "WellFormed({})", ty),
+ Normalize(projection) => write!(fmt, "Normalize({})", projection),
FromEnvTy(ty) => write!(fmt, "FromEnv({})", ty),
RegionOutlives(predicate) => write!(fmt, "RegionOutlives({})", predicate),
TypeOutlives(predicate) => write!(fmt, "TypeOutlives({})", predicate),
(traits::DomainGoal::WellFormed)(wc),
(traits::DomainGoal::FromEnv)(wc),
(traits::DomainGoal::WellFormedTy)(ty),
+ (traits::DomainGoal::Normalize)(projection),
(traits::DomainGoal::FromEnvTy)(ty),
(traits::DomainGoal::RegionOutlives)(predicate),
(traits::DomainGoal::TypeOutlives)(predicate),
use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
StableHasher, StableHasherResult,
StableVec};
-use arena::{TypedArena, DroplessArena};
+use arena::{TypedArena, SyncDroplessArena};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::sync::{Lrc, Lock};
use std::any::Any;
use std::borrow::Borrow;
-use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::hash_map::{self, Entry};
use std::hash::{Hash, Hasher};
pub struct AllArenas<'tcx> {
pub global: GlobalArenas<'tcx>,
- pub interner: DroplessArena,
+ pub interner: SyncDroplessArena,
}
impl<'tcx> AllArenas<'tcx> {
pub fn new() -> Self {
AllArenas {
global: GlobalArenas::new(),
- interner: DroplessArena::new(),
+ interner: SyncDroplessArena::new(),
}
}
}
pub struct CtxtInterners<'tcx> {
/// The arena that types, regions, etc are allocated from
- arena: &'tcx DroplessArena,
+ arena: &'tcx SyncDroplessArena,
/// Specifically use a speedy hash algorithm for these hash sets,
/// they're accessed quite often.
}
impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> {
- fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> {
+ fn new(arena: &'tcx SyncDroplessArena) -> CtxtInterners<'tcx> {
CtxtInterners {
arena,
type_: Default::default(),
return ty;
}
let global_interner = global_interners.map(|interners| {
- interners.type_.borrow_mut()
+ (interners.type_.borrow_mut(), &interners.arena)
});
- if let Some(ref interner) = global_interner {
- if let Some(&Interned(ty)) = interner.get(&st) {
+ if let Some((ref type_, _)) = global_interner {
+ if let Some(&Interned(ty)) = type_.get(&st) {
return ty;
}
}
// determine that all contents are in the global tcx.
// See comments on Lift for why we can't use that.
if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
- if let Some(interner) = global_interners {
+ if let Some((mut type_, arena)) = global_interner {
let ty_struct: TyS<'gcx> = unsafe {
mem::transmute(ty_struct)
};
- let ty: Ty<'gcx> = interner.arena.alloc(ty_struct);
- global_interner.unwrap().insert(Interned(ty));
+ let ty: Ty<'gcx> = arena.alloc(ty_struct);
+ type_.insert(Interned(ty));
return ty;
}
} else {
// Make sure we don't end up with inference
// types/regions in the global tcx.
- if global_interners.is_none() {
+ if global_interner.is_none() {
drop(interner);
bug!("Attempted to intern `{:?}` which contains \
inference types/regions in the global type context",
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
- /// Used to prevent layout from recursing too deeply.
- pub layout_depth: Cell<usize>,
-
stability_interner: Lock<FxHashSet<&'tcx attr::Stability>>,
pub interpret_interner: InterpretInterner<'tcx>,
crate_name: Symbol::intern(crate_name),
data_layout,
layout_interner: Lock::new(FxHashSet()),
- layout_depth: Cell::new(0),
stability_interner: Lock::new(FxHashSet()),
interpret_interner: Default::default(),
tx_to_llvm_workers: Lock::new(tx),
self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder)
}
- /// If true, we should use NLL-style region checking instead of
- /// lexical style.
- pub fn nll(self) -> bool {
- self.features().nll || self.sess.opts.debugging_opts.nll
- }
-
/// If true, we should use the MIR-based borrowck (we may *also* use
/// the AST-based borrowck).
- pub fn use_mir(self) -> bool {
+ pub fn use_mir_borrowck(self) -> bool {
self.borrowck_mode().use_mir()
}
mode @ BorrowckMode::Compare => mode,
mode @ BorrowckMode::Ast => {
- if self.nll() {
+ if self.features().nll {
BorrowckMode::Mir
} else {
mode
/// MIR borrowck, but not when NLL is used. They are also consumed
/// by the validation stuff.
pub fn emit_end_regions(self) -> bool {
- // FIXME(#46875) -- we should not emit end regions when NLL is enabled,
- // but for now we can't stop doing so because it causes false positives
self.sess.opts.debugging_opts.emit_end_regions ||
self.sess.opts.debugging_opts.mir_emit_validate > 0 ||
- self.use_mir()
+ self.use_mir_borrowck()
}
#[inline]
/// Call the closure with a local `TyCtxt` using the given arena.
pub fn enter_local<F, R>(
&self,
- arena: &'tcx DroplessArena,
+ arena: &'tcx SyncDroplessArena,
f: F
) -> R
where
let new_icx = ty::tls::ImplicitCtxt {
tcx,
query: icx.query.clone(),
+ layout_depth: icx.layout_depth,
};
ty::tls::enter_context(&new_icx, |new_icx| {
f(new_icx.tcx)
/// The current query job, if any. This is updated by start_job in
/// ty::maps::plumbing when executing a query
pub query: Option<Lrc<maps::QueryJob<'gcx>>>,
+
+ /// Used to prevent layout from recursing too deeply.
+ pub layout_depth: usize,
}
// A thread local value which stores a pointer to the current ImplicitCtxt
let icx = ImplicitCtxt {
tcx,
query: None,
+ layout_depth: 0,
};
enter_context(&icx, |_| {
f(tcx)
self.intern_tup(&[])
}
+ pub fn mk_diverging_default(self) -> Ty<'tcx> {
+ if self.features().never_type {
+ self.types.never
+ } else {
+ self.intern_tup(&[])
+ }
+ }
+
pub fn mk_bool(self) -> Ty<'tcx> {
self.mk_ty(TyBool)
}
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
-> Result<&'tcx LayoutDetails, LayoutError<'tcx>>
{
- let (param_env, ty) = query.into_parts();
+ ty::tls::with_related_context(tcx, move |icx| {
+ let rec_limit = *tcx.sess.recursion_limit.get();
+ let (param_env, ty) = query.into_parts();
- let rec_limit = *tcx.sess.recursion_limit.get();
- let depth = tcx.layout_depth.get();
- if depth > rec_limit {
- tcx.sess.fatal(
- &format!("overflow representing the type `{}`", ty));
- }
+ if icx.layout_depth > rec_limit {
+ tcx.sess.fatal(
+ &format!("overflow representing the type `{}`", ty));
+ }
- tcx.layout_depth.set(depth+1);
- let cx = LayoutCx { tcx, param_env };
- let layout = cx.layout_raw_uncached(ty);
- tcx.layout_depth.set(depth);
+ // Update the ImplicitCtxt to increase the layout_depth
+ let icx = ty::tls::ImplicitCtxt {
+ layout_depth: icx.layout_depth + 1,
+ ..icx.clone()
+ };
- layout
+ ty::tls::enter_context(&icx, |_| {
+ let cx = LayoutCx { tcx, param_env };
+ cx.layout_raw_uncached(ty)
+ })
+ })
}
pub fn provide(providers: &mut ty::maps::Providers) {
}
}
- let discr = Scalar {
+ let tag_mask = !0u128 >> (128 - ity.size().bits());
+ let tag = Scalar {
value: Int(ity, signed),
- valid_range: (min as u128)..=(max as u128)
+ valid_range: (min as u128 & tag_mask)..=(max as u128 & tag_mask),
};
- let abi = if discr.value.size(dl) == size {
- Abi::Scalar(discr.clone())
+ let abi = if tag.value.size(dl) == size {
+ Abi::Scalar(tag.clone())
} else {
Abi::Aggregate { sized: true }
};
tcx.intern_layout(LayoutDetails {
variants: Variants::Tagged {
- discr,
+ discr: tag,
variants
},
fields: FieldPlacement::Arbitrary {
}
}
-impl<'tcx> QueryDescription<'tcx> for queries::item_body_nested_bodies<'tcx> {
- fn describe(tcx: TyCtxt, def_id: DefId) -> String {
- format!("nested item bodies of `{}`", tcx.item_path_str(def_id))
- }
-}
-
impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_static<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("const checking if rvalue is promotable to static `{}`",
/// A span and a query key
#[derive(Clone, Debug)]
pub struct QueryInfo<'tcx> {
+ /// The span for a reason this query was required
pub span: Span,
pub query: Query<'tcx>,
}
cycle.insert(0, job.info.clone());
if &*job as *const _ == self as *const _ {
- break;
+ // This is the end of the cycle
+ // The span entry we included was for the usage
+ // of the cycle itself, and not part of the cycle
+ // Replace it with the span which caused the cycle to form
+ cycle[0].span = span;
+ // Find out why the cycle itself was used
+ let usage = job.parent.as_ref().map(|parent| {
+ (job.info.span, parent.info.query.clone())
+ });
+ return Err(CycleError { usage, cycle });
}
current_job = job.parent.clone();
}
- Err(CycleError { span, cycle })
+ panic!("did not find a cycle")
}
/// Signals to waiters that the query is complete.
use infer::canonical::{self, Canonical};
use lint;
use middle::borrowck::BorrowCheckResult;
-use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
- ExternBodyNestedBodies, ForeignModule};
-use middle::cstore::{NativeLibraryKind, DepKind, CrateSource, ExternConstBody};
+use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule};
+use middle::cstore::{NativeLibraryKind, DepKind, CrateSource};
use middle::privacy::AccessLevels;
use middle::reachable::ReachableSet;
use middle::region;
[] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>,
[] fn trans_fn_attrs: trans_fn_attrs(DefId) -> TransFnAttrs,
[] fn fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>,
+ /// Gets the rendered value of the specified constant or associated constant.
+ /// Used by rustdoc.
+ [] fn rendered_const: RenderedConst(DefId) -> String,
[] fn impl_parent: ImplParent(DefId) -> Option<DefId>,
[] fn trait_of_item: TraitOfItem(DefId) -> Option<DefId>,
- [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies,
[] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
[] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc<ItemLocalSet>,
[] fn is_mir_available: IsMirAvailable(DefId) -> bool,
[] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc<LanguageItems>,
[] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc<Vec<(DefId, usize)>>,
[] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc<Vec<LangItem>>,
- [] fn extern_const_body: ExternConstBody(DefId) -> ExternConstBody<'tcx>,
[] fn visible_parent_map: visible_parent_map_node(CrateNum)
-> Lrc<DefIdMap<DefId>>,
[] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool,
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
[] fn target_features_whitelist:
- target_features_whitelist_node(CrateNum) -> Lrc<FxHashSet<String>>,
+ target_features_whitelist_node(CrateNum) -> Lrc<FxHashMap<String, Option<String>>>,
// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
[] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>)
use ty::maps::job::QueryResult;
use ty::codec::{self as ty_codec, TyDecoder, TyEncoder};
use ty::context::TyCtxt;
+use util::common::time;
const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
// Encode query results
let mut query_result_index = EncodedQueryResultIndex::new();
- {
+ time(tcx.sess, "encode query results", || {
use ty::maps::queries::*;
let enc = &mut encoder;
let qri = &mut query_result_index;
}
}
}
- }
+
+ Ok(())
+ })?;
// Encode diagnostics
let diagnostics_index = {
E: 'enc + TyEncoder,
Q::Value: Encodable,
{
+ let desc = &format!("encode_query_results for {}",
+ unsafe { ::std::intrinsics::type_name::<Q>() });
+
+ time(tcx.sess, desc, || {
+
for (key, entry) in Q::get_cache_internal(tcx).map.iter() {
if Q::cache_on_disk(key.clone()) {
let entry = match *entry {
}
Ok(())
+ })
}
use errors::Level;
use ty::tls;
use ty::{TyCtxt};
+use ty::maps::Query;
use ty::maps::config::QueryDescription;
use ty::maps::job::{QueryResult, QueryInfo};
use ty::item_path;
#[derive(Clone)]
pub(super) struct CycleError<'tcx> {
- pub(super) span: Span,
+ /// The query and related span which uses the cycle
+ pub(super) usage: Option<(Span, Query<'tcx>)>,
pub(super) cycle: Vec<QueryInfo<'tcx>>,
}
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
- pub(super) fn report_cycle(self, CycleError { span, cycle: stack }: CycleError)
+ pub(super) fn report_cycle(self, CycleError { usage, cycle: stack }: CycleError<'gcx>)
-> DiagnosticBuilder<'a>
{
assert!(!stack.is_empty());
+ let fix_span = |span: Span, query: &Query<'gcx>| {
+ self.sess.codemap().def_span(query.default_span(self, span))
+ };
+
// Disable naming impls with types in this path, since that
// sometimes cycles itself, leading to extra cycle errors.
// (And cycle errors around impls tend to occur during the
// collect/coherence phases anyhow.)
item_path::with_forced_impl_filename_line(|| {
- let span = self.sess.codemap().def_span(span);
- let mut err =
- struct_span_err!(self.sess, span, E0391,
- "cyclic dependency detected");
- err.span_label(span, "cyclic reference");
-
- err.span_note(self.sess.codemap().def_span(stack[0].span),
- &format!("the cycle begins when {}...", stack[0].query.describe(self)));
-
- for &QueryInfo { span, ref query, .. } in &stack[1..] {
- err.span_note(self.sess.codemap().def_span(span),
- &format!("...which then requires {}...", query.describe(self)));
+ let span = fix_span(stack[1 % stack.len()].span, &stack[0].query);
+ let mut err = struct_span_err!(self.sess,
+ span,
+ E0391,
+ "cycle detected when {}",
+ stack[0].query.describe(self));
+
+ for i in 1..stack.len() {
+ let query = &stack[i].query;
+ let span = fix_span(stack[(i + 1) % stack.len()].span, query);
+ err.span_note(span, &format!("...which requires {}...", query.describe(self)));
}
- err.note(&format!("...which then again requires {}, completing the cycle.",
+ err.note(&format!("...which again requires {}, completing the cycle",
stack[0].query.describe(self)));
+ if let Some((span, query)) = usage {
+ err.span_note(fix_span(span, &query),
+ &format!("cycle used when {}", query.describe(self)));
+ }
+
return err
})
}
r
}
}
+
+ // FIXME(eddyb) Get more valid Span's on queries.
+ pub fn default_span(&self, tcx: TyCtxt<'_, $tcx, '_>, span: Span) -> Span {
+ if span != DUMMY_SP {
+ return span;
+ }
+ // The def_span query is used to calculate default_span,
+ // so exit to avoid infinite recursion
+ match *self {
+ Query::def_span(..) => return span,
+ _ => ()
+ }
+ match *self {
+ $(Query::$name(key) => key.default_span(tcx),)*
+ }
+ }
}
pub mod queries {
/// If the query already executed and panicked, this will fatal error / silently panic
fn try_get_lock(
tcx: TyCtxt<'a, $tcx, 'lcx>,
- mut span: Span,
+ span: Span,
key: &$K
) -> TryGetLock<'a, $tcx, $V, Self>
{
};
mem::drop(lock);
- // This just matches the behavior of `try_get_with` so the span when
- // we await matches the span we would use when executing.
- // See the FIXME there.
- if span == DUMMY_SP && stringify!($name) != "def_span" {
- span = key.default_span(tcx);
- }
-
if let Err(cycle) = job.await(tcx, span) {
return TryGetLock::JobCompleted(Err(cycle));
}
}
fn try_get_with(tcx: TyCtxt<'a, $tcx, 'lcx>,
- mut span: Span,
+ span: Span,
key: $K)
-> Result<$V, CycleError<$tcx>>
{
let mut lock = get_lock_or_return!();
- // FIXME(eddyb) Get more valid Span's on queries.
- // def_span guard is necessary to prevent a recursive loop,
- // default_span calls def_span query internally.
- if span == DUMMY_SP && stringify!($name) != "def_span" {
- // This might deadlock if we hold the map lock since we might be
- // waiting for the def_span query and switch to some other fiber
- // So we drop the lock here and reacquire it
- mem::drop(lock);
- span = key.default_span(tcx);
- lock = get_lock_or_return!();
- }
-
// Fast path for when incr. comp. is off. `to_dep_node` is
// expensive for some DepKinds.
if !tcx.dep_graph.is_fully_enabled() {
let icx = ty::tls::ImplicitCtxt {
tcx,
query: Some(job.clone()),
+ layout_depth: icx.layout_depth,
};
// Use the ImplicitCtxt while we execute the query
DepKind::LookupDeprecationEntry => {
force!(lookup_deprecation_entry, def_id!());
}
- DepKind::ItemBodyNestedBodies => { force!(item_body_nested_bodies, def_id!()); }
DepKind::ConstIsRvaluePromotableToStatic => {
force!(const_is_rvalue_promotable_to_static, def_id!());
}
DepKind::ItemAttrs => { force!(item_attrs, def_id!()); }
DepKind::TransFnAttrs => { force!(trans_fn_attrs, def_id!()); }
DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); }
+ DepKind::RenderedConst => { force!(rendered_const, def_id!()); }
DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); }
DepKind::IsPanicRuntime => { force!(is_panic_runtime, krate!()); }
DepKind::IsCompilerBuiltins => { force!(is_compiler_builtins, krate!()); }
DepKind::GetLangItems => { force!(get_lang_items, LOCAL_CRATE); }
DepKind::DefinedLangItems => { force!(defined_lang_items, krate!()); }
DepKind::MissingLangItems => { force!(missing_lang_items, krate!()); }
- DepKind::ExternConstBody => { force!(extern_const_body, def_id!()); }
DepKind::VisibleParentMap => { force!(visible_parent_map, LOCAL_CRATE); }
DepKind::MissingExternCrateItem => {
force!(missing_extern_crate_item, krate!());
}
}
- /// Returns the type of ty[i]
+ /// Returns the type of `ty[i]`.
pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
match self.sty {
TyArray(ty, _) | TySlice(ty) => Some(ty),
use rustc::middle::allocator::AllocatorKind;
use rustc_errors;
use syntax::abi::Abi;
-use syntax::ast::{Crate, Attribute, LitKind, StrStyle};
-use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg};
-use syntax::ast::{self, Ident, Item, ItemKind, TyKind, VisibilityKind, Expr};
+use syntax::ast::{Attribute, Crate, LitKind, StrStyle};
+use syntax::ast::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety};
+use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind};
use syntax::attr;
use syntax::codemap::{dummy_spanned, respan};
-use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
+use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan};
use syntax::ext::base::ExtCtxt;
use syntax::ext::base::Resolver;
use syntax::ext::build::AstBuilder;
use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
-pub fn modify(sess: &ParseSess,
- resolver: &mut Resolver,
- krate: Crate,
- handler: &rustc_errors::Handler) -> ast::Crate {
+pub fn modify(
+ sess: &ParseSess,
+ resolver: &mut Resolver,
+ krate: Crate,
+ handler: &rustc_errors::Handler,
+) -> ast::Crate {
ExpandAllocatorDirectives {
handler,
sess,
let name = if attr::contains_name(&item.attrs, "global_allocator") {
"global_allocator"
} else {
- return fold::noop_fold_item(item, self)
+ return fold::noop_fold_item(item, self);
};
match item.node {
ItemKind::Static(..) => {}
_ => {
- self.handler.span_err(item.span, "allocators must be statics");
- return SmallVector::one(item)
+ self.handler
+ .span_err(item.span, "allocators must be statics");
+ return SmallVector::one(item);
}
}
if self.found {
- self.handler.span_err(item.span, "cannot define more than one \
- #[global_allocator]");
- return SmallVector::one(item)
+ self.handler.span_err(
+ item.span,
+ "cannot define more than one \
+ #[global_allocator]",
+ );
+ return SmallVector::one(item);
}
self.found = true;
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
- }
+ },
});
let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark));
let ecfg = ExpansionConfig::default(name.to_string());
core: Ident::from_str("core"),
cx: ExtCtxt::new(self.sess, ecfg, self.resolver),
};
- let super_path = f.cx.path(f.span, vec![
- Ident::from_str("super"),
- f.global,
- ]);
+ let super_path = f.cx.path(f.span, vec![Ident::from_str("super"), f.global]);
let mut items = vec![
f.cx.item_extern_crate(f.span, f.core),
f.cx.item_use_simple(
let mut ret = SmallVector::new();
ret.push(item);
ret.push(module);
- return ret
+ return ret;
}
fn fold_mac(&mut self, mac: Mac) -> Mac {
i += 1;
name
};
- let args = method.inputs.iter().map(|ty| {
- self.arg_ty(ty, &mut abi_args, mk)
- }).collect();
+ let args = method
+ .inputs
+ .iter()
+ .map(|ty| self.arg_ty(ty, &mut abi_args, mk))
+ .collect();
let result = self.call_allocator(method.name, args);
let (output_ty, output_expr) = self.ret_ty(&method.output, result);
- let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)),
- Unsafety::Unsafe,
- dummy_spanned(Constness::NotConst),
- Abi::Rust,
- Generics::default(),
- self.cx.block_expr(output_expr));
- self.cx.item(self.span,
- Ident::from_str(&self.kind.fn_name(method.name)),
- self.attrs(),
- kind)
+ let kind = ItemKind::Fn(
+ self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)),
+ Unsafety::Unsafe,
+ dummy_spanned(Constness::NotConst),
+ Abi::Rust,
+ Generics::default(),
+ self.cx.block_expr(output_expr),
+ );
+ self.cx.item(
+ self.span,
+ Ident::from_str(&self.kind.fn_name(method.name)),
+ self.attrs(),
+ kind,
+ )
}
fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> {
- let method = self.cx.path(self.span, vec![
- self.core,
- Ident::from_str("alloc"),
- Ident::from_str("GlobalAlloc"),
- Ident::from_str(method),
- ]);
+ let method = self.cx.path(
+ self.span,
+ vec![
+ self.core,
+ Ident::from_str("alloc"),
+ Ident::from_str("GlobalAlloc"),
+ Ident::from_str(method),
+ ],
+ );
let method = self.cx.expr_path(method);
let allocator = self.cx.path_ident(self.span, self.global);
let allocator = self.cx.expr_path(allocator);
]
}
- fn arg_ty(&self,
- ty: &AllocatorTy,
- args: &mut Vec<Arg>,
- ident: &mut FnMut() -> Ident) -> P<Expr> {
+ fn arg_ty(
+ &self,
+ ty: &AllocatorTy,
+ args: &mut Vec<Arg>,
+ ident: &mut FnMut() -> Ident,
+ ) -> P<Expr> {
match *ty {
AllocatorTy::Layout => {
let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
args.push(self.cx.arg(self.span, size, ty_usize.clone()));
args.push(self.cx.arg(self.span, align, ty_usize));
- let layout_new = self.cx.path(self.span, vec![
- self.core,
- Ident::from_str("alloc"),
- Ident::from_str("Layout"),
- Ident::from_str("from_size_align_unchecked"),
- ]);
+ let layout_new = self.cx.path(
+ self.span,
+ vec![
+ self.core,
+ Ident::from_str("alloc"),
+ Ident::from_str("Layout"),
+ Ident::from_str("from_size_align_unchecked"),
+ ],
+ );
let layout_new = self.cx.expr_path(layout_new);
let size = self.cx.expr_ident(self.span, size);
let align = self.cx.expr_ident(self.span, align);
- let layout = self.cx.expr_call(self.span,
- layout_new,
- vec![size, align]);
+ let layout = self.cx.expr_call(self.span, layout_new, vec![size, align]);
layout
}
self.cx.expr_ident(self.span, ident)
}
- AllocatorTy::ResultPtr |
- AllocatorTy::Bang |
- AllocatorTy::Unit => {
+ AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("can't convert AllocatorTy to an argument")
}
}
(self.ptr_u8(), expr)
}
- AllocatorTy::Bang => {
- (self.cx.ty(self.span, TyKind::Never), expr)
- }
+ AllocatorTy::Unit => (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr),
- AllocatorTy::Unit => {
- (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr)
- }
-
- AllocatorTy::Layout |
- AllocatorTy::Usize |
- AllocatorTy::Ptr => {
+ AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("can't convert AllocatorTy to an output")
}
}
}
fn ptr_opaque(&self) -> P<Ty> {
- let opaque = self.cx.path(self.span, vec![
- self.core,
- Ident::from_str("alloc"),
- Ident::from_str("Opaque"),
- ]);
+ let opaque = self.cx.path(
+ self.span,
+ vec![
+ self.core,
+ Ident::from_str("alloc"),
+ Ident::from_str("Opaque"),
+ ],
+ );
let ty_opaque = self.cx.ty_path(opaque);
self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable)
}
inputs: &[AllocatorTy::Layout],
output: AllocatorTy::ResultPtr,
},
- AllocatorMethod {
- name: "oom",
- inputs: &[],
- output: AllocatorTy::Bang,
- },
AllocatorMethod {
name: "dealloc",
inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
}
pub enum AllocatorTy {
- Bang,
Layout,
Ptr,
ResultPtr,
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![forbid(unsafe_code)]
+#![feature(try_from)]
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
extern crate rustc_cratesio_shim;
base.is_like_android = true;
base.position_independent_executables = true;
base.has_elf_tls = false;
+ base.requires_uwtable = true;
base
}
/// Whether a .debug_gdb_scripts section will be added to the output object file
pub emit_debug_gdb_scripts: bool,
+
+ /// Whether or not to unconditionally `uwtable` attributes on functions,
+ /// typically because the platform needs to unwind for things like stack
+ /// unwinders.
+ pub requires_uwtable: bool,
}
impl Default for TargetOptions {
default_hidden_visibility: false,
embed_bitcode: false,
emit_debug_gdb_scripts: true,
+ requires_uwtable: false,
}
}
}
key!(default_hidden_visibility, bool);
key!(embed_bitcode, bool);
key!(emit_debug_gdb_scripts, bool);
+ key!(requires_uwtable, bool);
if let Some(array) = obj.find("abi-blacklist").and_then(Json::as_array) {
for name in array.iter().filter_map(|abi| abi.as_string()) {
target_option_val!(default_hidden_visibility);
target_option_val!(embed_bitcode);
target_option_val!(emit_debug_gdb_scripts);
+ target_option_val!(requires_uwtable);
if default.abi_blacklist != self.options.abi_blacklist {
d.insert("abi-blacklist".to_string(), self.options.abi_blacklist.iter()
custom_unwind_resume: true,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
+ requires_uwtable: true,
.. Default::default()
}
crt_static_respected: true,
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
+ requires_uwtable: true,
.. Default::default()
}
impl<A: Array> Drop for Iter<A> {
fn drop(&mut self) {
- for _ in self {}
+ self.for_each(drop);
}
}
impl<'a, A: Array> Drop for Drain<'a, A> {
fn drop(&mut self) {
// exhaust self first
- while let Some(_) = self.next() {}
+ self.for_each(drop);
if self.tail_len > 0 {
unsafe {
use rustc::ich::Fingerprint;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_mir as mir;
-use rustc::session::{Session, CompileResult, CrateDisambiguator};
+use rustc::session::{CompileResult, CrateDisambiguator, Session};
use rustc::session::CompileIncomplete;
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
use rustc::session::search_paths::PathKind;
use rustc::lint;
-use rustc::middle::{self, stability, reachable, resolve_lifetime};
+use rustc::middle::{self, reachable, resolve_lifetime, stability};
use rustc::middle::cstore::CrateStore;
use rustc::middle::privacy::AccessLevels;
-use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
+use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
use rustc::traits;
-use rustc::util::common::{ErrorReported, time, install_panic_hook};
+use rustc::util::common::{install_panic_hook, time, ErrorReported};
use rustc_allocator as allocator;
use rustc_borrowck as borrowck;
use rustc_incremental;
use rustc_privacy;
use rustc_plugin::registry::Registry;
use rustc_plugin as plugin;
-use rustc_passes::{self, ast_validation, loops, rvalue_promotion, hir_stats};
+use rustc_passes::{self, ast_validation, hir_stats, loops, rvalue_promotion};
use super::Compilation;
use serialize::json;
use std::any::Any;
use std::env;
-use std::ffi::{OsString, OsStr};
+use std::ffi::{OsStr, OsString};
use std::fs;
use std::io::{self, Write};
use std::iter;
use profile;
-pub fn compile_input(trans: Box<TransCrate>,
- sess: &Session,
- cstore: &CStore,
- input_path: &Option<PathBuf>,
- input: &Input,
- outdir: &Option<PathBuf>,
- output: &Option<PathBuf>,
- addl_plugins: Option<Vec<String>>,
- control: &CompileController) -> CompileResult {
+pub fn compile_input(
+ trans: Box<TransCrate>,
+ sess: &Session,
+ cstore: &CStore,
+ input_path: &Option<PathBuf>,
+ input: &Input,
+ outdir: &Option<PathBuf>,
+ output: &Option<PathBuf>,
+ addl_plugins: Option<Vec<String>>,
+ control: &CompileController,
+) -> CompileResult {
macro_rules! controller_entry_point {
($point: ident, $tsess: expr, $make_state: expr, $phase_result: expr) => {{
let state = &mut $make_state;
};
let (krate, registry) = {
- let mut compile_state = CompileState::state_after_parse(input,
- sess,
- outdir,
- output,
- krate,
- &cstore);
- controller_entry_point!(after_parse,
- sess,
- compile_state,
- Ok(()));
+ let mut compile_state =
+ CompileState::state_after_parse(input, sess, outdir, output, krate, &cstore);
+ controller_entry_point!(after_parse, sess, compile_state, Ok(()));
(compile_state.krate.unwrap(), compile_state.registry)
};
::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
install_panic_hook();
- let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
+ let ExpansionResult {
+ expanded_crate,
+ defs,
+ analysis,
+ resolutions,
+ mut hir_forest,
+ } = {
phase_2_configure_and_expand(
sess,
&cstore,
control.make_glob_map,
|expanded_crate| {
let mut state = CompileState::state_after_expand(
- input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
+ input,
+ sess,
+ outdir,
+ output,
+ &cstore,
+ expanded_crate,
+ &crate_name,
);
controller_entry_point!(after_expand, sess, state, Ok(()));
Ok(())
- }
+ },
)?
};
if output_contains_path(&output_paths, input_path) {
sess.err(&format!(
"the input file \"{}\" would be overwritten by the generated \
- executable",
- input_path.display()));
+ executable",
+ input_path.display()
+ ));
return Err(CompileIncomplete::Stopped);
}
if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
sess.err(&format!(
"the generated executable for the input file \"{}\" conflicts with the \
- existing directory \"{}\"",
- input_path.display(), dir_path.display()));
+ existing directory \"{}\"",
+ input_path.display(),
+ dir_path.display()
+ ));
return Err(CompileIncomplete::Stopped);
}
}
}
write_out_deps(sess, &outputs, &output_paths);
- if sess.opts.output_types.contains_key(&OutputType::DepInfo) &&
- sess.opts.output_types.keys().count() == 1 {
- return Ok(())
+ if sess.opts.output_types.contains_key(&OutputType::DepInfo)
+ && sess.opts.output_types.len() == 1
+ {
+ return Ok(());
}
if let &Some(ref dir) = outdir {
let arenas = AllArenas::new();
// Construct the HIR map
- let hir_map = time(sess,
- "indexing hir",
- || hir_map::map_crate(sess, cstore, &mut hir_forest, &defs));
+ let hir_map = time(sess, "indexing hir", || {
+ hir_map::map_crate(sess, cstore, &mut hir_forest, &defs)
+ });
{
hir_map.dep_graph.assert_ignored();
- controller_entry_point!(after_hir_lowering,
- sess,
- CompileState::state_after_hir_lowering(input,
- sess,
- outdir,
- output,
- &arenas,
- &cstore,
- &hir_map,
- &analysis,
- &resolutions,
- &expanded_crate,
- &hir_map.krate(),
- &outputs,
- &crate_name),
- Ok(()));
+ controller_entry_point!(
+ after_hir_lowering,
+ sess,
+ CompileState::state_after_hir_lowering(
+ input,
+ sess,
+ outdir,
+ output,
+ &arenas,
+ &cstore,
+ &hir_map,
+ &analysis,
+ &resolutions,
+ &expanded_crate,
+ &hir_map.krate(),
+ &outputs,
+ &crate_name
+ ),
+ Ok(())
+ );
}
let opt_crate = if control.keep_ast {
None
};
- phase_3_run_analysis_passes(&*trans,
- control,
- sess,
- cstore,
- hir_map,
- analysis,
- resolutions,
- &arenas,
- &crate_name,
- &outputs,
- |tcx, analysis, rx, result| {
- {
- // Eventually, we will want to track plugins.
- tcx.dep_graph.with_ignore(|| {
- let mut state = CompileState::state_after_analysis(input,
- sess,
- outdir,
- output,
- opt_crate,
- tcx.hir.krate(),
- &analysis,
- tcx,
- &crate_name);
- (control.after_analysis.callback)(&mut state);
- });
-
- if control.after_analysis.stop == Compilation::Stop {
- return result.and_then(|_| Err(CompileIncomplete::Stopped));
+ phase_3_run_analysis_passes(
+ &*trans,
+ control,
+ sess,
+ cstore,
+ hir_map,
+ analysis,
+ resolutions,
+ &arenas,
+ &crate_name,
+ &outputs,
+ |tcx, analysis, rx, result| {
+ {
+ // Eventually, we will want to track plugins.
+ tcx.dep_graph.with_ignore(|| {
+ let mut state = CompileState::state_after_analysis(
+ input,
+ sess,
+ outdir,
+ output,
+ opt_crate,
+ tcx.hir.krate(),
+ &analysis,
+ tcx,
+ &crate_name,
+ );
+ (control.after_analysis.callback)(&mut state);
+ });
+
+ if control.after_analysis.stop == Compilation::Stop {
+ return result.and_then(|_| Err(CompileIncomplete::Stopped));
+ }
}
- }
- result?;
+ result?;
- if log_enabled!(::log::Level::Info) {
- println!("Pre-trans");
- tcx.print_debug_stats();
- }
+ if log_enabled!(::log::Level::Info) {
+ println!("Pre-trans");
+ tcx.print_debug_stats();
+ }
- let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx);
+ let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx);
- if log_enabled!(::log::Level::Info) {
- println!("Post-trans");
- tcx.print_debug_stats();
- }
+ if log_enabled!(::log::Level::Info) {
+ println!("Post-trans");
+ tcx.print_debug_stats();
+ }
- if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
- if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) {
- sess.err(&format!("could not emit MIR: {}", e));
- sess.abort_if_errors();
+ if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
+ if let Err(e) = mir::transform::dump_mir::emit_mir(tcx, &outputs) {
+ sess.err(&format!("could not emit MIR: {}", e));
+ sess.abort_if_errors();
+ }
}
- }
- Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone()))
- })??
+ Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone()))
+ },
+ )??
};
if sess.opts.debugging_opts.print_type_sizes {
}
impl<'a, 'tcx> CompileState<'a, 'tcx> {
- fn empty(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>)
- -> Self {
+ fn empty(input: &'a Input, session: &'tcx Session, out_dir: &'a Option<PathBuf>) -> Self {
CompileState {
input,
session,
}
}
- fn state_after_parse(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>,
- krate: ast::Crate,
- cstore: &'tcx CStore)
- -> Self {
+ fn state_after_parse(
+ input: &'a Input,
+ session: &'tcx Session,
+ out_dir: &'a Option<PathBuf>,
+ out_file: &'a Option<PathBuf>,
+ krate: ast::Crate,
+ cstore: &'tcx CStore,
+ ) -> Self {
CompileState {
// Initialize the registry before moving `krate`
registry: Some(Registry::new(&session, krate.span)),
}
}
- fn state_after_expand(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>,
- cstore: &'tcx CStore,
- expanded_crate: &'a ast::Crate,
- crate_name: &'a str)
- -> Self {
+ fn state_after_expand(
+ input: &'a Input,
+ session: &'tcx Session,
+ out_dir: &'a Option<PathBuf>,
+ out_file: &'a Option<PathBuf>,
+ cstore: &'tcx CStore,
+ expanded_crate: &'a ast::Crate,
+ crate_name: &'a str,
+ ) -> Self {
CompileState {
crate_name: Some(crate_name),
cstore: Some(cstore),
}
}
- fn state_after_hir_lowering(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>,
- arenas: &'tcx AllArenas<'tcx>,
- cstore: &'tcx CStore,
- hir_map: &'a hir_map::Map<'tcx>,
- analysis: &'a ty::CrateAnalysis,
- resolutions: &'a Resolutions,
- krate: &'a ast::Crate,
- hir_crate: &'a hir::Crate,
- output_filenames: &'a OutputFilenames,
- crate_name: &'a str)
- -> Self {
+ fn state_after_hir_lowering(
+ input: &'a Input,
+ session: &'tcx Session,
+ out_dir: &'a Option<PathBuf>,
+ out_file: &'a Option<PathBuf>,
+ arenas: &'tcx AllArenas<'tcx>,
+ cstore: &'tcx CStore,
+ hir_map: &'a hir_map::Map<'tcx>,
+ analysis: &'a ty::CrateAnalysis,
+ resolutions: &'a Resolutions,
+ krate: &'a ast::Crate,
+ hir_crate: &'a hir::Crate,
+ output_filenames: &'a OutputFilenames,
+ crate_name: &'a str,
+ ) -> Self {
CompileState {
crate_name: Some(crate_name),
arenas: Some(arenas),
}
}
- fn state_after_analysis(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>,
- krate: Option<&'a ast::Crate>,
- hir_crate: &'a hir::Crate,
- analysis: &'a ty::CrateAnalysis,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- crate_name: &'a str)
- -> Self {
+ fn state_after_analysis(
+ input: &'a Input,
+ session: &'tcx Session,
+ out_dir: &'a Option<PathBuf>,
+ out_file: &'a Option<PathBuf>,
+ krate: Option<&'a ast::Crate>,
+ hir_crate: &'a hir::Crate,
+ analysis: &'a ty::CrateAnalysis,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ crate_name: &'a str,
+ ) -> Self {
CompileState {
analysis: Some(analysis),
tcx: Some(tcx),
}
}
- fn state_when_compilation_done(input: &'a Input,
- session: &'tcx Session,
- out_dir: &'a Option<PathBuf>,
- out_file: &'a Option<PathBuf>)
- -> Self {
+ fn state_when_compilation_done(
+ input: &'a Input,
+ session: &'tcx Session,
+ out_dir: &'a Option<PathBuf>,
+ out_file: &'a Option<PathBuf>,
+ ) -> Self {
CompileState {
out_file: out_file.as_ref().map(|s| &**s),
..CompileState::empty(input, session, out_dir)
}
}
-pub fn phase_1_parse_input<'a>(control: &CompileController,
- sess: &'a Session,
- input: &Input)
- -> PResult<'a, ast::Crate> {
- sess.diagnostic().set_continue_after_error(control.continue_parse_after_error);
+pub fn phase_1_parse_input<'a>(
+ control: &CompileController,
+ sess: &'a Session,
+ input: &Input,
+) -> PResult<'a, ast::Crate> {
+ sess.diagnostic()
+ .set_continue_after_error(control.continue_parse_after_error);
if sess.profile_queries() {
profile::begin(sess);
}
- let krate = time(sess, "parsing", || {
- match *input {
- Input::File(ref file) => {
- parse::parse_crate_from_file(file, &sess.parse_sess)
- }
- Input::Str { ref input, ref name } => {
- parse::parse_crate_from_source_str(name.clone(),
- input.clone(),
- &sess.parse_sess)
- }
- }
+ let krate = time(sess, "parsing", || match *input {
+ Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
+ Input::Str {
+ ref input,
+ ref name,
+ } => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
})?;
sess.diagnostic().set_continue_after_error(true);
}
if sess.opts.debugging_opts.input_stats {
- println!("Lines of code: {}", sess.codemap().count_lines());
+ println!(
+ "Lines of code: {}",
+ sess.codemap().count_lines()
+ );
println!("Pre-expansion node count: {}", count_nodes(&krate));
}
/// standard library and prelude, and name resolution.
///
/// Returns `None` if we're aborting after handling -W help.
-pub fn phase_2_configure_and_expand<F>(sess: &Session,
- cstore: &CStore,
- krate: ast::Crate,
- registry: Option<Registry>,
- crate_name: &str,
- addl_plugins: Option<Vec<String>>,
- make_glob_map: MakeGlobMap,
- after_expand: F)
- -> Result<ExpansionResult, CompileIncomplete>
- where F: FnOnce(&ast::Crate) -> CompileResult {
+pub fn phase_2_configure_and_expand<F>(
+ sess: &Session,
+ cstore: &CStore,
+ krate: ast::Crate,
+ registry: Option<Registry>,
+ crate_name: &str,
+ addl_plugins: Option<Vec<String>>,
+ make_glob_map: MakeGlobMap,
+ after_expand: F,
+) -> Result<ExpansionResult, CompileIncomplete>
+where
+ F: FnOnce(&ast::Crate) -> CompileResult,
+{
// Currently, we ignore the name resolution data structures for the purposes of dependency
// tracking. Instead we will run name resolution and include its output in the hash of each
// item, much like we do for macro expansion. In other words, the hash reflects not just
// this back at some point.
let mut crate_loader = CrateLoader::new(sess, &cstore, &crate_name);
let resolver_arenas = Resolver::arenas();
- let result = phase_2_configure_and_expand_inner(sess, cstore, krate, registry, crate_name,
- addl_plugins, make_glob_map, &resolver_arenas,
- &mut crate_loader, after_expand);
+ let result = phase_2_configure_and_expand_inner(
+ sess,
+ cstore,
+ krate,
+ registry,
+ crate_name,
+ addl_plugins,
+ make_glob_map,
+ &resolver_arenas,
+ &mut crate_loader,
+ after_expand,
+ );
match result {
- Ok(InnerExpansionResult {expanded_crate, resolver, hir_forest}) => {
- Ok(ExpansionResult {
- expanded_crate,
- defs: resolver.definitions,
- hir_forest,
- resolutions: Resolutions {
- freevars: resolver.freevars,
- export_map: resolver.export_map,
- trait_map: resolver.trait_map,
- maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
- maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
- },
-
- analysis: ty::CrateAnalysis {
- access_levels: Lrc::new(AccessLevels::default()),
- name: crate_name.to_string(),
- glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
+ Ok(InnerExpansionResult {
+ expanded_crate,
+ resolver,
+ hir_forest,
+ }) => Ok(ExpansionResult {
+ expanded_crate,
+ defs: resolver.definitions,
+ hir_forest,
+ resolutions: Resolutions {
+ freevars: resolver.freevars,
+ export_map: resolver.export_map,
+ trait_map: resolver.trait_map,
+ maybe_unused_trait_imports: resolver.maybe_unused_trait_imports,
+ maybe_unused_extern_crates: resolver.maybe_unused_extern_crates,
+ },
+
+ analysis: ty::CrateAnalysis {
+ access_levels: Lrc::new(AccessLevels::default()),
+ name: crate_name.to_string(),
+ glob_map: if resolver.make_glob_map {
+ Some(resolver.glob_map)
+ } else {
+ None
},
- })
- }
- Err(x) => Err(x)
+ },
+ }),
+ Err(x) => Err(x),
}
}
/// Same as phase_2_configure_and_expand, but doesn't let you keep the resolver
/// around
-pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
- cstore: &'a CStore,
- krate: ast::Crate,
- registry: Option<Registry>,
- crate_name: &str,
- addl_plugins: Option<Vec<String>>,
- make_glob_map: MakeGlobMap,
- resolver_arenas: &'a ResolverArenas<'a>,
- crate_loader: &'a mut CrateLoader,
- after_expand: F)
- -> Result<InnerExpansionResult<'a>, CompileIncomplete>
- where F: FnOnce(&ast::Crate) -> CompileResult,
+pub fn phase_2_configure_and_expand_inner<'a, F>(
+ sess: &'a Session,
+ cstore: &'a CStore,
+ krate: ast::Crate,
+ registry: Option<Registry>,
+ crate_name: &str,
+ addl_plugins: Option<Vec<String>>,
+ make_glob_map: MakeGlobMap,
+ resolver_arenas: &'a ResolverArenas<'a>,
+ crate_loader: &'a mut CrateLoader,
+ after_expand: F,
+) -> Result<InnerExpansionResult<'a>, CompileIncomplete>
+where
+ F: FnOnce(&ast::Crate) -> CompileResult,
{
- let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess,
- sess.opts.test,
- sess.opts.debugging_opts.edition);
+ let (mut krate, features) = syntax::config::features(
+ krate,
+ &sess.parse_sess,
+ sess.opts.test,
+ sess.edition(),
+ );
// these need to be set "early" so that expansion sees `quote` if enabled.
sess.init_features(features);
let disambiguator = compute_crate_disambiguator(sess);
sess.crate_disambiguator.set(disambiguator);
- rustc_incremental::prepare_session_directory(
- sess,
- &crate_name,
- disambiguator,
- );
+ rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
if sess.opts.incremental.is_some() {
time(sess, "garbage collect incremental cache directory", || {
if let Err(e) = rustc_incremental::garbage_collect_session_directories(sess) {
- warn!("Error while trying to garbage collect incremental \
- compilation cache directory: {}", e);
+ warn!(
+ "Error while trying to garbage collect incremental \
+ compilation cache directory: {}",
+ e
+ );
}
});
}
let mut addl_plugins = Some(addl_plugins);
let registrars = time(sess, "plugin loading", || {
- plugin::load::load_plugins(sess,
- &cstore,
- &krate,
- crate_name,
- addl_plugins.take().unwrap())
+ plugin::load::load_plugins(
+ sess,
+ &cstore,
+ &krate,
+ crate_name,
+ addl_plugins.take().unwrap(),
+ )
});
let mut registry = registry.unwrap_or(Registry::new(sess, krate.span));
time(sess, "plugin registration", || {
if sess.features_untracked().rustc_diagnostic_macros {
- registry.register_macro("__diagnostic_used",
- diagnostics::plugin::expand_diagnostic_used);
- registry.register_macro("__register_diagnostic",
- diagnostics::plugin::expand_register_diagnostic);
- registry.register_macro("__build_diagnostic_array",
- diagnostics::plugin::expand_build_diagnostic_array);
+ registry.register_macro(
+ "__diagnostic_used",
+ diagnostics::plugin::expand_diagnostic_used,
+ );
+ registry.register_macro(
+ "__register_diagnostic",
+ diagnostics::plugin::expand_register_diagnostic,
+ );
+ registry.register_macro(
+ "__build_diagnostic_array",
+ diagnostics::plugin::expand_build_diagnostic_array,
+ );
}
for registrar in registrars {
});
let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives();
- let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
- llvm_passes, attributes, .. } = registry;
+ let Registry {
+ syntax_exts,
+ early_lint_passes,
+ late_lint_passes,
+ lint_groups,
+ llvm_passes,
+ attributes,
+ ..
+ } = registry;
sess.track_errors(|| {
let mut ls = sess.lint_store.borrow_mut();
return Err(CompileIncomplete::Stopped);
}
- let mut resolver = Resolver::new(sess,
- cstore,
- &krate,
- crate_name,
- make_glob_map,
- crate_loader,
- &resolver_arenas);
+ let mut resolver = Resolver::new(
+ sess,
+ cstore,
+ &krate,
+ crate_name,
+ make_glob_map,
+ crate_loader,
+ &resolver_arenas,
+ );
resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives;
syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote);
+ // Expand all macros
krate = time(sess, "expansion", || {
// Windows dlls do not have rpaths, so they don't know how to find their
// dependencies. It's up to us to tell the system where to find all the
let mut old_path = OsString::new();
if cfg!(windows) {
old_path = env::var_os("PATH").unwrap_or(old_path);
- let mut new_path = sess.host_filesearch(PathKind::All)
- .get_dylib_search_paths();
+ let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths();
for path in env::split_paths(&old_path) {
if !new_path.contains(&path) {
new_path.push(path);
}
}
- env::set_var("PATH",
- &env::join_paths(new_path.iter()
- .filter(|p| env::join_paths(iter::once(p)).is_ok()))
- .unwrap());
+ env::set_var(
+ "PATH",
+ &env::join_paths(
+ new_path
+ .iter()
+ .filter(|p| env::join_paths(iter::once(p)).is_ok()),
+ ).unwrap(),
+ );
}
+
+ // Create the config for macro expansion
let features = sess.features_untracked();
let cfg = syntax::ext::expand::ExpansionConfig {
features: Some(&features),
let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver);
let err_count = ecx.parse_sess.span_diagnostic.err_count();
- let krate = ecx.monotonic_expander().expand_crate(krate);
+ // Expand macros now!
+ let krate = time(sess, "expand crate", || {
+ ecx.monotonic_expander().expand_crate(krate)
+ });
- ecx.check_unused_macros();
+ // The rest is error reporting
- let mut missing_fragment_specifiers: Vec<_> =
- ecx.parse_sess.missing_fragment_specifiers.borrow().iter().cloned().collect();
+ time(sess, "check unused macros", || {
+ ecx.check_unused_macros();
+ });
+
+ let mut missing_fragment_specifiers: Vec<_> = ecx.parse_sess
+ .missing_fragment_specifiers
+ .borrow()
+ .iter()
+ .cloned()
+ .collect();
missing_fragment_specifiers.sort();
for span in missing_fragment_specifiers {
let lint = lint::builtin::MISSING_FRAGMENT_SPECIFIER;
});
krate = time(sess, "maybe building test harness", || {
- syntax::test::modify_for_testing(&sess.parse_sess,
- &mut resolver,
- sess.opts.test,
- krate,
- sess.diagnostic(),
- &sess.features_untracked())
+ syntax::test::modify_for_testing(
+ &sess.parse_sess,
+ &mut resolver,
+ sess.opts.test,
+ krate,
+ sess.diagnostic(),
+ &sess.features_untracked(),
+ )
});
// If we're actually rustdoc then there's no need to actually compile
let num_crate_types = crate_types.len();
let is_proc_macro_crate = crate_types.contains(&config::CrateTypeProcMacro);
let is_test_crate = sess.opts.test;
- syntax_ext::proc_macro_registrar::modify(&sess.parse_sess,
- &mut resolver,
- krate,
- is_proc_macro_crate,
- is_test_crate,
- num_crate_types,
- sess.diagnostic())
+ syntax_ext::proc_macro_registrar::modify(
+ &sess.parse_sess,
+ &mut resolver,
+ krate,
+ is_proc_macro_crate,
+ is_test_crate,
+ num_crate_types,
+ sess.diagnostic(),
+ )
});
}
krate = time(sess, "creating allocators", || {
- allocator::expand::modify(&sess.parse_sess,
- &mut resolver,
- krate,
- sess.diagnostic())
+ allocator::expand::modify(&sess.parse_sess, &mut resolver, krate, sess.diagnostic())
});
after_expand(&krate)?;
println!("{}", json::as_json(&krate));
}
- time(sess,
- "AST validation",
- || ast_validation::check_crate(sess, &krate));
+ time(sess, "AST validation", || {
+ ast_validation::check_crate(sess, &krate)
+ });
time(sess, "name resolution", || -> CompileResult {
resolver.resolve_crate(&krate);
// Needs to go *after* expansion to be able to check the results of macro expansion.
time(sess, "complete gated feature checking", || {
sess.track_errors(|| {
- syntax::feature_gate::check_crate(&krate,
- &sess.parse_sess,
- &sess.features_untracked(),
- &attributes,
- sess.opts.unstable_features);
+ syntax::feature_gate::check_crate(
+ &krate,
+ &sess.parse_sess,
+ &sess.features_untracked(),
+ &attributes,
+ sess.opts.unstable_features,
+ );
})
})?;
None => DepGraph::new_disabled(),
Some(future) => {
let prev_graph = time(sess, "blocked while dep-graph loading finishes", || {
- future.open()
- .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
- message: format!("could not decode incremental cache: {:?}", e)
- })
- .open(sess)
+ future
+ .open()
+ .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
+ message: format!("could not decode incremental cache: {:?}", e),
+ })
+ .open(sess)
});
DepGraph::new(prev_graph)
}
hir_map::Forest::new(hir_crate, &dep_graph)
});
- time(sess,
- "early lint checks",
- || lint::check_ast_crate(sess, &krate));
+ time(sess, "early lint checks", || {
+ lint::check_ast_crate(sess, &krate)
+ });
// Discard hygiene data, which isn't required after lowering to HIR.
if !sess.opts.debugging_opts.keep_hygiene_data {
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx, F, R>(trans: &TransCrate,
- control: &CompileController,
- sess: &'tcx Session,
- cstore: &'tcx CrateStore,
- hir_map: hir_map::Map<'tcx>,
- mut analysis: ty::CrateAnalysis,
- resolutions: Resolutions,
- arenas: &'tcx AllArenas<'tcx>,
- name: &str,
- output_filenames: &OutputFilenames,
- f: F)
- -> Result<R, CompileIncomplete>
- where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
- ty::CrateAnalysis,
- mpsc::Receiver<Box<Any + Send>>,
- CompileResult) -> R
+pub fn phase_3_run_analysis_passes<'tcx, F, R>(
+ trans: &TransCrate,
+ control: &CompileController,
+ sess: &'tcx Session,
+ cstore: &'tcx CrateStore,
+ hir_map: hir_map::Map<'tcx>,
+ mut analysis: ty::CrateAnalysis,
+ resolutions: Resolutions,
+ arenas: &'tcx AllArenas<'tcx>,
+ name: &str,
+ output_filenames: &OutputFilenames,
+ f: F,
+) -> Result<R, CompileIncomplete>
+where
+ F: for<'a> FnOnce(
+ TyCtxt<'a, 'tcx, 'tcx>,
+ ty::CrateAnalysis,
+ mpsc::Receiver<Box<Any + Send>>,
+ CompileResult,
+ ) -> R,
{
- let query_result_on_disk_cache = time(sess,
- "load query result cache",
- || rustc_incremental::load_query_result_cache(sess));
+ let query_result_on_disk_cache = time(sess, "load query result cache", || {
+ rustc_incremental::load_query_result_cache(sess)
+ });
- time(sess,
- "looking for entry point",
- || middle::entry::find_entry_point(sess, &hir_map, name));
+ time(sess, "looking for entry point", || {
+ middle::entry::find_entry_point(sess, &hir_map, name)
+ });
- sess.plugin_registrar_fn.set(time(sess, "looking for plugin registrar", || {
- plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map)
- }));
- sess.derive_registrar_fn.set(derive_registrar::find(&hir_map));
+ sess.plugin_registrar_fn
+ .set(time(sess, "looking for plugin registrar", || {
+ plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map)
+ }));
+ sess.derive_registrar_fn
+ .set(derive_registrar::find(&hir_map));
- time(sess,
- "loop checking",
- || loops::check_crate(sess, &hir_map));
+ time(sess, "loop checking", || loops::check_crate(sess, &hir_map));
let mut local_providers = ty::maps::Providers::default();
default_provide(&mut local_providers);
let (tx, rx) = mpsc::channel();
- TyCtxt::create_and_enter(sess,
- cstore,
- local_providers,
- extern_providers,
- arenas,
- resolutions,
- hir_map,
- query_result_on_disk_cache,
- name,
- tx,
- output_filenames,
- |tcx| {
- // Do some initialization of the DepGraph that can only be done with the
- // tcx available.
- rustc_incremental::dep_graph_tcx_init(tcx);
-
- time(sess, "attribute checking", || {
- hir::check_attr::check_crate(tcx)
- });
+ TyCtxt::create_and_enter(
+ sess,
+ cstore,
+ local_providers,
+ extern_providers,
+ arenas,
+ resolutions,
+ hir_map,
+ query_result_on_disk_cache,
+ name,
+ tx,
+ output_filenames,
+ |tcx| {
+ // Do some initialization of the DepGraph that can only be done with the
+ // tcx available.
+ rustc_incremental::dep_graph_tcx_init(tcx);
+
+ time(sess, "attribute checking", || {
+ hir::check_attr::check_crate(tcx)
+ });
- time(sess,
- "stability checking",
- || stability::check_unstable_api_usage(tcx));
+ time(sess, "stability checking", || {
+ stability::check_unstable_api_usage(tcx)
+ });
- // passes are timed inside typeck
- match typeck::check_crate(tcx) {
- Ok(x) => x,
- Err(x) => {
- f(tcx, analysis, rx, Err(x));
- return Err(x);
+ // passes are timed inside typeck
+ match typeck::check_crate(tcx) {
+ Ok(x) => x,
+ Err(x) => {
+ f(tcx, analysis, rx, Err(x));
+ return Err(x);
+ }
}
- }
- time(sess,
- "rvalue promotion",
- || rvalue_promotion::check_crate(tcx));
+ time(sess, "rvalue promotion", || {
+ rvalue_promotion::check_crate(tcx)
+ });
- analysis.access_levels =
- time(sess, "privacy checking", || rustc_privacy::check_crate(tcx));
+ analysis.access_levels =
+ time(sess, "privacy checking", || rustc_privacy::check_crate(tcx));
- time(sess,
- "intrinsic checking",
- || middle::intrinsicck::check_crate(tcx));
+ time(sess, "intrinsic checking", || {
+ middle::intrinsicck::check_crate(tcx)
+ });
- time(sess,
- "match checking",
- || mir::matchck_crate(tcx));
+ time(sess, "match checking", || mir::matchck_crate(tcx));
- // this must run before MIR dump, because
- // "not all control paths return a value" is reported here.
- //
- // maybe move the check to a MIR pass?
- time(sess,
- "liveness checking",
- || middle::liveness::check_crate(tcx));
-
- time(sess,
- "borrow checking",
- || borrowck::check_crate(tcx));
-
- time(sess,
- "MIR borrow checking",
- || for def_id in tcx.body_owners() { tcx.mir_borrowck(def_id); });
-
- time(sess,
- "MIR effect checking",
- || for def_id in tcx.body_owners() {
- mir::transform::check_unsafety::check_unsafety(tcx, def_id)
- });
- // Avoid overwhelming user with errors if type checking failed.
- // I'm not sure how helpful this is, to be honest, but it avoids
- // a
- // lot of annoying errors in the compile-fail tests (basically,
- // lint warnings and so on -- kindck used to do this abort, but
- // kindck is gone now). -nmatsakis
- if sess.err_count() > 0 {
- return Ok(f(tcx, analysis, rx, sess.compile_status()));
- }
+ // this must run before MIR dump, because
+ // "not all control paths return a value" is reported here.
+ //
+ // maybe move the check to a MIR pass?
+ time(sess, "liveness checking", || {
+ middle::liveness::check_crate(tcx)
+ });
- time(sess, "death checking", || middle::dead::check_crate(tcx));
+ time(sess, "borrow checking", || borrowck::check_crate(tcx));
- time(sess, "unused lib feature checking", || {
- stability::check_unused_or_stable_features(tcx)
- });
+ time(sess, "MIR borrow checking", || {
+ for def_id in tcx.body_owners() {
+ tcx.mir_borrowck(def_id);
+ }
+ });
- time(sess, "lint checking", || lint::check_crate(tcx));
+ time(sess, "MIR effect checking", || {
+ for def_id in tcx.body_owners() {
+ mir::transform::check_unsafety::check_unsafety(tcx, def_id)
+ }
+ });
+ // Avoid overwhelming user with errors if type checking failed.
+ // I'm not sure how helpful this is, to be honest, but it avoids
+ // a
+ // lot of annoying errors in the compile-fail tests (basically,
+ // lint warnings and so on -- kindck used to do this abort, but
+ // kindck is gone now). -nmatsakis
+ if sess.err_count() > 0 {
+ return Ok(f(tcx, analysis, rx, sess.compile_status()));
+ }
- time(sess,
- "dumping chalk-like clauses",
- || rustc_traits::lowering::dump_program_clauses(tcx));
+ time(sess, "death checking", || middle::dead::check_crate(tcx));
- return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
- })
+ time(sess, "unused lib feature checking", || {
+ stability::check_unused_or_stable_features(tcx)
+ });
+
+ time(sess, "lint checking", || lint::check_crate(tcx));
+
+ time(sess, "dumping chalk-like clauses", || {
+ rustc_traits::lowering::dump_program_clauses(tcx)
+ });
+
+ return Ok(f(tcx, analysis, rx, tcx.sess.compile_status()));
+ },
+ )
}
/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
-pub fn phase_4_translate_to_llvm<'a, 'tcx>(trans: &TransCrate,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- rx: mpsc::Receiver<Box<Any + Send>>)
- -> Box<Any> {
- time(tcx.sess,
- "resolving dependency formats",
- || ::rustc::middle::dependency_format::calculate(tcx));
-
- let translation =
- time(tcx.sess, "translation", move || {
- trans.trans_crate(tcx, rx)
- });
+pub fn phase_4_translate_to_llvm<'a, 'tcx>(
+ trans: &TransCrate,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ rx: mpsc::Receiver<Box<Any + Send>>,
+) -> Box<Any> {
+ time(tcx.sess, "resolving dependency formats", || {
+ ::rustc::middle::dependency_format::calculate(tcx)
+ });
+
+ let translation = time(tcx.sess, "translation", move || trans.trans_crate(tcx, rx));
if tcx.sess.profile_queries() {
profile::dump(&tcx.sess, "profile_queries".to_string())
}
}
// Returns all the paths that correspond to generated files.
-fn generated_output_paths(sess: &Session,
- outputs: &OutputFilenames,
- exact_name: bool,
- crate_name: &str) -> Vec<PathBuf> {
+fn generated_output_paths(
+ sess: &Session,
+ outputs: &OutputFilenames,
+ exact_name: bool,
+ crate_name: &str,
+) -> Vec<PathBuf> {
let mut out_filenames = Vec::new();
for output_type in sess.opts.output_types.keys() {
let file = outputs.path(*output_type);
match *output_type {
// If the filename has been overridden using `-o`, it will not be modified
// by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
- OutputType::Exe if !exact_name => {
- for crate_type in sess.crate_types.borrow().iter() {
- let p = ::rustc_trans_utils::link::filename_for_input(
- sess,
- *crate_type,
- crate_name,
- outputs
- );
- out_filenames.push(p);
- }
- }
+ OutputType::Exe if !exact_name => for crate_type in sess.crate_types.borrow().iter() {
+ let p = ::rustc_trans_utils::link::filename_for_input(
+ sess,
+ *crate_type,
+ crate_name,
+ outputs,
+ );
+ out_filenames.push(p);
+ },
OutputType::DepInfo if sess.opts.debugging_opts.dep_info_omit_d_target => {
// Don't add the dep-info output when omitting it from dep-info targets
}
// Runs `f` on every output file path and returns the first non-None result, or None if `f`
// returns None for every file path.
fn check_output<F, T>(output_paths: &Vec<PathBuf>, f: F) -> Option<T>
- where F: Fn(&PathBuf) -> Option<T> {
- for output_path in output_paths {
- if let Some(result) = f(output_path) {
- return Some(result);
- }
- }
- None
+where
+ F: Fn(&PathBuf) -> Option<T>,
+{
+ for output_path in output_paths {
+ if let Some(result) = f(output_path) {
+ return Some(result);
+ }
+ }
+ None
}
pub fn output_contains_path(output_paths: &Vec<PathBuf>, input_path: &PathBuf) -> bool {
let input_path = input_path.canonicalize().ok();
if input_path.is_none() {
- return false
+ return false;
}
let check = |output_path: &PathBuf| {
if output_path.canonicalize().ok() == input_path {
Some(())
- } else { None }
+ } else {
+ None
+ }
};
check_output(output_paths, check).is_some()
}
let check = |output_path: &PathBuf| {
if output_path.is_dir() {
Some(output_path.clone())
- } else { None }
+ } else {
+ None
+ }
};
check_output(output_paths, check)
}
-fn write_out_deps(sess: &Session,
- outputs: &OutputFilenames,
- out_filenames: &Vec<PathBuf>) {
+fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &Vec<PathBuf>) {
// Write out dependency rules to the dep-info file if requested
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
return;
}
let deps_filename = outputs.path(OutputType::DepInfo);
- let result =
- (|| -> io::Result<()> {
- // Build a list of files used to compile the output and
- // write Makefile-compatible dependency rules
- let files: Vec<String> = sess.codemap()
- .files()
- .iter()
- .filter(|fmap| fmap.is_real_file())
- .filter(|fmap| !fmap.is_imported())
- .map(|fmap| escape_dep_filename(&fmap.name))
- .collect();
- let mut file = fs::File::create(&deps_filename)?;
- for path in out_filenames {
- write!(file, "{}: {}\n\n", path.display(), files.join(" "))?;
- }
+ let result = (|| -> io::Result<()> {
+ // Build a list of files used to compile the output and
+ // write Makefile-compatible dependency rules
+ let files: Vec<String> = sess.codemap()
+ .files()
+ .iter()
+ .filter(|fmap| fmap.is_real_file())
+ .filter(|fmap| !fmap.is_imported())
+ .map(|fmap| escape_dep_filename(&fmap.name))
+ .collect();
+ let mut file = fs::File::create(&deps_filename)?;
+ for path in out_filenames {
+ write!(file, "{}: {}\n\n", path.display(), files.join(" "))?;
+ }
- // Emit a fake target for each input file to the compilation. This
- // prevents `make` from spitting out an error if a file is later
- // deleted. For more info see #28735
- for path in files {
- writeln!(file, "{}:", path)?;
- }
- Ok(())
- })();
+ // Emit a fake target for each input file to the compilation. This
+ // prevents `make` from spitting out an error if a file is later
+ // deleted. For more info see #28735
+ for path in files {
+ writeln!(file, "{}:", path)?;
+ }
+ Ok(())
+ })();
match result {
Ok(()) => {}
Err(e) => {
- sess.fatal(&format!("error writing dependencies to `{}`: {}",
- deps_filename.display(),
- e));
+ sess.fatal(&format!(
+ "error writing dependencies to `{}`: {}",
+ deps_filename.display(),
+ e
+ ));
}
}
}
pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<config::CrateType> {
// Unconditionally collect crate types from attributes to make them used
- let attr_types: Vec<config::CrateType> =
- attrs.iter()
- .filter_map(|a| {
- if a.check_name("crate_type") {
- match a.value_str() {
- Some(ref n) if *n == "rlib" => {
- Some(config::CrateTypeRlib)
- }
- Some(ref n) if *n == "dylib" => {
- Some(config::CrateTypeDylib)
- }
- Some(ref n) if *n == "cdylib" => {
- Some(config::CrateTypeCdylib)
- }
- Some(ref n) if *n == "lib" => {
- Some(config::default_lib_output())
- }
- Some(ref n) if *n == "staticlib" => {
- Some(config::CrateTypeStaticlib)
- }
- Some(ref n) if *n == "proc-macro" => {
- Some(config::CrateTypeProcMacro)
- }
- Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
- Some(_) => {
- session.buffer_lint(lint::builtin::UNKNOWN_CRATE_TYPES,
- ast::CRATE_NODE_ID,
- a.span,
- "invalid `crate_type` value");
- None
- }
- _ => {
- session.struct_span_err(a.span, "`crate_type` requires a value")
- .note("for example: `#![crate_type=\"lib\"]`")
- .emit();
- None
- }
- }
- } else {
- None
- }
- })
- .collect();
+ let attr_types: Vec<config::CrateType> = attrs
+ .iter()
+ .filter_map(|a| {
+ if a.check_name("crate_type") {
+ match a.value_str() {
+ Some(ref n) if *n == "rlib" => Some(config::CrateTypeRlib),
+ Some(ref n) if *n == "dylib" => Some(config::CrateTypeDylib),
+ Some(ref n) if *n == "cdylib" => Some(config::CrateTypeCdylib),
+ Some(ref n) if *n == "lib" => Some(config::default_lib_output()),
+ Some(ref n) if *n == "staticlib" => Some(config::CrateTypeStaticlib),
+ Some(ref n) if *n == "proc-macro" => Some(config::CrateTypeProcMacro),
+ Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable),
+ Some(_) => {
+ session.buffer_lint(
+ lint::builtin::UNKNOWN_CRATE_TYPES,
+ ast::CRATE_NODE_ID,
+ a.span,
+ "invalid `crate_type` value",
+ );
+ None
+ }
+ _ => {
+ session
+ .struct_span_err(a.span, "`crate_type` requires a value")
+ .note("for example: `#![crate_type=\"lib\"]`")
+ .emit();
+ None
+ }
+ }
+ } else {
+ None
+ }
+ })
+ .collect();
// If we're generating a test executable, then ignore all other output
// styles at all other locations
if base.is_empty() {
base.extend(attr_types);
if base.is_empty() {
- base.push(::rustc_trans_utils::link::default_output_for_target(session));
+ base.push(::rustc_trans_utils::link::default_output_for_target(
+ session,
+ ));
}
base.sort();
base.dedup();
let res = !::rustc_trans_utils::link::invalid_output_for_target(session, *crate_type);
if !res {
- session.warn(&format!("dropping unsupported crate type `{}` for target `{}`",
- *crate_type,
- session.opts.target_triple));
+ session.warn(&format!(
+ "dropping unsupported crate type `{}` for target `{}`",
+ *crate_type, session.opts.target_triple
+ ));
}
res
// Also incorporate crate type, so that we don't get symbol conflicts when
// linking against a library of the same name, if this is an executable.
- let is_exe = session.crate_types.borrow().contains(&config::CrateTypeExecutable);
+ let is_exe = session
+ .crate_types
+ .borrow()
+ .contains(&config::CrateTypeExecutable);
hasher.write(if is_exe { b"exe" } else { b"lib" });
CrateDisambiguator::from(hasher.finish())
-
}
-pub fn build_output_filenames(input: &Input,
- odir: &Option<PathBuf>,
- ofile: &Option<PathBuf>,
- attrs: &[ast::Attribute],
- sess: &Session)
- -> OutputFilenames {
+pub fn build_output_filenames(
+ input: &Input,
+ odir: &Option<PathBuf>,
+ ofile: &Option<PathBuf>,
+ attrs: &[ast::Attribute],
+ sess: &Session,
+) -> OutputFilenames {
match *ofile {
None => {
// "-" as input file will cause the parser to read from stdin so we
// If a crate name is present, we use it as the link name
let stem = sess.opts
- .crate_name
- .clone()
- .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string()))
- .unwrap_or(input.filestem());
+ .crate_name
+ .clone()
+ .or_else(|| attr::find_crate_name(attrs).map(|n| n.to_string()))
+ .unwrap_or(input.filestem());
OutputFilenames {
out_directory: dirpath,
Some(ref out_file) => {
let unnamed_output_types = sess.opts
- .output_types
- .values()
- .filter(|a| a.is_none())
- .count();
+ .output_types
+ .values()
+ .filter(|a| a.is_none())
+ .count();
let ofile = if unnamed_output_types > 1 {
- sess.warn("due to multiple output types requested, the explicitly specified \
- output file name will be adapted for each output type");
+ sess.warn(
+ "due to multiple output types requested, the explicitly specified \
+ output file name will be adapted for each output type",
+ );
None
} else {
Some(out_file.clone())
OutputFilenames {
out_directory: out_file.parent().unwrap_or(cur_dir).to_path_buf(),
- out_filestem: out_file.file_stem()
- .unwrap_or(OsStr::new(""))
- .to_str()
- .unwrap()
- .to_string(),
+ out_filestem: out_file
+ .file_stem()
+ .unwrap_or(OsStr::new(""))
+ .to_str()
+ .unwrap()
+ .to_string(),
single_output_file: ofile,
extra: sess.opts.cg.extra_filename.clone(),
outputs: sess.opts.output_types.clone(),
#![feature(slice_sort_by_cached_key)]
#![feature(set_stdio)]
#![feature(rustc_stack_internals)]
+#![feature(no_debug)]
extern crate arena;
extern crate getopts;
pub fn get_trans(sess: &Session) -> Box<TransCrate> {
static INIT: Once = ONCE_INIT;
+
+ #[allow(deprecated)]
+ #[no_debug]
static mut LOAD: fn() -> Box<TransCrate> = || unreachable!();
INIT.call_once(|| {
(result, Some(sess))
}
+#[cfg(unix)]
+pub fn set_sigpipe_handler() {
+ unsafe {
+ // Set the SIGPIPE signal handler, so that an EPIPE
+ // will cause rustc to terminate, as expected.
+ assert!(libc::signal(libc::SIGPIPE, libc::SIG_DFL) != libc::SIG_ERR);
+ }
+}
+
+#[cfg(windows)]
+pub fn set_sigpipe_handler() {}
+
// Extract output directory and file from matches.
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
use rustc::hir::map as hir_map;
use rustc::session::{self, config};
use rustc::session::config::{OutputFilenames, OutputTypes};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
use syntax;
use syntax::ast;
use syntax::abi::Abi;
}
}
-fn errors(msgs: &[&str]) -> (Box<Emitter + Send>, usize) {
+fn errors(msgs: &[&str]) -> (Box<Emitter + sync::Send>, usize) {
let v = msgs.iter().map(|m| m.to_string()).collect();
- (box ExpectErrorEmitter { messages: v } as Box<Emitter + Send>, msgs.len())
+ (box ExpectErrorEmitter { messages: v } as Box<Emitter + sync::Send>, msgs.len())
}
fn test_env<F>(source_string: &str,
- args: (Box<Emitter + Send>, usize),
+ args: (Box<Emitter + sync::Send>, usize),
body: F)
where F: FnOnce(Env)
{
}
fn test_env_impl<F>(source_string: &str,
- (emitter, expected_err_count): (Box<Emitter + Send>, usize),
+ (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
body: F)
where F: FnOnce(Env)
{
} else {
0
};
- (b_start..b_end + extra).contains(a_start) ||
- (a_start..a_end + extra).contains(b_start)
+ (b_start..b_end + extra).contains(&a_start) ||
+ (a_start..a_end + extra).contains(&b_start)
}
fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false)
use emitter::{Emitter, EmitterWriter};
-use rustc_data_structures::sync::{self, Lrc};
+use rustc_data_structures::sync::{self, Lrc, Lock, LockCell};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stable_hasher::StableHasher;
use std::borrow::Cow;
-use std::cell::{RefCell, Cell};
+use std::cell::Cell;
use std::{error, fmt};
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
pub flags: HandlerFlags,
err_count: AtomicUsize,
- emitter: RefCell<Box<Emitter>>,
- continue_after_error: Cell<bool>,
- delayed_span_bug: RefCell<Option<Diagnostic>>,
+ emitter: Lock<Box<Emitter + sync::Send>>,
+ continue_after_error: LockCell<bool>,
+ delayed_span_bug: Lock<Option<Diagnostic>>,
// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
// emitting the same diagnostic with extended help (`--teach`) twice, which
// would be uneccessary repetition.
- tracked_diagnostic_codes: RefCell<FxHashSet<DiagnosticId>>,
+ taught_diagnostics: Lock<FxHashSet<DiagnosticId>>,
+
+ /// Used to suggest rustc --explain <error code>
+ emitted_diagnostic_codes: Lock<FxHashSet<DiagnosticId>>,
// This set contains a hash of every diagnostic that has been emitted by
// this handler. These hashes is used to avoid emitting the same error
// twice.
- emitted_diagnostics: RefCell<FxHashSet<u128>>,
+ emitted_diagnostics: Lock<FxHashSet<u128>>,
}
fn default_track_diagnostic(_: &Diagnostic) {}
pub fn with_emitter(can_emit_warnings: bool,
treat_err_as_bug: bool,
- e: Box<Emitter>)
+ e: Box<Emitter + sync::Send>)
-> Handler {
Handler::with_emitter_and_flags(
e,
})
}
- pub fn with_emitter_and_flags(e: Box<Emitter>, flags: HandlerFlags) -> Handler {
+ pub fn with_emitter_and_flags(e: Box<Emitter + sync::Send>, flags: HandlerFlags) -> Handler {
Handler {
flags,
err_count: AtomicUsize::new(0),
- emitter: RefCell::new(e),
- continue_after_error: Cell::new(true),
- delayed_span_bug: RefCell::new(None),
- tracked_diagnostic_codes: RefCell::new(FxHashSet()),
- emitted_diagnostics: RefCell::new(FxHashSet()),
+ emitter: Lock::new(e),
+ continue_after_error: LockCell::new(true),
+ delayed_span_bug: Lock::new(None),
+ taught_diagnostics: Lock::new(FxHashSet()),
+ emitted_diagnostic_codes: Lock::new(FxHashSet()),
+ emitted_diagnostics: Lock::new(FxHashSet()),
}
}
/// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
/// the overall count of emitted error diagnostics.
pub fn reset_err_count(&self) {
- self.emitted_diagnostics.replace(FxHashSet());
+ *self.emitted_diagnostics.borrow_mut() = FxHashSet();
self.err_count.store(0, SeqCst);
}
let _ = self.fatal(&s);
let can_show_explain = self.emitter.borrow().should_show_explain();
- let are_there_diagnostics = !self.tracked_diagnostic_codes.borrow().is_empty();
+ let are_there_diagnostics = !self.emitted_diagnostic_codes.borrow().is_empty();
if can_show_explain && are_there_diagnostics {
let mut error_codes =
- self.tracked_diagnostic_codes.borrow()
+ self.emitted_diagnostic_codes.borrow()
.clone()
.into_iter()
.filter_map(|x| match x {
}
}
- /// `true` if a diagnostic with this code has already been emitted in this handler.
+ /// `true` if we haven't taught a diagnostic with this code already.
+ /// The caller must then teach the user about such a diagnostic.
///
/// Used to suppress emitting the same error multiple times with extended explanation when
/// calling `-Zteach`.
- pub fn code_emitted(&self, code: &DiagnosticId) -> bool {
- self.tracked_diagnostic_codes.borrow().contains(code)
+ pub fn must_teach(&self, code: &DiagnosticId) -> bool {
+ self.taught_diagnostics.borrow_mut().insert(code.clone())
}
pub fn force_print_db(&self, mut db: DiagnosticBuilder) {
});
if let Some(ref code) = diagnostic.code {
- self.tracked_diagnostic_codes.borrow_mut().insert(code.clone());
+ self.emitted_diagnostic_codes.borrow_mut().insert(code.clone());
}
let diagnostic_hash = {
time(sess, "persist dep-graph", || {
save_in(sess,
dep_graph_path(sess),
- |e| encode_dep_graph(tcx, e));
+ |e| {
+ time(sess, "encode dep-graph", || {
+ encode_dep_graph(tcx, e)
+ })
+ });
});
}
tcx.sess.opts.dep_tracking_hash().encode(encoder)?;
// Encode the graph data.
- let serialized_graph = tcx.dep_graph.serialize();
+ let serialized_graph = time(tcx.sess, "getting serialized graph", || {
+ tcx.dep_graph.serialize()
+ });
if tcx.sess.opts.debugging_opts.incremental_info {
#[derive(Clone)]
println!("[incremental]");
}
- serialized_graph.encode(encoder)?;
+ time(tcx.sess, "encoding serialized graph", || {
+ serialized_graph.encode(encoder)
+ })?;
Ok(())
}
fn encode_query_cache(tcx: TyCtxt,
encoder: &mut Encoder)
-> io::Result<()> {
- tcx.serialize_query_result_cache(encoder)
+ time(tcx.sess, "serialize query result cache", || {
+ tcx.serialize_query_result_cache(encoder)
+ })
}
}
fn main() {
+ if env::var_os("RUST_CHECK").is_some() {
+ // If we're just running `check`, there's no need for LLVM to be built.
+ println!("cargo:rerun-if-env-changed=RUST_CHECK");
+ return;
+ }
+
let target = env::var("TARGET").expect("TARGET was not set");
let llvm_config = env::var_os("LLVM_CONFIG")
.map(PathBuf::from)
+++ /dev/null
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
-
-use isolated_encoder::IsolatedEncoder;
-use schema::*;
-
-use rustc::hir;
-use rustc::ty::{self, TyCtxt};
-
-use rustc::ich::Fingerprint;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct Ast<'tcx> {
- pub body: Lazy<hir::Body>,
- pub tables: Lazy<ty::TypeckTables<'tcx>>,
- pub nested_bodies: LazySeq<hir::Body>,
- pub rvalue_promotable_to_static: bool,
- pub stable_bodies_hash: Fingerprint,
-}
-
-impl_stable_hash_for!(struct Ast<'tcx> {
- body,
- tables,
- nested_bodies,
- rvalue_promotable_to_static,
- stable_bodies_hash
-});
-
-impl<'a, 'b, 'tcx> IsolatedEncoder<'a, 'b, 'tcx> {
- pub fn encode_body(&mut self, body_id: hir::BodyId) -> Lazy<Ast<'tcx>> {
- let body = self.tcx.hir.body(body_id);
-
- // In order to avoid having to hash hir::Bodies from extern crates, we
- // hash them here, during export, and store the hash with metadata.
- let stable_bodies_hash = {
- let mut hcx = self.tcx.create_stable_hashing_context();
- let mut hasher = StableHasher::new();
-
- hcx.while_hashing_hir_bodies(true, |hcx| {
- body.hash_stable(hcx, &mut hasher);
- });
-
- hasher.finish()
- };
-
- let lazy_body = self.lazy(body);
- let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
- let tables = self.tcx.typeck_tables_of(body_owner_def_id);
- let lazy_tables = self.lazy(tables);
-
- let mut visitor = NestedBodyCollector {
- tcx: self.tcx,
- bodies_found: Vec::new(),
- };
- visitor.visit_body(body);
- let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found);
-
- let rvalue_promotable_to_static =
- self.tcx.const_is_rvalue_promotable_to_static(body_owner_def_id);
-
- self.lazy(&Ast {
- body: lazy_body,
- tables: lazy_tables,
- nested_bodies: lazy_nested_bodies,
- rvalue_promotable_to_static,
- stable_bodies_hash,
- })
- }
-}
-
-struct NestedBodyCollector<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- bodies_found: Vec<&'tcx hir::Body>,
-}
-
-impl<'a, 'tcx: 'a> Visitor<'tcx> for NestedBodyCollector<'a, 'tcx> {
- fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::None
- }
-
- fn visit_nested_body(&mut self, body: hir::BodyId) {
- let body = self.tcx.hir.body(body);
- self.bodies_found.push(body);
- self.visit_body(body);
- }
-}
mir_const_qualif => {
(cdata.mir_const_qualif(def_id.index), Lrc::new(IdxSetBuf::new_empty(0)))
}
- typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { Lrc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
is_const_fn => { cdata.is_const_fn(def_id.index) }
// This is only used by rustdoc anyway, which shouldn't have
// incremental recompilation ever enabled.
fn_arg_names => { cdata.get_fn_arg_names(def_id.index) }
+ rendered_const => { cdata.get_rendered_const(def_id.index) }
impl_parent => { cdata.get_parent_impl(def_id.index) }
trait_of_item => { cdata.get_trait_of_item(def_id.index) }
- item_body_nested_bodies => { cdata.item_body_nested_bodies(tcx, def_id.index) }
const_is_rvalue_promotable_to_static => {
cdata.const_is_rvalue_promotable_to_static(def_id.index)
}
defined_lang_items => { Lrc::new(cdata.get_lang_items()) }
missing_lang_items => { Lrc::new(cdata.get_missing_lang_items()) }
- extern_const_body => {
- debug!("item_body({:?}): inlining item", def_id);
- cdata.extern_const_body(tcx, def_id.index)
- }
-
missing_extern_crate_item => {
let r = match *cdata.extern_crate.borrow() {
Some(extern_crate) if !extern_crate.direct => true,
use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash,
DisambiguatedDefPathData};
use rustc::hir;
-use rustc::middle::cstore::{LinkagePreference, ExternConstBody,
- ExternBodyNestedBodies};
+use rustc::middle::cstore::LinkagePreference;
use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex,
use rustc::util::captures::Captures;
use rustc::util::nodemap::FxHashMap;
-use std::collections::BTreeMap;
use std::io;
use std::mem;
use std::u32;
impl<'tcx> EntryKind<'tcx> {
fn to_def(&self, did: DefId) -> Option<Def> {
Some(match *self {
- EntryKind::Const(_) => Def::Const(did),
+ EntryKind::Const(..) => Def::Const(did),
EntryKind::AssociatedConst(..) => Def::AssociatedConst(did),
EntryKind::ImmStatic |
EntryKind::ForeignImmStatic => Def::Static(did, false),
}
}
- pub fn extern_const_body(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- id: DefIndex)
- -> ExternConstBody<'tcx> {
- assert!(!self.is_proc_macro(id));
- let ast = self.entry(id).ast.unwrap();
- let def_id = self.local_def_id(id);
- let ast = ast.decode((self, tcx));
- let body = ast.body.decode((self, tcx));
- ExternConstBody {
- body: tcx.hir.intern_inlined_body(def_id, body),
- fingerprint: ast.stable_bodies_hash,
- }
- }
-
- pub fn item_body_tables(&self,
- id: DefIndex,
- tcx: TyCtxt<'a, 'tcx, 'tcx>)
- -> &'tcx ty::TypeckTables<'tcx> {
- let ast = self.entry(id).ast.unwrap().decode(self);
- tcx.alloc_tables(ast.tables.decode((self, tcx)))
- }
-
- pub fn item_body_nested_bodies(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- id: DefIndex)
- -> ExternBodyNestedBodies {
- if let Some(ref ast) = self.entry(id).ast {
- let mut ast = ast.decode(self);
- let nested_bodies: BTreeMap<_, _> = ast.nested_bodies
- .decode((self, tcx.sess))
- .map(|body| (body.id(), body))
- .collect();
- ExternBodyNestedBodies {
- nested_bodies: Lrc::new(nested_bodies),
- fingerprint: ast.stable_bodies_hash,
- }
- } else {
- ExternBodyNestedBodies {
- nested_bodies: Lrc::new(BTreeMap::new()),
- fingerprint: Fingerprint::ZERO,
- }
- }
- }
-
pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool {
- self.entry(id).ast.expect("const item missing `ast`")
- .decode(self).rvalue_promotable_to_static
+ match self.entry(id).kind {
+ EntryKind::AssociatedConst(_, data, _) |
+ EntryKind::Const(data, _) => data.ast_promotable,
+ _ => bug!(),
+ }
}
pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
match self.entry(id).kind {
- EntryKind::Const(qualif) |
- EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif) |
- EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif) => {
- qualif
+ EntryKind::Const(qualif, _) |
+ EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif, _) |
+ EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif, _) => {
+ qualif.mir
}
_ => bug!(),
}
let name = def_key.disambiguated_data.data.get_opt_name().unwrap();
let (kind, container, has_self) = match item.kind {
- EntryKind::AssociatedConst(container, _) => {
+ EntryKind::AssociatedConst(container, _, _) => {
(ty::AssociatedKind::Const, container, false)
}
EntryKind::Method(data) => {
lazy_seq.decode((self, tcx)).collect()
}
+ pub fn get_rendered_const(&self, id: DefIndex) -> String {
+ match self.entry(id).kind {
+ EntryKind::Const(_, data) |
+ EntryKind::AssociatedConst(_, _, data) => data.decode(self).0,
+ _ => bug!(),
+ }
+ }
+
pub fn wasm_custom_sections(&self) -> Vec<DefId> {
let sections = self.root
.wasm_custom_sections
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: None,
mir: self.encode_optimized_mir(def_id),
}
}
generics: None,
predicates: None,
- ast: None,
mir: None
}
}
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: None,
mir: None,
}
}
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: None,
mir: self.encode_optimized_mir(def_id),
}
}
let kind = match trait_item.kind {
ty::AssociatedKind::Const => {
- EntryKind::AssociatedConst(container, 0)
+ let const_qualif =
+ if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
+ self.const_qualif(0, body)
+ } else {
+ ConstQualif { mir: 0, ast_promotable: false }
+ };
+
+ let rendered =
+ hir::print::to_string(&self.tcx.hir, |s| s.print_trait_item(ast_item));
+ let rendered_const = self.lazy(&RenderedConst(rendered));
+
+ EntryKind::AssociatedConst(container, const_qualif, rendered_const)
}
ty::AssociatedKind::Method => {
let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
- Some(self.encode_body(body))
- } else {
- None
- },
mir: self.encode_optimized_mir(def_id),
}
}
+ fn metadata_output_only(&self) -> bool {
+ // MIR optimisation can be skipped when we're just interested in the metadata.
+ !self.tcx.sess.opts.output_types.should_trans()
+ }
+
+ fn const_qualif(&self, mir: u8, body_id: hir::BodyId) -> ConstQualif {
+ let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
+ let ast_promotable = self.tcx.const_is_rvalue_promotable_to_static(body_owner_def_id);
+
+ ConstQualif { mir, ast_promotable }
+ }
+
fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
debug!("IsolatedEncoder::encode_info_for_impl_item({:?})", def_id);
let tcx = self.tcx;
let kind = match impl_item.kind {
ty::AssociatedKind::Const => {
- EntryKind::AssociatedConst(container,
- self.tcx.at(ast_item.span).mir_const_qualif(def_id).0)
+ if let hir::ImplItemKind::Const(_, body_id) = ast_item.node {
+ let mir = self.tcx.at(ast_item.span).mir_const_qualif(def_id).0;
+
+ EntryKind::AssociatedConst(container,
+ self.const_qualif(mir, body_id),
+ self.encode_rendered_const_for_body(body_id))
+ } else {
+ bug!()
+ }
}
ty::AssociatedKind::Method => {
let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
};
- let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node {
- (Some(body), true)
- } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
- let generics = self.tcx.generics_of(def_id);
- let types = generics.parent_types as usize + generics.types.len();
- let needs_inline = types > 0 || tcx.trans_fn_attrs(def_id).requests_inline();
- let is_const_fn = sig.constness == hir::Constness::Const;
- let ast = if is_const_fn { Some(body) } else { None };
- let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
- (ast, needs_inline || is_const_fn || always_encode_mir)
- } else {
- (None, false)
- };
+ let mir =
+ match ast_item.node {
+ hir::ImplItemKind::Const(..) => true,
+ hir::ImplItemKind::Method(ref sig, _) => {
+ let generics = self.tcx.generics_of(def_id);
+ let types = generics.parent_types as usize + generics.types.len();
+ let needs_inline =
+ (types > 0 || tcx.trans_fn_attrs(def_id).requests_inline())
+ && !self.metadata_output_only();
+ let is_const_fn = sig.constness == hir::Constness::Const;
+ let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
+ needs_inline || is_const_fn || always_encode_mir
+ },
+ hir::ImplItemKind::Type(..) => false,
+ };
Entry {
kind,
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: ast.map(|body| self.encode_body(body)),
mir: if mir { self.encode_optimized_mir(def_id) } else { None },
}
}
self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr))
}
+ fn encode_rendered_const_for_body(&mut self, body_id: hir::BodyId) -> Lazy<RenderedConst> {
+ let body = self.tcx.hir.body(body_id);
+ let rendered = hir::print::to_string(&self.tcx.hir, |s| s.print_expr(&body.value));
+ let rendered_const = &RenderedConst(rendered);
+ self.lazy(rendered_const)
+ }
+
fn encode_info_for_item(&mut self, (def_id, item): (DefId, &'tcx hir::Item)) -> Entry<'tcx> {
let tcx = self.tcx;
let kind = match item.node {
hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
- hir::ItemConst(..) => {
- EntryKind::Const(tcx.at(item.span).mir_const_qualif(def_id).0)
+ hir::ItemConst(_, body_id) => {
+ let mir = tcx.at(item.span).mir_const_qualif(def_id).0;
+ EntryKind::Const(
+ self.const_qualif(mir, body_id),
+ self.encode_rendered_const_for_body(body_id)
+ )
}
hir::ItemFn(_, _, constness, .., body) => {
let data = FnData {
_ => None,
},
- ast: match item.node {
- hir::ItemConst(_, body) |
- hir::ItemFn(_, _, hir::Constness::Const, _, _, body) => {
- Some(self.encode_body(body))
- }
- _ => None,
- },
mir: match item.node {
hir::ItemStatic(..) => {
self.encode_optimized_mir(def_id)
hir::ItemConst(..) => self.encode_optimized_mir(def_id),
hir::ItemFn(_, _, constness, _, ref generics, _) => {
let has_tps = generics.ty_params().next().is_some();
- let needs_inline = has_tps || tcx.trans_fn_attrs(def_id).requests_inline();
+ let needs_inline = (has_tps || tcx.trans_fn_attrs(def_id).requests_inline()) &&
+ !self.metadata_output_only();
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
if needs_inline || constness == hir::Constness::Const || always_encode_mir {
self.encode_optimized_mir(def_id)
variances: LazySeq::empty(),
generics: None,
predicates: None,
- ast: None,
mir: None,
}
}
generics: None,
predicates: None,
- ast: None,
mir: None,
}
}
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: None,
mir: None,
}
}
generics: Some(self.encode_generics(def_id)),
predicates: None,
- ast: None,
mir: self.encode_optimized_mir(def_id),
}
}
debug!("IsolatedEncoder::encode_info_for_embedded_const({:?})", def_id);
let tcx = self.tcx;
let id = tcx.hir.as_local_node_id(def_id).unwrap();
- let body = tcx.hir.body_owned_by(id);
+ let body_id = tcx.hir.body_owned_by(id);
+ let const_data = self.encode_rendered_const_for_body(body_id);
+ let mir = tcx.mir_const_qualif(def_id).0;
Entry {
- kind: EntryKind::Const(tcx.mir_const_qualif(def_id).0),
+ kind: EntryKind::Const(self.const_qualif(mir, body_id), const_data),
visibility: self.lazy(&ty::Visibility::Public),
span: self.lazy(&tcx.def_span(def_id)),
attributes: LazySeq::empty(),
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: Some(self.encode_body(body)),
mir: self.encode_optimized_mir(def_id),
}
}
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: None,
mir: None,
}
}
{
self.ecx.lazy_seq_ref(slice.iter())
}
-
- pub fn lazy_seq_ref_from_slice<T>(&mut self, slice: &[&T]) -> LazySeq<T>
- where T: Encodable
- {
- self.ecx.lazy_seq_ref(slice.iter().map(|x| *x))
- }
}
mod diagnostics;
-mod astencode;
mod index_builder;
mod index;
mod encoder;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use astencode;
use index;
use rustc::hir;
pub generics: Option<Lazy<ty::Generics>>,
pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
- pub ast: Option<Lazy<astencode::Ast<'tcx>>>,
pub mir: Option<Lazy<mir::Mir<'tcx>>>,
}
variances,
generics,
predicates,
- ast,
mir
});
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub enum EntryKind<'tcx> {
- Const(u8),
+ Const(ConstQualif, Lazy<RenderedConst>),
ImmStatic,
MutStatic,
ForeignImmStatic,
Impl(Lazy<ImplData<'tcx>>),
Method(Lazy<MethodData<'tcx>>),
AssociatedType(AssociatedContainer),
- AssociatedConst(AssociatedContainer, u8),
+ AssociatedConst(AssociatedContainer, ConstQualif, Lazy<RenderedConst>),
}
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for EntryKind<'gcx> {
EntryKind::Type => {
// Nothing else to hash here.
}
- EntryKind::Const(qualif) => {
+ EntryKind::Const(qualif, ref const_data) => {
qualif.hash_stable(hcx, hasher);
+ const_data.hash_stable(hcx, hasher);
}
EntryKind::Enum(ref repr_options) => {
repr_options.hash_stable(hcx, hasher);
EntryKind::AssociatedType(associated_container) => {
associated_container.hash_stable(hcx, hasher);
}
- EntryKind::AssociatedConst(associated_container, qualif) => {
+ EntryKind::AssociatedConst(associated_container, qualif, _) => {
associated_container.hash_stable(hcx, hasher);
qualif.hash_stable(hcx, hasher);
}
}
}
+/// Additional data for EntryKind::Const and EntryKind::AssociatedConst
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable)]
+pub struct ConstQualif {
+ pub mir: u8,
+ pub ast_promotable: bool,
+}
+
+impl_stable_hash_for!(struct ConstQualif { mir, ast_promotable });
+
+/// Contains a constant which has been rendered to a String.
+/// Used by rustdoc.
+#[derive(RustcEncodable, RustcDecodable)]
+pub struct RenderedConst(pub String);
+
+impl<'a> HashStable<StableHashingContext<'a>> for RenderedConst {
+ #[inline]
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ self.0.hash_stable(hcx, hasher);
+ }
+}
+
#[derive(RustcEncodable, RustcDecodable)]
pub struct ModData {
pub reexports: LazySeq<def::Export>,
--- /dev/null
+// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use borrow_check::place_ext::PlaceExt;
+use dataflow::indexes::BorrowIndex;
+use rustc::mir::traversal;
+use rustc::mir::visit::{PlaceContext, Visitor};
+use rustc::mir::{self, Location, Mir, Place};
+use rustc::ty::{Region, TyCtxt};
+use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc_data_structures::indexed_vec::IndexVec;
+use std::fmt;
+use std::hash::Hash;
+use std::ops::Index;
+
+crate struct BorrowSet<'tcx> {
+ /// The fundamental map relating bitvector indexes to the borrows
+ /// in the MIR.
+ crate borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
+
+ /// Each borrow is also uniquely identified in the MIR by the
+ /// `Location` of the assignment statement in which it appears on
+ /// the right hand side; we map each such location to the
+ /// corresponding `BorrowIndex`.
+ crate location_map: FxHashMap<Location, BorrowIndex>,
+
+ /// Locations which activate borrows.
+ /// NOTE: A given location may activate more than one borrow in the future
+ /// when more general two-phase borrow support is introduced, but for now we
+ /// only need to store one borrow index
+ crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
+
+ /// Every borrow has a region; this maps each such regions back to
+ /// its borrow-indexes.
+ crate region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
+
+ /// Map from local to all the borrows on that local
+ crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+}
+
+impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
+ type Output = BorrowData<'tcx>;
+
+ fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
+ &self.borrows[index]
+ }
+}
+
+#[derive(Debug)]
+crate struct BorrowData<'tcx> {
+ /// Location where the borrow reservation starts.
+ /// In many cases, this will be equal to the activation location but not always.
+ crate reserve_location: Location,
+ /// Location where the borrow is activated. None if this is not a
+ /// 2-phase borrow.
+ crate activation_location: Option<Location>,
+ /// What kind of borrow this is
+ crate kind: mir::BorrowKind,
+ /// The region for which this borrow is live
+ crate region: Region<'tcx>,
+ /// Place from which we are borrowing
+ crate borrowed_place: mir::Place<'tcx>,
+ /// Place to which the borrow was stored
+ crate assigned_place: mir::Place<'tcx>,
+}
+
+impl<'tcx> fmt::Display for BorrowData<'tcx> {
+ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
+ let kind = match self.kind {
+ mir::BorrowKind::Shared => "",
+ mir::BorrowKind::Unique => "uniq ",
+ mir::BorrowKind::Mut { .. } => "mut ",
+ };
+ let region = format!("{}", self.region);
+ let region = if region.len() > 0 {
+ format!("{} ", region)
+ } else {
+ region
+ };
+ write!(w, "&{}{}{:?}", region, kind, self.borrowed_place)
+ }
+}
+
+impl<'tcx> BorrowSet<'tcx> {
+ pub fn build(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
+ let mut visitor = GatherBorrows {
+ tcx,
+ mir,
+ idx_vec: IndexVec::new(),
+ location_map: FxHashMap(),
+ activation_map: FxHashMap(),
+ region_map: FxHashMap(),
+ local_map: FxHashMap(),
+ pending_activations: FxHashMap(),
+ };
+
+ for (block, block_data) in traversal::preorder(mir) {
+ visitor.visit_basic_block_data(block, block_data);
+ }
+
+ // Double check: We should have found an activation for every pending
+ // activation.
+ assert_eq!(
+ visitor
+ .pending_activations
+ .iter()
+ .find(|&(_local, &borrow_index)| visitor.idx_vec[borrow_index]
+ .activation_location
+ .is_none()),
+ None,
+ "never found an activation for this borrow!",
+ );
+
+ BorrowSet {
+ borrows: visitor.idx_vec,
+ location_map: visitor.location_map,
+ activation_map: visitor.activation_map,
+ region_map: visitor.region_map,
+ local_map: visitor.local_map,
+ }
+ }
+
+ crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
+ self.activation_map
+ .get(&location)
+ .map(|activations| &activations[..])
+ .unwrap_or(&[])
+ }
+}
+
+struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
+ location_map: FxHashMap<Location, BorrowIndex>,
+ activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
+ region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
+ local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+
+ /// When we encounter a 2-phase borrow statement, it will always
+ /// be assigning into a temporary TEMP:
+ ///
+ /// TEMP = &foo
+ ///
+ /// We add TEMP into this map with `b`, where `b` is the index of
+ /// the borrow. When we find a later use of this activation, we
+ /// remove from the map (and add to the "tombstone" set below).
+ pending_activations: FxHashMap<mir::Local, BorrowIndex>,
+}
+
+impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
+ fn visit_assign(
+ &mut self,
+ block: mir::BasicBlock,
+ assigned_place: &mir::Place<'tcx>,
+ rvalue: &mir::Rvalue<'tcx>,
+ location: mir::Location,
+ ) {
+ if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
+ if borrowed_place.is_unsafe_place(self.tcx, self.mir) {
+ return;
+ }
+
+ let borrow = BorrowData {
+ kind,
+ region,
+ reserve_location: location,
+ activation_location: None,
+ borrowed_place: borrowed_place.clone(),
+ assigned_place: assigned_place.clone(),
+ };
+ let idx = self.idx_vec.push(borrow);
+ self.location_map.insert(location, idx);
+
+ self.insert_as_pending_if_two_phase(location, &assigned_place, region, kind, idx);
+
+ insert(&mut self.region_map, ®ion, idx);
+ if let Some(local) = borrowed_place.root_local() {
+ insert(&mut self.local_map, &local, idx);
+ }
+ }
+
+ return self.super_assign(block, assigned_place, rvalue, location);
+
+ fn insert<'a, K, V>(map: &'a mut FxHashMap<K, FxHashSet<V>>, k: &K, v: V)
+ where
+ K: Clone + Eq + Hash,
+ V: Eq + Hash,
+ {
+ map.entry(k.clone()).or_insert(FxHashSet()).insert(v);
+ }
+ }
+
+ fn visit_place(
+ &mut self,
+ place: &mir::Place<'tcx>,
+ context: PlaceContext<'tcx>,
+ location: Location,
+ ) {
+ self.super_place(place, context, location);
+
+ // We found a use of some temporary TEMP...
+ if let Place::Local(temp) = place {
+ // ... check whether we (earlier) saw a 2-phase borrow like
+ //
+ // TMP = &mut place
+ match self.pending_activations.get(temp) {
+ Some(&borrow_index) => {
+ let borrow_data = &mut self.idx_vec[borrow_index];
+
+ // Watch out: the use of TMP in the borrow
+ // itself doesn't count as an
+ // activation. =)
+ if borrow_data.reserve_location == location && context == PlaceContext::Store {
+ return;
+ }
+
+ if let Some(other_activation) = borrow_data.activation_location {
+ span_bug!(
+ self.mir.source_info(location).span,
+ "found two activations for 2-phase borrow temporary {:?}: \
+ {:?} and {:?}",
+ temp,
+ location,
+ other_activation,
+ );
+ }
+
+ // Otherwise, this is the unique later use
+ // that we expect.
+ borrow_data.activation_location = Some(location);
+ self.activation_map
+ .entry(location)
+ .or_insert(Vec::new())
+ .push(borrow_index);
+ }
+
+ None => {}
+ }
+ }
+ }
+
+ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
+ if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
+ // double-check that we already registered a BorrowData for this
+
+ let borrow_index = self.location_map[&location];
+ let borrow_data = &self.idx_vec[borrow_index];
+ assert_eq!(borrow_data.reserve_location, location);
+ assert_eq!(borrow_data.kind, kind);
+ assert_eq!(borrow_data.region, region);
+ assert_eq!(borrow_data.borrowed_place, *place);
+ }
+
+ return self.super_rvalue(rvalue, location);
+ }
+
+ fn visit_statement(
+ &mut self,
+ block: mir::BasicBlock,
+ statement: &mir::Statement<'tcx>,
+ location: Location,
+ ) {
+ return self.super_statement(block, statement, location);
+ }
+}
+
+impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
+ /// Returns true if the borrow represented by `kind` is
+ /// allowed to be split into separate Reservation and
+ /// Activation phases.
+ fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
+ self.tcx.two_phase_borrows()
+ && (kind.allows_two_phase_borrow()
+ || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
+ }
+
+ /// If this is a two-phase borrow, then we will record it
+ /// as "pending" until we find the activating use.
+ fn insert_as_pending_if_two_phase(
+ &mut self,
+ start_location: Location,
+ assigned_place: &mir::Place<'tcx>,
+ region: Region<'tcx>,
+ kind: mir::BorrowKind,
+ borrow_index: BorrowIndex,
+ ) {
+ debug!(
+ "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?}, {:?})",
+ start_location, assigned_place, region, borrow_index,
+ );
+
+ if !self.allow_two_phase_borrow(kind) {
+ debug!(" -> {:?}", start_location);
+ return;
+ }
+
+ // When we encounter a 2-phase borrow statement, it will always
+ // be assigning into a temporary TEMP:
+ //
+ // TEMP = &foo
+ //
+ // so extract `temp`.
+ let temp = if let &mir::Place::Local(temp) = assigned_place {
+ temp
+ } else {
+ span_bug!(
+ self.mir.source_info(start_location).span,
+ "expected 2-phase borrow to assign to a local, not `{:?}`",
+ assigned_place,
+ );
+ };
+
+ // Insert `temp` into the list of pending activations. From
+ // now on, we'll be on the lookout for a use of it. Note that
+ // we are guaranteed that this use will come after the
+ // assignment.
+ let old_value = self.pending_activations.insert(temp, borrow_index);
+ assert!(old_value.is_none());
+ }
+}
use super::{Context, MirBorrowckCtxt};
use super::{InitializationRequiringAction, PrefixSet};
-use dataflow::{Borrows, BorrowData, FlowAtLocation, MovingOutStatements};
+use super::borrow_set::BorrowData;
+
+use dataflow::{FlowAtLocation, MovingOutStatements};
use dataflow::move_paths::MovePathIndex;
use util::borrowck_errors::{BorrowckErrors, Origin};
(place, span): (&Place<'tcx>, Span),
gen_borrow_kind: BorrowKind,
issued_borrow: &BorrowData<'tcx>,
- end_issued_loan_span: Option<Span>,
) {
let issued_span = self.retrieve_borrow_span(issued_borrow);
"it",
rgt,
"",
- end_issued_loan_span,
+ None,
Origin::Mir,
)
}
"",
issued_span,
"",
- end_issued_loan_span,
+ None,
Origin::Mir,
)
}
span,
&desc_place,
issued_span,
- end_issued_loan_span,
+ None,
Origin::Mir,
)
}
issued_span,
"it",
"",
- end_issued_loan_span,
+ None,
Origin::Mir,
),
lft,
issued_span,
"",
- end_issued_loan_span,
+ None,
Origin::Mir,
)
}
lft,
issued_span,
"",
- end_issued_loan_span,
+ None,
Origin::Mir,
)
}
context: Context,
borrow: &BorrowData<'tcx>,
drop_span: Span,
- borrows: &Borrows<'cx, 'gcx, 'tcx>
) {
- let end_span = borrows.opt_region_end_span(&borrow.region);
- let scope_tree = borrows.scope_tree();
+ let scope_tree = self.tcx.region_scope_tree(self.mir_def_id);
let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
.last()
.unwrap();
drop_span,
borrow_span,
proper_span,
- end_span,
);
}
(RegionKind::ReScope(_), None) => {
drop_span,
borrow_span,
proper_span,
- end_span,
);
}
(RegionKind::ReEarlyBound(_), Some(name))
drop_span,
borrow_span,
proper_span,
- end_span,
);
}
(RegionKind::ReEarlyBound(_), None)
drop_span,
borrow_span,
proper_span,
- end_span,
);
}
(RegionKind::ReLateBound(_, _), _)
drop_span: Span,
borrow_span: Span,
_proper_span: Span,
- end_span: Option<Span>,
) {
let tcx = self.tcx;
let mut err =
drop_span,
format!("`{}` dropped here while still borrowed", name),
);
- if let Some(end) = end_span {
- err.span_label(end, "borrowed value needs to live until here");
- }
self.explain_why_borrow_contains_point(context, borrow, &mut err);
err.emit();
}
drop_span: Span,
_borrow_span: Span,
proper_span: Span,
- end_span: Option<Span>,
) {
let tcx = self.tcx;
let mut err =
"temporary value dropped here while still borrowed",
);
err.note("consider using a `let` binding to increase its lifetime");
- if let Some(end) = end_span {
- err.span_label(end, "temporary value needs to live until here");
- }
self.explain_why_borrow_contains_point(context, borrow, &mut err);
err.emit();
}
drop_span: Span,
borrow_span: Span,
_proper_span: Span,
- _end_span: Option<Span>,
) {
debug!(
"report_unscoped_local_value_does_not_live_long_enough(\
err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(drop_span, "borrowed value only lives until here");
- if !tcx.nll() {
- tcx.note_and_explain_region(
- scope_tree,
- &mut err,
- "borrowed value must be valid for ",
- borrow.region,
- "...",
- );
- }
-
self.explain_why_borrow_contains_point(context, borrow, &mut err);
err.emit();
}
drop_span: Span,
_borrow_span: Span,
proper_span: Span,
- _end_span: Option<Span>,
) {
debug!(
"report_unscoped_temporary_value_does_not_live_long_enough(\
err.span_label(proper_span, "temporary value does not live long enough");
err.span_label(drop_span, "temporary value only lives until here");
- if !tcx.nll() {
- tcx.note_and_explain_region(
- scope_tree,
- &mut err,
- "borrowed value must be valid for ",
- borrow.region,
- "...",
- );
- }
-
self.explain_why_borrow_contains_point(context, borrow, &mut err);
err.emit();
}
}
// Retrieve span of given borrow from the current MIR representation
- pub fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
+ crate fn retrieve_borrow_span(&self, borrow: &BorrowData) -> Span {
self.mir.source_info(borrow.reserve_location).span
}
//! but is not as ugly as it is right now.
use rustc::mir::{BasicBlock, Location};
+use rustc_data_structures::indexed_set::Iter;
use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
use dataflow::{EverInitializedPlaces, MovingOutStatements};
use dataflow::{Borrows};
use dataflow::{FlowAtLocation, FlowsAtLocation};
use dataflow::move_paths::HasMoveData;
+use dataflow::move_paths::indexes::BorrowIndex;
use std::fmt;
// (forced to be `pub` due to its use as an associated type below.)
-pub(crate) struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
- pub borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
+crate struct Flows<'b, 'gcx: 'tcx, 'tcx: 'b> {
+ borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
pub inits: FlowAtLocation<MaybeInitializedPlaces<'b, 'gcx, 'tcx>>,
pub uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
pub move_outs: FlowAtLocation<MovingOutStatements<'b, 'gcx, 'tcx>>,
}
impl<'b, 'gcx, 'tcx> Flows<'b, 'gcx, 'tcx> {
- pub fn new(
+ crate fn new(
borrows: FlowAtLocation<Borrows<'b, 'gcx, 'tcx>>,
inits: FlowAtLocation<MaybeInitializedPlaces<'b, 'gcx, 'tcx>>,
uninits: FlowAtLocation<MaybeUninitializedPlaces<'b, 'gcx, 'tcx>>,
ever_inits,
}
}
+
+ crate fn borrows_in_scope(&self) -> impl Iterator<Item = BorrowIndex> + '_ {
+ self.borrows.iter_incoming()
+ }
+
+ crate fn with_outgoing_borrows(&self, op: impl FnOnce(Iter<BorrowIndex>)) {
+ self.borrows.with_iter_outgoing(op)
+ }
}
macro_rules! each_flow {
s.push_str(", ");
};
saw_one = true;
- let borrow_data = &self.borrows.operator().borrows()[borrow.borrow_index()];
- s.push_str(&format!("{}{}", borrow_data,
- if borrow.is_activation() { "@active" } else { "" }));
+ let borrow_data = &self.borrows.operator().borrows()[borrow];
+ s.push_str(&format!("{}", borrow_data));
});
s.push_str("] ");
s.push_str(", ");
};
saw_one = true;
- let borrow_data = &self.borrows.operator().borrows()[borrow.borrow_index()];
+ let borrow_data = &self.borrows.operator().borrows()[borrow];
s.push_str(&format!("{}", borrow_data));
});
s.push_str("] ");
use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
use rustc::mir::ClosureRegionRequirements;
+use rustc_data_structures::control_flow_graph::dominators::Dominators;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
use std::rc::Rc;
-use syntax::ast;
use syntax_pos::Span;
use dataflow::{do_dataflow, DebugFormatted};
use dataflow::{DataflowResultsConsumer};
use dataflow::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
use dataflow::{EverInitializedPlaces, MovingOutStatements};
-use dataflow::{BorrowData, Borrows, ReserveOrActivateIndex};
+use dataflow::Borrows;
use dataflow::indexes::BorrowIndex;
use dataflow::move_paths::{IllegalMoveOriginKind, MoveError};
use dataflow::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
use std::iter;
+use self::borrow_set::{BorrowSet, BorrowData};
use self::flows::Flows;
use self::prefixes::PrefixSet;
use self::MutateMode::{JustWrite, WriteAndRead};
+crate mod borrow_set;
mod error_reporting;
mod flows;
+crate mod place_ext;
mod prefixes;
pub(crate) mod nll;
let input_mir = tcx.mir_validated(def_id);
debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
- if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir() {
+ if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir_borrowck() {
return None;
}
.as_local_node_id(def_id)
.expect("do_mir_borrowck: non-local DefId");
- // Make our own copy of the MIR. This copy will be modified (in place) to
- // contain non-lexical lifetimes. It will have a lifetime tied
- // to the inference context.
+ // Replace all regions with fresh inference variables. This
+ // requires first making our own copy of the MIR. This copy will
+ // be modified (in place) to contain non-lexical lifetimes. It
+ // will have a lifetime tied to the inference context.
let mut mir: Mir<'tcx> = input_mir.clone();
- let free_regions = if !tcx.nll() {
- None
- } else {
- let mir = &mut mir;
-
- // Replace all regions with fresh inference variables.
- Some(nll::replace_regions_in_mir(infcx, def_id, param_env, mir))
- };
- let mir = &mir;
+ let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut mir);
+ let mir = &mir; // no further changes
let move_data: MoveData<'tcx> = match MoveData::gather_moves(mir, tcx) {
Ok(move_data) => move_data,
|bd, i| DebugFormatted::new(&bd.move_data().inits[i]),
));
+ let borrow_set = Rc::new(BorrowSet::build(tcx, mir));
+
// If we are in non-lexical mode, compute the non-lexical lifetimes.
- let (opt_regioncx, opt_closure_req) = if let Some(free_regions) = free_regions {
- let (regioncx, opt_closure_req) = nll::compute_regions(
- infcx,
- def_id,
- free_regions,
- mir,
- param_env,
- &mut flow_inits,
- &mdpe.move_data,
- );
- (Some(Rc::new(regioncx)), opt_closure_req)
- } else {
- assert!(!tcx.nll());
- (None, None)
- };
+ let (regioncx, opt_closure_req) = nll::compute_regions(
+ infcx,
+ def_id,
+ free_regions,
+ mir,
+ param_env,
+ &mut flow_inits,
+ &mdpe.move_data,
+ &borrow_set,
+ );
+ let regioncx = Rc::new(regioncx);
let flow_inits = flow_inits; // remove mut
let flow_borrows = FlowAtLocation::new(do_dataflow(
id,
&attributes,
&dead_unwinds,
- Borrows::new(tcx, mir, opt_regioncx.clone(), def_id, body_id),
- |rs, i| {
- DebugFormatted::new(&(i.kind(), rs.location(i.borrow_index())))
- }
+ Borrows::new(tcx, mir, regioncx.clone(), def_id, body_id, &borrow_set),
+ |rs, i| DebugFormatted::new(&rs.location(i)),
));
- let movable_generator = !match tcx.hir.get(id) {
+ let movable_generator = match tcx.hir.get(id) {
hir::map::Node::NodeExpr(&hir::Expr {
node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)),
..
- }) => true,
- _ => false,
+ }) => false,
+ _ => true,
};
+ let dominators = mir.dominators();
+
let mut mbcx = MirBorrowckCtxt {
tcx: tcx,
mir: mir,
- node_id: id,
+ mir_def_id: def_id,
move_data: &mdpe.move_data,
param_env: param_env,
movable_generator,
access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(),
moved_error_reported: FxHashSet(),
- nonlexical_regioncx: opt_regioncx,
+ nonlexical_regioncx: regioncx,
nonlexical_cause_info: None,
+ borrow_set,
+ dominators,
};
let mut state = Flows::new(
pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
mir: &'cx Mir<'tcx>,
- node_id: ast::NodeId,
+ mir_def_id: DefId,
move_data: &'cx MoveData<'tcx>,
param_env: ParamEnv<'gcx>,
movable_generator: bool,
/// Non-lexical region inference context, if NLL is enabled. This
/// contains the results from region inference and lets us e.g.
/// find out which CFG points are contained in each borrow region.
- nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
+ nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
nonlexical_cause_info: Option<RegionCausalInfo>,
+
+ /// The set of borrows extracted from the MIR
+ borrow_set: Rc<BorrowSet<'tcx>>,
+
+ /// Dominators for MIR
+ dominators: Dominators<BasicBlock>,
}
// Check that:
if self.movable_generator {
// Look for any active borrows to locals
- let domain = flow_state.borrows.operator();
- let data = domain.borrows();
- flow_state.borrows.with_iter_outgoing(|borrows| {
+ let borrow_set = self.borrow_set.clone();
+ flow_state.with_outgoing_borrows(|borrows| {
for i in borrows {
- let borrow = &data[i.borrow_index()];
+ let borrow = &borrow_set[i];
self.check_for_local_borrow(borrow, span);
}
});
// Often, the storage will already have been killed by an explicit
// StorageDead, but we don't always emit those (notably on unwind paths),
// so this "extra check" serves as a kind of backup.
- let domain = flow_state.borrows.operator();
- let data = domain.borrows();
- flow_state.borrows.with_iter_outgoing(|borrows| {
+ let borrow_set = self.borrow_set.clone();
+ flow_state.with_outgoing_borrows(|borrows| {
for i in borrows {
- let borrow = &data[i.borrow_index()];
+ let borrow = &borrow_set[i];
let context = ContextKind::StorageDead.new(loc);
- self.check_for_invalidation_at_exit(context, borrow, span, flow_state);
+ self.check_for_invalidation_at_exit(context, borrow, span);
}
});
}
rw: ReadOrWrite,
flow_state: &Flows<'cx, 'gcx, 'tcx>,
) -> bool {
+ debug!(
+ "check_access_for_conflict(context={:?}, place_span={:?}, sd={:?}, rw={:?})",
+ context,
+ place_span,
+ sd,
+ rw,
+ );
+
let mut error_reported = false;
self.each_borrow_involving_path(
context,
(sd, place_span.0),
flow_state,
- |this, index, borrow| match (rw, borrow.kind) {
+ |this, borrow_index, borrow| match (rw, borrow.kind) {
// Obviously an activation is compatible with its own
// reservation (or even prior activating uses of same
// borrow); so don't check if they interfere.
//
// NOTE: *reservations* do conflict with themselves;
// thus aren't injecting unsoundenss w/ this check.)
- (Activation(_, activating), _) if activating == index.borrow_index() => {
+ (Activation(_, activating), _) if activating == borrow_index => {
debug!(
"check_access_for_conflict place_span: {:?} sd: {:?} rw: {:?} \
- skipping {:?} b/c activation of same borrow_index: {:?}",
+ skipping {:?} b/c activation of same borrow_index",
place_span,
sd,
rw,
- (index, borrow),
- index.borrow_index()
+ (borrow_index, borrow),
);
Control::Continue
}
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
- if this.allow_two_phase_borrow(borrow.kind) && index.is_reservation() {
+ if !this.is_active(borrow, context.loc) {
+ assert!(this.allow_two_phase_borrow(borrow.kind));
return Control::Continue;
}
this.report_use_while_mutably_borrowed(context, place_span, borrow)
}
ReadKind::Borrow(bk) => {
- let end_issued_loan_span = flow_state
- .borrows
- .operator()
- .opt_region_end_span(&borrow.region);
error_reported = true;
this.report_conflicting_borrow(
context,
place_span,
bk,
&borrow,
- end_issued_loan_span,
)
}
}
match kind {
WriteKind::MutableBorrow(bk) => {
- let end_issued_loan_span = flow_state
- .borrows
- .operator()
- .opt_region_end_span(&borrow.region);
-
error_reported = true;
this.report_conflicting_borrow(
context,
place_span,
bk,
&borrow,
- end_issued_loan_span,
)
}
WriteKind::StorageDeadOrDrop => {
context,
borrow,
place_span.1,
- flow_state.borrows.operator(),
);
}
WriteKind::Mutate => {
context: Context,
borrow: &BorrowData<'tcx>,
span: Span,
- flow_state: &Flows<'cx, 'gcx, 'tcx>,
) {
debug!("check_for_invalidation_at_exit({:?})", borrow);
let place = &borrow.borrowed_place;
context,
borrow,
span,
- flow_state.borrows.operator(),
)
}
}
// Two-phase borrow support: For each activation that is newly
// generated at this statement, check if it interferes with
// another borrow.
- let domain = flow_state.borrows.operator();
- let data = domain.borrows();
- flow_state.borrows.each_gen_bit(|gen| {
- if gen.is_activation() {
- let borrow_index = gen.borrow_index();
- let borrow = &data[borrow_index];
- // currently the flow analysis registers
- // activations for both mutable and immutable
- // borrows. So make sure we are talking about a
- // mutable borrow before we check it.
- match borrow.kind {
- BorrowKind::Shared => return,
- BorrowKind::Unique | BorrowKind::Mut { .. } => {}
- }
-
- self.access_place(
- ContextKind::Activation.new(location),
- (&borrow.borrowed_place, span),
- (
- Deep,
- Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index),
- ),
- LocalMutationIsAllowed::No,
- flow_state,
- );
- // We do not need to call `check_if_path_or_subpath_is_moved`
- // again, as we already called it when we made the
- // initial reservation.
- }
- });
+ let borrow_set = self.borrow_set.clone();
+ for &borrow_index in borrow_set.activations_at_location(location) {
+ let borrow = &borrow_set[borrow_index];
+
+ // only mutable borrows should be 2-phase
+ assert!(match borrow.kind {
+ BorrowKind::Shared => false,
+ BorrowKind::Unique | BorrowKind::Mut { .. } => true,
+ });
+
+ self.access_place(
+ ContextKind::Activation.new(location),
+ (&borrow.borrowed_place, span),
+ (
+ Deep,
+ Activation(WriteKind::MutableBorrow(borrow.kind), borrow_index),
+ ),
+ LocalMutationIsAllowed::No,
+ flow_state,
+ );
+ // We do not need to call `check_if_path_or_subpath_is_moved`
+ // again, as we already called it when we made the
+ // initial reservation.
+ }
}
}
} else {
self.get_default_err_msg(place)
};
+ let sp = self.mir.source_info(locations[0]).span;
+ let mut to_suggest_span = String::new();
+ if let Ok(src) =
+ self.tcx.sess.codemap().span_to_snippet(sp) {
+ to_suggest_span = src[1..].to_string();
+ };
err_info = Some((
- self.mir.source_info(locations[0]).span,
+ sp,
"consider changing this to be a \
- mutable reference: `&mut`", item_msg,
+ mutable reference",
+ to_suggest_span,
+ item_msg,
self.get_primary_err_msg(base)));
}
},
_ => {},
}
- if let Some((err_help_span, err_help_stmt, item_msg, sec_span)) = err_info {
+ if let Some((err_help_span,
+ err_help_stmt,
+ to_suggest_span,
+ item_msg,
+ sec_span)) = err_info {
let mut err = self.tcx.cannot_assign(span, &item_msg, Origin::Mir);
- err.span_suggestion(err_help_span, err_help_stmt, format!(""));
+ err.span_suggestion(err_help_span,
+ err_help_stmt,
+ format!("&mut {}", to_suggest_span));
if place != place_err {
err.span_label(span, sec_span);
}
unreachable!("iter::repeat returned None")
}
- /// This function iterates over all of the current borrows
- /// (represented by 1-bits in `flow_state.borrows`) that conflict
- /// with an access to a place, invoking the `op` callback for each
- /// one.
+ /// This function iterates over all of the in-scope borrows that
+ /// conflict with an access to a place, invoking the `op` callback
+ /// for each one.
///
/// "Current borrow" here means a borrow that reaches the point in
/// the control-flow where the access occurs.
///
- /// The borrow's phase is represented by the ReserveOrActivateIndex
- /// passed to the callback: one can call `is_reservation()` and
- /// `is_activation()` to determine what phase the borrow is
- /// currently in, when such distinction matters.
+ /// The borrow's phase is represented by the IsActive parameter
+ /// passed to the callback.
fn each_borrow_involving_path<F>(
&mut self,
_context: Context,
flow_state: &Flows<'cx, 'gcx, 'tcx>,
mut op: F,
) where
- F: FnMut(&mut Self, ReserveOrActivateIndex, &BorrowData<'tcx>) -> Control,
+ F: FnMut(&mut Self, BorrowIndex, &BorrowData<'tcx>) -> Control,
{
let (access, place) = access_place;
// FIXME: analogous code in check_loans first maps `place` to
// its base_path.
- let data = flow_state.borrows.operator().borrows();
-
// check for loan restricting path P being used. Accounts for
// borrows of P, P.a.b, etc.
- let mut iter_incoming = flow_state.borrows.iter_incoming();
- while let Some(i) = iter_incoming.next() {
- let borrowed = &data[i.borrow_index()];
+ let borrow_set = self.borrow_set.clone();
+ for i in flow_state.borrows_in_scope() {
+ let borrowed = &borrow_set[i];
if self.places_conflict(&borrowed.borrowed_place, place, access) {
debug!(
}
}
}
+
+ fn is_active(
+ &self,
+ borrow_data: &BorrowData<'tcx>,
+ location: Location
+ ) -> bool {
+ debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);
+
+ // If this is not a 2-phase borrow, it is always active.
+ let activation_location = match borrow_data.activation_location {
+ Some(v) => v,
+ None => return true,
+ };
+
+ // Otherwise, it is active for every location *except* in between
+ // the reservation and the activation:
+ //
+ // X
+ // /
+ // R <--+ Except for this
+ // / \ | diamond
+ // \ / |
+ // A <------+
+ // |
+ // Z
+ //
+ // Note that we assume that:
+ // - the reservation R dominates the activation A
+ // - the activation A post-dominates the reservation R (ignoring unwinding edges).
+ //
+ // This means that there can't be an edge that leaves A and
+ // comes back into that diamond unless it passes through R.
+ //
+ // Suboptimal: In some cases, this code walks the dominator
+ // tree twice when it only has to be walked once. I am
+ // lazy. -nmatsakis
+
+ // If dominated by the activation A, then it is active. The
+ // activation occurs upon entering the point A, so this is
+ // also true if location == activation_location.
+ if activation_location.dominates(location, &self.dominators) {
+ return true;
+ }
+
+ // The reservation starts *on exiting* the reservation block,
+ // so check if the location is dominated by R.successor. If so,
+ // this point falls in between the reservation and location.
+ let reserve_location = borrow_data.reserve_location.successor_within_block();
+ if reserve_location.dominates(location, &self.dominators) {
+ false
+ } else {
+ // Otherwise, this point is outside the diamond, so
+ // consider the borrow active. This could happen for
+ // example if the borrow remains active around a loop (in
+ // which case it would be active also for the point R,
+ // which would generate an error).
+ true
+ }
+ }
}
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
use borrow_check::nll::region_infer::{Cause, RegionInferenceContext};
use borrow_check::{Context, MirBorrowckCtxt};
-use dataflow::BorrowData;
+use borrow_check::borrow_set::BorrowData;
use rustc::mir::visit::{MirVisitable, PlaceContext, Visitor};
use rustc::mir::{Local, Location, Mir};
use rustc_data_structures::fx::FxHashSet;
borrow: &BorrowData<'tcx>,
err: &mut DiagnosticBuilder<'_>,
) {
- if let Some(regioncx) = &self.nonlexical_regioncx {
- let mir = self.mir;
+ let regioncx = &&self.nonlexical_regioncx;
+ let mir = self.mir;
- if self.nonlexical_cause_info.is_none() {
- self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
- }
+ if self.nonlexical_cause_info.is_none() {
+ self.nonlexical_cause_info = Some(regioncx.compute_causal_info(mir));
+ }
+
+ let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
+ if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
+ match *cause.root_cause() {
+ Cause::LiveVar(local, location) => {
+ match find_regular_use(mir, regioncx, borrow, location, local) {
+ Some(p) => {
+ err.span_label(
+ mir.source_info(p).span,
+ format!("borrow later used here"),
+ );
+ }
+
+ None => {
+ span_bug!(
+ mir.source_info(context.loc).span,
+ "Cause should end in a LiveVar"
+ );
+ }
+ }
+ }
- let cause_info = self.nonlexical_cause_info.as_ref().unwrap();
- if let Some(cause) = cause_info.why_region_contains_point(borrow.region, context.loc) {
- match *cause.root_cause() {
- Cause::LiveVar(local, location) => {
- match find_regular_use(mir, regioncx, borrow, location, local) {
- Some(p) => {
+ Cause::DropVar(local, location) => {
+ match find_drop_use(mir, regioncx, borrow, location, local) {
+ Some(p) => match &mir.local_decls[local].name {
+ Some(local_name) => {
err.span_label(
mir.source_info(p).span,
- format!("borrow later used here"),
+ format!(
+ "borrow later used here, when `{}` is dropped",
+ local_name
+ ),
);
}
-
None => {
- span_bug!(
- mir.source_info(context.loc).span,
- "Cause should end in a LiveVar"
+ err.span_label(
+ mir.local_decls[local].source_info.span,
+ "borrow may end up in a temporary, created here",
);
- }
- }
- }
- Cause::DropVar(local, location) => {
- match find_drop_use(mir, regioncx, borrow, location, local) {
- Some(p) => match &mir.local_decls[local].name {
- Some(local_name) => {
- err.span_label(
- mir.source_info(p).span,
- format!(
- "borrow later used here, when `{}` is dropped",
- local_name
- ),
- );
- }
- None => {
- err.span_label(
- mir.local_decls[local].source_info.span,
- "borrow may end up in a temporary, created here",
- );
-
- err.span_label(
- mir.source_info(p).span,
- "temporary later dropped here, \
- potentially using the reference",
- );
- }
- },
-
- None => {
- span_bug!(
- mir.source_info(context.loc).span,
- "Cause should end in a DropVar"
+ err.span_label(
+ mir.source_info(p).span,
+ "temporary later dropped here, \
+ potentially using the reference",
);
}
- }
- }
+ },
- Cause::UniversalRegion(region_vid) => {
- if let Some(region) = regioncx.to_error_region(region_vid) {
- self.tcx.note_and_explain_free_region(
- err,
- "borrowed value must be valid for ",
- region,
- "...",
+ None => {
+ span_bug!(
+ mir.source_info(context.loc).span,
+ "Cause should end in a DropVar"
);
}
}
+ }
- _ => {}
+ Cause::UniversalRegion(region_vid) => {
+ if let Some(region) = regioncx.to_error_region(region_vid) {
+ self.tcx.note_and_explain_free_region(
+ err,
+ "borrowed value must be valid for ",
+ region,
+ "...",
+ );
+ }
}
+
+ _ => {}
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use borrow_check::borrow_set::BorrowSet;
use rustc::hir::def_id::DefId;
use rustc::mir::{ClosureRegionRequirements, ClosureOutlivesSubject, Mir};
use rustc::infer::InferCtxt;
param_env: ty::ParamEnv<'gcx>,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'cx, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
+ _borrow_set: &BorrowSet<'tcx>,
) -> (
RegionInferenceContext<'tcx>,
Option<ClosureRegionRequirements<'gcx>>,
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::mir::{BasicBlock, Location, Mir};
-use rustc::ty::RegionVid;
+use rustc::ty::{self, RegionVid};
use syntax::codemap::Span;
use super::{Cause, CauseExt, TrackCauses};
if let Some(causes) = &mut self.causes {
let cause = make_cause(causes);
let old_cause = causes.get_mut(&(r, i)).unwrap();
- if cause < **old_cause {
+ // #49998: compare using root cause alone to avoid
+ // useless traffic from similar outlives chains.
+
+ let overwrite = if ty::tls::with(|tcx| {
+ tcx.sess.opts.debugging_opts.nll_subminimal_causes
+ }) {
+ cause.root_cause() < old_cause.root_cause()
+ } else {
+ cause < **old_cause
+ };
+ if overwrite {
*old_cause = Rc::new(cause);
return true;
}
tcx.predicates_of(def_id).instantiate(tcx, substs);
let predicates =
type_checker.normalize(&instantiated_predicates.predicates, location);
- type_checker.prove_predicates(predicates.iter().cloned(), location);
+ type_checker.prove_predicates(predicates, location);
}
value.ty
let predicates = self.normalize(&instantiated_predicates.predicates, location);
debug!("prove_aggregate_predicates: predicates={:?}", predicates);
- self.prove_predicates(predicates.iter().cloned(), location);
+ self.prove_predicates(predicates, location);
}
fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location) {
self.prove_predicates(
- [ty::Predicate::Trait(
+ Some(ty::Predicate::Trait(
trait_ref.to_poly_trait_ref().to_poly_trait_predicate(),
- )].iter()
- .cloned(),
+ )),
location,
);
}
- fn prove_predicates(
- &mut self,
- predicates: impl IntoIterator<Item = ty::Predicate<'tcx>>,
- location: Location,
- ) {
- let mut predicates_iter = predicates.into_iter();
+ fn prove_predicates<T>(&mut self, predicates: T, location: Location)
+ where
+ T: IntoIterator<Item = ty::Predicate<'tcx>>,
+ T::IntoIter: Clone,
+ {
+ let predicates = predicates.into_iter();
debug!(
"prove_predicates(predicates={:?}, location={:?})",
- predicates_iter.by_ref().collect::<Vec<_>>(),
- location
+ predicates.clone().collect::<Vec<_>>(),
+ location,
);
self.fully_perform_op(location.at_self(), |this| {
let cause = this.misc(this.last_span);
- let obligations = predicates_iter
+ let obligations = predicates
+ .into_iter()
.map(|p| traits::Obligation::new(cause.clone(), this.param_env, p))
.collect();
Ok(InferOk {
// When NLL is enabled, the borrow checker runs the typeck
// itself, so we don't need this MIR pass anymore.
- if tcx.nll() {
+ if tcx.use_mir_borrowck() {
return;
}
/// True if `r` is a member of this set of universal regions.
pub fn is_universal_region(&self, r: RegionVid) -> bool {
- (FIRST_GLOBAL_INDEX..self.num_universals).contains(r.index())
+ (FIRST_GLOBAL_INDEX..self.num_universals).contains(&r.index())
}
/// Classifies `r` as a universal region, returning `None` if this
/// is not a member of this set of universal regions.
pub fn region_classification(&self, r: RegionVid) -> Option<RegionClassification> {
let index = r.index();
- if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(index) {
+ if (FIRST_GLOBAL_INDEX..self.first_extern_index).contains(&index) {
Some(RegionClassification::Global)
- } else if (self.first_extern_index..self.first_local_index).contains(index) {
+ } else if (self.first_extern_index..self.first_local_index).contains(&index) {
Some(RegionClassification::External)
- } else if (self.first_local_index..self.num_universals).contains(index) {
+ } else if (self.first_local_index..self.num_universals).contains(&index) {
Some(RegionClassification::Local)
} else {
None
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir;
+use rustc::mir::ProjectionElem;
+use rustc::mir::{Local, Mir, Place};
+use rustc::ty::{self, TyCtxt};
+
+/// Extension methods for the `Place` type.
+crate trait PlaceExt<'tcx> {
+ /// True if this is a deref of a raw pointer.
+ fn is_unsafe_place(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool;
+
+ /// If this is a place like `x.f.g`, returns the local
+ /// `x`. Returns `None` if this is based in a static.
+ fn root_local(&self) -> Option<Local>;
+}
+
+impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
+ fn is_unsafe_place(&self, tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> bool {
+ match self {
+ Place::Local(_) => false,
+ Place::Static(static_) => {
+ tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
+ }
+ Place::Projection(proj) => match proj.elem {
+ ProjectionElem::Field(..)
+ | ProjectionElem::Downcast(..)
+ | ProjectionElem::Subslice { .. }
+ | ProjectionElem::ConstantIndex { .. }
+ | ProjectionElem::Index(_) => proj.base.is_unsafe_place(tcx, mir),
+ ProjectionElem::Deref => {
+ let ty = proj.base.ty(mir, tcx).to_ty(tcx);
+ match ty.sty {
+ ty::TyRawPtr(..) => true,
+ _ => proj.base.is_unsafe_place(tcx, mir),
+ }
+ }
+ },
+ }
+ }
+
+ fn root_local(&self) -> Option<Local> {
+ let mut p = self;
+ loop {
+ match p {
+ Place::Projection(pi) => p = &pi.base,
+ Place::Static(_) => return None,
+ Place::Local(l) => return Some(*l),
+ }
+ }
+ }
+}
PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
i == variant_index || {
+ self.hir.tcx().features().never_type &&
self.hir.tcx().features().exhaustive_patterns &&
self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use borrow_check::borrow_set::{BorrowSet, BorrowData};
+use borrow_check::place_ext::PlaceExt;
+
use rustc;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::region;
use rustc::mir::{self, Location, Place, Mir};
-use rustc::mir::visit::{PlaceContext, Visitor};
-use rustc::ty::{self, Region, TyCtxt};
+use rustc::ty::TyCtxt;
use rustc::ty::RegionKind;
use rustc::ty::RegionKind::ReScope;
-use rustc::util::nodemap::{FxHashMap, FxHashSet};
-use rustc_data_structures::bitslice::{BitwiseOperator};
-use rustc_data_structures::indexed_set::{IdxSet};
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_data_structures::bitslice::BitwiseOperator;
+use rustc_data_structures::indexed_set::IdxSet;
+use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::sync::Lrc;
use dataflow::{BitDenotation, BlockSets, InitialFlow};
-pub use dataflow::indexes::{BorrowIndex, ReserveOrActivateIndex};
+pub use dataflow::indexes::BorrowIndex;
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::ToRegionVid;
-use syntax_pos::Span;
-
-use std::fmt;
-use std::hash::Hash;
use std::rc::Rc;
/// `Borrows` stores the data used in the analyses that track the flow
scope_tree: Lrc<region::ScopeTree>,
root_scope: Option<region::Scope>,
- /// The fundamental map relating bitvector indexes to the borrows
- /// in the MIR.
- borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
-
- /// Each borrow is also uniquely identified in the MIR by the
- /// `Location` of the assignment statement in which it appears on
- /// the right hand side; we map each such location to the
- /// corresponding `BorrowIndex`.
- location_map: FxHashMap<Location, BorrowIndex>,
-
- /// Every borrow in MIR is immediately stored into a place via an
- /// assignment statement. This maps each such assigned place back
- /// to its borrow-indexes.
- assigned_map: FxHashMap<Place<'tcx>, FxHashSet<BorrowIndex>>,
-
- /// Locations which activate borrows.
- activation_map: FxHashMap<Location, FxHashSet<BorrowIndex>>,
-
- /// Every borrow has a region; this maps each such regions back to
- /// its borrow-indexes.
- region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
-
- /// Map from local to all the borrows on that local
- local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
-
- /// Maps regions to their corresponding source spans
- /// Only contains ReScope()s as keys
- region_span_map: FxHashMap<RegionKind, Span>,
+ borrow_set: Rc<BorrowSet<'tcx>>,
/// NLL region inference context with which NLL queries should be resolved
- nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
-}
-
-// temporarily allow some dead fields: `kind` and `region` will be
-// needed by borrowck; `borrowed_place` will probably be a MovePathIndex when
-// that is extended to include borrowed data paths.
-#[allow(dead_code)]
-#[derive(Debug)]
-pub struct BorrowData<'tcx> {
- /// Location where the borrow reservation starts.
- /// In many cases, this will be equal to the activation location but not always.
- pub(crate) reserve_location: Location,
- /// What kind of borrow this is
- pub(crate) kind: mir::BorrowKind,
- /// The region for which this borrow is live
- pub(crate) region: Region<'tcx>,
- /// Place from which we are borrowing
- pub(crate) borrowed_place: mir::Place<'tcx>,
- /// Place to which the borrow was stored
- pub(crate) assigned_place: mir::Place<'tcx>,
-}
-
-impl<'tcx> fmt::Display for BorrowData<'tcx> {
- fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
- let kind = match self.kind {
- mir::BorrowKind::Shared => "",
- mir::BorrowKind::Unique => "uniq ",
- mir::BorrowKind::Mut { .. } => "mut ",
- };
- let region = format!("{}", self.region);
- let region = if region.len() > 0 { format!("{} ", region) } else { region };
- write!(w, "&{}{}{:?}", region, kind, self.borrowed_place)
- }
-}
-
-impl ReserveOrActivateIndex {
- fn reserved(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new(i.index() * 2) }
- fn active(i: BorrowIndex) -> Self { ReserveOrActivateIndex::new((i.index() * 2) + 1) }
-
- pub(crate) fn is_reservation(self) -> bool { self.index() % 2 == 0 }
- pub(crate) fn is_activation(self) -> bool { self.index() % 2 == 1}
-
- pub(crate) fn kind(self) -> &'static str {
- if self.is_reservation() { "reserved" } else { "active" }
- }
- pub(crate) fn borrow_index(self) -> BorrowIndex {
- BorrowIndex::new(self.index() / 2)
- }
+ nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
}
impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- mir: &'a Mir<'tcx>,
- nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
- def_id: DefId,
- body_id: Option<hir::BodyId>)
- -> Self {
+ crate fn new(
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ nonlexical_regioncx: Rc<RegionInferenceContext<'tcx>>,
+ def_id: DefId,
+ body_id: Option<hir::BodyId>,
+ borrow_set: &Rc<BorrowSet<'tcx>>
+ ) -> Self {
let scope_tree = tcx.region_scope_tree(def_id);
let root_scope = body_id.map(|body_id| {
region::Scope::CallSite(tcx.hir.body(body_id).value.hir_id.local_id)
});
- let mut visitor = GatherBorrows {
- tcx,
- mir,
- idx_vec: IndexVec::new(),
- location_map: FxHashMap(),
- assigned_map: FxHashMap(),
- activation_map: FxHashMap(),
- region_map: FxHashMap(),
- local_map: FxHashMap(),
- region_span_map: FxHashMap(),
- nonlexical_regioncx: nonlexical_regioncx.clone()
- };
- visitor.visit_mir(mir);
- return Borrows { tcx: tcx,
- mir: mir,
- borrows: visitor.idx_vec,
- scope_tree,
- root_scope,
- location_map: visitor.location_map,
- assigned_map: visitor.assigned_map,
- activation_map: visitor.activation_map,
- region_map: visitor.region_map,
- local_map: visitor.local_map,
- region_span_map: visitor.region_span_map,
- nonlexical_regioncx };
-
- struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- mir: &'a Mir<'tcx>,
- idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
- location_map: FxHashMap<Location, BorrowIndex>,
- assigned_map: FxHashMap<Place<'tcx>, FxHashSet<BorrowIndex>>,
- activation_map: FxHashMap<Location, FxHashSet<BorrowIndex>>,
- region_map: FxHashMap<Region<'tcx>, FxHashSet<BorrowIndex>>,
- local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
- region_span_map: FxHashMap<RegionKind, Span>,
- nonlexical_regioncx: Option<Rc<RegionInferenceContext<'tcx>>>,
- }
-
- impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
- fn visit_assign(&mut self,
- block: mir::BasicBlock,
- assigned_place: &mir::Place<'tcx>,
- rvalue: &mir::Rvalue<'tcx>,
- location: mir::Location) {
- fn root_local(mut p: &mir::Place<'_>) -> Option<mir::Local> {
- loop { match p {
- mir::Place::Projection(pi) => p = &pi.base,
- mir::Place::Static(_) => return None,
- mir::Place::Local(l) => return Some(*l)
- }}
- }
-
- if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
- if is_unsafe_place(self.tcx, self.mir, borrowed_place) { return; }
-
- let activate_location = self.compute_activation_location(location,
- &assigned_place,
- region,
- kind);
- let borrow = BorrowData {
- kind, region,
- reserve_location: location,
- borrowed_place: borrowed_place.clone(),
- assigned_place: assigned_place.clone(),
- };
- let idx = self.idx_vec.push(borrow);
- self.location_map.insert(location, idx);
-
- insert(&mut self.activation_map, &activate_location, idx);
- insert(&mut self.assigned_map, assigned_place, idx);
- insert(&mut self.region_map, ®ion, idx);
- if let Some(local) = root_local(borrowed_place) {
- insert(&mut self.local_map, &local, idx);
- }
- }
-
- return self.super_assign(block, assigned_place, rvalue, location);
-
- fn insert<'a, K, V>(map: &'a mut FxHashMap<K, FxHashSet<V>>,
- k: &K,
- v: V)
- where K: Clone+Eq+Hash, V: Eq+Hash
- {
- map.entry(k.clone())
- .or_insert(FxHashSet())
- .insert(v);
- }
- }
-
- fn visit_rvalue(&mut self,
- rvalue: &mir::Rvalue<'tcx>,
- location: mir::Location) {
- if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
- // double-check that we already registered a BorrowData for this
-
- let mut found_it = false;
- for idx in &self.region_map[region] {
- let bd = &self.idx_vec[*idx];
- if bd.reserve_location == location &&
- bd.kind == kind &&
- bd.region == region &&
- bd.borrowed_place == *place
- {
- found_it = true;
- break;
- }
- }
- assert!(found_it, "Ref {:?} at {:?} missing BorrowData", rvalue, location);
- }
-
- return self.super_rvalue(rvalue, location);
- }
-
- fn visit_statement(&mut self,
- block: mir::BasicBlock,
- statement: &mir::Statement<'tcx>,
- location: Location) {
- if let mir::StatementKind::EndRegion(region_scope) = statement.kind {
- self.region_span_map.insert(ReScope(region_scope), statement.source_info.span);
- }
- return self.super_statement(block, statement, location);
- }
- }
-
- /// A MIR visitor that determines if a specific place is used in a two-phase activating
- /// manner in a given chunk of MIR.
- struct ContainsUseOfPlace<'b, 'tcx: 'b> {
- target: &'b Place<'tcx>,
- use_found: bool,
- }
-
- impl<'b, 'tcx: 'b> ContainsUseOfPlace<'b, 'tcx> {
- fn new(place: &'b Place<'tcx>) -> Self {
- Self { target: place, use_found: false }
- }
-
- /// return whether `context` should be considered a "use" of a
- /// place found in that context. "Uses" activate associated
- /// borrows (at least when such uses occur while the borrow also
- /// has a reservation at the time).
- fn is_potential_use(context: PlaceContext) -> bool {
- match context {
- // storage effects on a place do not activate it
- PlaceContext::StorageLive | PlaceContext::StorageDead => false,
-
- // validation effects do not activate a place
- //
- // FIXME: Should they? Is it just another read? Or can we
- // guarantee it won't dereference the stored address? How
- // "deep" does validation go?
- PlaceContext::Validate => false,
-
- // FIXME: This is here to not change behaviour from before
- // AsmOutput existed, but it's not necessarily a pure overwrite.
- // so it's possible this should activate the place.
- PlaceContext::AsmOutput |
- // pure overwrites of a place do not activate it. (note
- // PlaceContext::Call is solely about dest place)
- PlaceContext::Store | PlaceContext::Call => false,
-
- // reads of a place *do* activate it
- PlaceContext::Move |
- PlaceContext::Copy |
- PlaceContext::Drop |
- PlaceContext::Inspect |
- PlaceContext::Borrow { .. } |
- PlaceContext::Projection(..) => true,
- }
- }
- }
-
- impl<'b, 'tcx: 'b> Visitor<'tcx> for ContainsUseOfPlace<'b, 'tcx> {
- fn visit_place(&mut self,
- place: &mir::Place<'tcx>,
- context: PlaceContext<'tcx>,
- location: Location) {
- if Self::is_potential_use(context) && place == self.target {
- self.use_found = true;
- return;
- // There is no need to keep checking the statement, we already found a use
- }
-
- self.super_place(place, context, location);
- }
- }
-
- impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
- /// Returns true if the borrow represented by `kind` is
- /// allowed to be split into separate Reservation and
- /// Activation phases.
- fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
- self.tcx.two_phase_borrows() &&
- (kind.allows_two_phase_borrow() ||
- self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
- }
-
- /// Returns true if the given location contains an NLL-activating use of the given place
- fn location_contains_use(&self, location: Location, place: &Place) -> bool {
- let mut use_checker = ContainsUseOfPlace::new(place);
- let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
- panic!("could not find block at location {:?}", location);
- });
- if location.statement_index != block.statements.len() {
- // This is a statement
- let stmt = block.statements.get(location.statement_index).unwrap_or_else(|| {
- panic!("could not find statement at location {:?}");
- });
- use_checker.visit_statement(location.block, stmt, location);
- } else {
- // This is a terminator
- match block.terminator {
- Some(ref term) => {
- use_checker.visit_terminator(location.block, term, location);
- }
- None => {
- // There is no way for Place to be used by the terminator if there is no
- // terminator
- }
- }
- }
-
- use_checker.use_found
- }
-
- /// Determines if the provided region is terminated after the provided location.
- /// EndRegion statements terminate their enclosed region::Scope.
- /// We also consult with the NLL region inference engine, should one be available
- fn region_terminated_after(&self, region: Region<'tcx>, location: Location) -> bool {
- let block_data = &self.mir[location.block];
- if location.statement_index != block_data.statements.len() {
- let stmt = &block_data.statements[location.statement_index];
- if let mir::StatementKind::EndRegion(region_scope) = stmt.kind {
- if &ReScope(region_scope) == region {
- // We encountered an EndRegion statement that terminates the provided
- // region
- return true;
- }
- }
- }
- if let Some(ref regioncx) = self.nonlexical_regioncx {
- if !regioncx.region_contains_point(region, location) {
- // NLL says the region has ended already
- return true;
- }
- }
-
- false
- }
-
- /// Computes the activation location of a borrow.
- /// The general idea is to start at the beginning of the region and perform a DFS
- /// until we exit the region, either via an explicit EndRegion or because NLL tells
- /// us so. If we find more than one valid activation point, we currently panic the
- /// compiler since two-phase borrows are only currently supported for compiler-
- /// generated code. More precisely, we only allow two-phase borrows for:
- /// - Function calls (fn some_func(&mut self, ....))
- /// - *Assign operators (a += b -> fn add_assign(&mut self, other: Self))
- /// See
- /// - https://github.com/rust-lang/rust/issues/48431
- /// for detailed design notes.
- /// See the FIXME in the body of the function for notes on extending support to more
- /// general two-phased borrows.
- fn compute_activation_location(&self,
- start_location: Location,
- assigned_place: &mir::Place<'tcx>,
- region: Region<'tcx>,
- kind: mir::BorrowKind) -> Location {
- debug!("Borrows::compute_activation_location({:?}, {:?}, {:?})",
- start_location,
- assigned_place,
- region);
- if !self.allow_two_phase_borrow(kind) {
- debug!(" -> {:?}", start_location);
- return start_location;
- }
-
- // Perform the DFS.
- // `stack` is the stack of locations still under consideration
- // `visited` is the set of points we have already visited
- // `found_use` is an Option that becomes Some when we find a use
- let mut stack = vec![start_location];
- let mut visited = FxHashSet();
- let mut found_use = None;
- while let Some(curr_loc) = stack.pop() {
- let block_data = &self.mir.basic_blocks()
- .get(curr_loc.block)
- .unwrap_or_else(|| {
- panic!("could not find block at location {:?}", curr_loc);
- });
-
- if self.region_terminated_after(region, curr_loc) {
- // No need to process this statement.
- // It's either an EndRegion (and thus couldn't use assigned_place) or not
- // contained in the NLL region and thus a use would be invalid
- continue;
- }
-
- if !visited.insert(curr_loc) {
- debug!(" Already visited {:?}", curr_loc);
- continue;
- }
-
- if self.location_contains_use(curr_loc, assigned_place) {
- // FIXME: Handle this case a little more gracefully. Perhaps collect
- // all uses in a vector, and find the point in the CFG that dominates
- // all of them?
- // Right now this is sufficient though since there should only be exactly
- // one borrow-activating use of the borrow.
- assert!(found_use.is_none(), "Found secondary use of place");
- found_use = Some(curr_loc);
- }
-
- // Push the points we should consider next.
- if curr_loc.statement_index < block_data.statements.len() {
- stack.push(curr_loc.successor_within_block());
- } else {
- stack.extend(block_data.terminator().successors().iter().map(
- |&basic_block| {
- Location {
- statement_index: 0,
- block: basic_block
- }
- }
- ))
- }
- }
- let found_use = found_use.expect("Did not find use of two-phase place");
- debug!(" -> {:?}", found_use);
- found_use
- }
- }
- }
-
- /// Returns the span for the "end point" given region. This will
- /// return `None` if NLL is enabled, since that concept has no
- /// meaning there. Otherwise, return region span if it exists and
- /// span for end of the function if it doesn't exist.
- pub(crate) fn opt_region_end_span(&self, region: &Region) -> Option<Span> {
- match self.nonlexical_regioncx {
- Some(_) => None,
- None => {
- match self.region_span_map.get(region) {
- Some(span) => Some(self.tcx.sess.codemap().end_point(*span)),
- None => Some(self.tcx.sess.codemap().end_point(self.mir.span))
- }
- }
+ Borrows {
+ tcx: tcx,
+ mir: mir,
+ borrow_set: borrow_set.clone(),
+ scope_tree,
+ root_scope,
+ nonlexical_regioncx,
}
}
- pub fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrows }
+ crate fn borrows(&self) -> &IndexVec<BorrowIndex, BorrowData<'tcx>> { &self.borrow_set.borrows }
pub fn scope_tree(&self) -> &Lrc<region::ScopeTree> { &self.scope_tree }
pub fn location(&self, idx: BorrowIndex) -> &Location {
- &self.borrows[idx].reserve_location
+ &self.borrow_set.borrows[idx].reserve_location
}
/// Add all borrows to the kill set, if those borrows are out of scope at `location`.
/// That means either they went out of either a nonlexical scope, if we care about those
/// at the moment, or the location represents a lexical EndRegion
fn kill_loans_out_of_scope_at_location(&self,
- sets: &mut BlockSets<ReserveOrActivateIndex>,
+ sets: &mut BlockSets<BorrowIndex>,
location: Location) {
- if let Some(ref regioncx) = self.nonlexical_regioncx {
- // NOTE: The state associated with a given `location`
- // reflects the dataflow on entry to the statement. If it
- // does not contain `borrow_region`, then then that means
- // that the statement at `location` kills the borrow.
- //
- // We are careful always to call this function *before* we
- // set up the gen-bits for the statement or
- // termanator. That way, if the effect of the statement or
- // terminator *does* introduce a new loan of the same
- // region, then setting that gen-bit will override any
- // potential kill introduced here.
- for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
- let borrow_region = borrow_data.region.to_region_vid();
- if !regioncx.region_contains_point(borrow_region, location) {
- sets.kill(&ReserveOrActivateIndex::reserved(borrow_index));
- sets.kill(&ReserveOrActivateIndex::active(borrow_index));
- }
+ let regioncx = &self.nonlexical_regioncx;
+
+ // NOTE: The state associated with a given `location`
+ // reflects the dataflow on entry to the statement. If it
+ // does not contain `borrow_region`, then then that means
+ // that the statement at `location` kills the borrow.
+ //
+ // We are careful always to call this function *before* we
+ // set up the gen-bits for the statement or
+ // termanator. That way, if the effect of the statement or
+ // terminator *does* introduce a new loan of the same
+ // region, then setting that gen-bit will override any
+ // potential kill introduced here.
+ for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() {
+ let borrow_region = borrow_data.region.to_region_vid();
+ if !regioncx.region_contains_point(borrow_region, location) {
+ sets.kill(&borrow_index);
}
}
}
fn kill_borrows_on_local(&self,
- sets: &mut BlockSets<ReserveOrActivateIndex>,
+ sets: &mut BlockSets<BorrowIndex>,
local: &rustc::mir::Local)
{
- if let Some(borrow_indexes) = self.local_map.get(local) {
- sets.kill_all(borrow_indexes.iter()
- .map(|b| ReserveOrActivateIndex::reserved(*b)));
- sets.kill_all(borrow_indexes.iter()
- .map(|b| ReserveOrActivateIndex::active(*b)));
- }
- }
-
- /// Performs the activations for a given location
- fn perform_activations_at_location(&self,
- sets: &mut BlockSets<ReserveOrActivateIndex>,
- location: Location) {
- // Handle activations
- match self.activation_map.get(&location) {
- Some(activations) => {
- for activated in activations {
- debug!("activating borrow {:?}", activated);
- sets.gen(&ReserveOrActivateIndex::active(*activated))
- }
- }
- None => {}
+ if let Some(borrow_indexes) = self.borrow_set.local_map.get(local) {
+ sets.kill_all(borrow_indexes);
}
}
}
impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> {
- type Idx = ReserveOrActivateIndex;
+ type Idx = BorrowIndex;
fn name() -> &'static str { "borrows" }
fn bits_per_block(&self) -> usize {
- self.borrows.len() * 2
+ self.borrow_set.borrows.len() * 2
}
- fn start_block_effect(&self, _entry_set: &mut IdxSet<ReserveOrActivateIndex>) {
+ fn start_block_effect(&self, _entry_set: &mut IdxSet<BorrowIndex>) {
// no borrows of code region_scopes have been taken prior to
// function execution, so this method has no effect on
// `_sets`.
}
fn before_statement_effect(&self,
- sets: &mut BlockSets<ReserveOrActivateIndex>,
+ sets: &mut BlockSets<BorrowIndex>,
location: Location) {
debug!("Borrows::before_statement_effect sets: {:?} location: {:?}", sets, location);
self.kill_loans_out_of_scope_at_location(sets, location);
}
- fn statement_effect(&self, sets: &mut BlockSets<ReserveOrActivateIndex>, location: Location) {
+ fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
debug!("Borrows::statement_effect sets: {:?} location: {:?}", sets, location);
let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
panic!("could not find statement at location {:?}");
});
- self.perform_activations_at_location(sets, location);
self.kill_loans_out_of_scope_at_location(sets, location);
match stmt.kind {
- // EndRegion kills any borrows (reservations and active borrows both)
- mir::StatementKind::EndRegion(region_scope) => {
- if let Some(borrow_indexes) = self.region_map.get(&ReScope(region_scope)) {
- assert!(self.nonlexical_regioncx.is_none());
- for idx in borrow_indexes {
- sets.kill(&ReserveOrActivateIndex::reserved(*idx));
- sets.kill(&ReserveOrActivateIndex::active(*idx));
- }
- } else {
- // (if there is no entry, then there are no borrows to be tracked)
- }
+ mir::StatementKind::EndRegion(_) => {
}
mir::StatementKind::Assign(ref lhs, ref rhs) => {
// propagate_call_return method.
if let mir::Rvalue::Ref(region, _, ref place) = *rhs {
- if is_unsafe_place(self.tcx, self.mir, place) { return; }
- let index = self.location_map.get(&location).unwrap_or_else(|| {
+ if place.is_unsafe_place(self.tcx, self.mir) { return; }
+ let index = self.borrow_set.location_map.get(&location).unwrap_or_else(|| {
panic!("could not find BorrowIndex for location {:?}", location);
});
if let RegionKind::ReEmpty = region {
// If the borrowed value dies before the borrow is used, the region for
// the borrow can be empty. Don't track the borrow in that case.
- sets.kill(&ReserveOrActivateIndex::active(*index));
+ sets.kill(&index);
return
}
- assert!(self.region_map.get(region).unwrap_or_else(|| {
+ assert!(self.borrow_set.region_map.get(region).unwrap_or_else(|| {
panic!("could not find BorrowIndexs for region {:?}", region);
}).contains(&index));
- sets.gen(&ReserveOrActivateIndex::reserved(*index));
+ sets.gen(&index);
// Issue #46746: Two-phase borrows handles
// stmts of form `Tmp = &mut Borrow` ...
// e.g. `box (&mut _)`. Current
// conservative solution: force
// immediate activation here.
- sets.gen(&ReserveOrActivateIndex::active(*index));
+ sets.gen(&index);
}
}
}
}
fn before_terminator_effect(&self,
- sets: &mut BlockSets<ReserveOrActivateIndex>,
+ sets: &mut BlockSets<BorrowIndex>,
location: Location) {
debug!("Borrows::before_terminator_effect sets: {:?} location: {:?}", sets, location);
self.kill_loans_out_of_scope_at_location(sets, location);
}
- fn terminator_effect(&self, sets: &mut BlockSets<ReserveOrActivateIndex>, location: Location) {
+ fn terminator_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) {
debug!("Borrows::terminator_effect sets: {:?} location: {:?}", sets, location);
let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| {
});
let term = block.terminator();
- self.perform_activations_at_location(sets, location);
self.kill_loans_out_of_scope_at_location(sets, location);
// and hence most of these loans will already be dead -- but, in some cases
// like unwind paths, we do not always emit `EndRegion` statements, so we
// add some kills here as a "backup" and to avoid spurious error messages.
- for (borrow_index, borrow_data) in self.borrows.iter_enumerated() {
+ for (borrow_index, borrow_data) in self.borrow_set.borrows.iter_enumerated() {
if let ReScope(scope) = borrow_data.region {
// Check that the scope is not actually a scope from a function that is
// a parent of our closure. Note that the CallSite scope itself is
if *scope != root_scope &&
self.scope_tree.is_subscope_of(*scope, root_scope)
{
- sets.kill(&ReserveOrActivateIndex::reserved(borrow_index));
- sets.kill(&ReserveOrActivateIndex::active(borrow_index));
+ sets.kill(&borrow_index);
}
}
}
}
fn propagate_call_return(&self,
- _in_out: &mut IdxSet<ReserveOrActivateIndex>,
+ _in_out: &mut IdxSet<BorrowIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
_dest_place: &mir::Place) {
}
}
-fn is_unsafe_place<'a, 'gcx: 'tcx, 'tcx: 'a>(
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- mir: &'a Mir<'tcx>,
- place: &mir::Place<'tcx>
-) -> bool {
- use self::mir::Place::*;
- use self::mir::ProjectionElem;
-
- match *place {
- Local(_) => false,
- Static(ref static_) => tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable),
- Projection(ref proj) => {
- match proj.elem {
- ProjectionElem::Field(..) |
- ProjectionElem::Downcast(..) |
- ProjectionElem::Subslice { .. } |
- ProjectionElem::ConstantIndex { .. } |
- ProjectionElem::Index(_) => {
- is_unsafe_place(tcx, mir, &proj.base)
- }
- ProjectionElem::Deref => {
- let ty = proj.base.ty(mir, tcx).to_ty(tcx);
- match ty.sty {
- ty::TyRawPtr(..) => true,
- _ => is_unsafe_place(tcx, mir, &proj.base),
- }
- }
- }
- }
- }
-}
use rustc_data_structures::indexed_vec::Idx;
use super::MoveDataParamEnv;
+
use util::elaborate_drops::DropFlagState;
use super::move_paths::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex, InitIndex};
pub use self::borrowed_locals::*;
-#[allow(dead_code)]
pub(super) mod borrows;
/// `MaybeInitializedPlaces` tracks all places that might be
pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
pub use self::impls::EverInitializedPlaces;
-pub use self::impls::borrows::{Borrows, BorrowData};
+pub use self::impls::borrows::Borrows;
pub use self::impls::HaveBeenBorrowedLocals;
-pub(crate) use self::impls::borrows::{ReserveOrActivateIndex};
pub use self::at_location::{FlowAtLocation, FlowsAtLocation};
pub(crate) use self::drop_flag_effects::*;
/// Index into Borrows.locations
new_index!(BorrowIndex, "bw");
-
- /// Index into Reservations/Activations bitvector
- new_index!(ReserveOrActivateIndex, "ra");
}
pub use self::indexes::MovePathIndex;
Ok(true)
}
-fn constructor_covered_by_range(ctor: &Constructor,
- from: &ConstVal, to: &ConstVal,
- end: RangeEnd,
- ty: Ty)
- -> Result<bool, ErrorReported> {
+fn constructor_covered_by_range<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ctor: &Constructor,
+ from: &ConstVal, to: &ConstVal,
+ end: RangeEnd,
+ ty: Ty<'tcx>,
+) -> Result<bool, ErrorReported> {
trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
- let cmp_from = |c_from| compare_const_vals(c_from, from, ty)
+ let cmp_from = |c_from| compare_const_vals(tcx, c_from, from, ty)
.map(|res| res != Ordering::Less);
- let cmp_to = |c_to| compare_const_vals(c_to, to, ty);
+ let cmp_to = |c_to| compare_const_vals(tcx, c_to, to, ty);
macro_rules! some_or_ok {
($e:expr) => {
match $e {
},
_ => {
match constructor_covered_by_range(
+ cx.tcx,
constructor, &value.val, &value.val, RangeEnd::Included,
value.ty,
) {
PatternKind::Range { lo, hi, ref end } => {
match constructor_covered_by_range(
+ cx.tcx,
constructor, &lo.val, &hi.val, end.clone(), lo.ty,
) {
Ok(true) => Some(vec![]),
pub use self::check_match::check_crate;
pub(crate) use self::check_match::check_match;
-use interpret::{const_val_field, const_discr};
+use interpret::{const_val_field, const_discr, self};
use rustc::middle::const_val::ConstVal;
use rustc::mir::{Field, BorrowKind, Mutability};
(PatternKind::Constant { value: lo },
PatternKind::Constant { value: hi }) => {
use std::cmp::Ordering;
- match (end, compare_const_vals(&lo.val, &hi.val, ty).unwrap()) {
+ match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) {
(RangeEnd::Excluded, Ordering::Less) =>
PatternKind::Range { lo, hi, end },
(RangeEnd::Excluded, _) => {
}
}
-pub fn compare_const_vals(a: &ConstVal, b: &ConstVal, ty: Ty) -> Option<Ordering> {
+pub fn compare_const_vals<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ a: &ConstVal,
+ b: &ConstVal,
+ ty: Ty<'tcx>,
+) -> Option<Ordering> {
use rustc_const_math::ConstFloat;
trace!("compare_const_vals: {:?}, {:?}", a, b);
use rustc::mir::interpret::{Value, PrimVal};
// FIXME(oli-obk): report cmp errors?
l.try_cmp(r).ok()
},
- ty::TyInt(_) => Some((a as i128).cmp(&(b as i128))),
+ ty::TyInt(_) => {
+ let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
+ let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
+ Some((a as i128).cmp(&(b as i128)))
+ },
_ => Some(a.cmp(&b)),
}
},
Ok(ecx)
}
-pub fn eval_body_with_mir<'a, 'mir, 'tcx>(
+pub fn eval_promoted<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
mir: &'mir mir::Mir<'tcx>,
match res {
Ok(val) => Some(val),
Err(mut err) => {
- ecx.report(&mut err, true, None);
+ ecx.report(&mut err, false, None);
None
}
}
self.param_env,
def_id,
substs,
- ).ok_or(EvalErrorKind::TypeckError.into()) // turn error prop into a panic to expose associated type in const issue
+ ).ok_or_else(|| EvalErrorKind::TypeckError.into()) // turn error prop into a panic to expose associated type in const issue
}
pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
trace!("load mir {:?}", instance);
match instance {
ty::InstanceDef::Item(def_id) => {
- self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| {
+ self.tcx.maybe_optimized_mir(def_id).ok_or_else(||
EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into()
- })
+ )
}
_ => Ok(self.tcx.instance_mir(instance)),
}
self.param_env,
def_id,
substs,
- ).ok_or(EvalErrorKind::TypeckError.into());
+ ).ok_or_else(|| EvalErrorKind::TypeckError.into());
let fn_ptr = self.memory.create_fn_alloc(instance?);
let valty = ValTy {
value: Value::ByVal(PrimVal::Ptr(fn_ptr)),
}
pub fn sign_extend(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
- let layout = self.layout_of(ty)?;
- let size = layout.size.bits();
- assert!(layout.abi.is_signed());
- // sign extend
- let amt = 128 - size;
- // shift the unsigned value to the left
- // and back to the right as signed (essentially fills with FF on the left)
- Ok((((value << amt) as i128) >> amt) as u128)
+ super::sign_extend(self.tcx.tcx, value, ty)
}
pub fn truncate(&self, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
- let size = self.layout_of(ty)?.size.bits();
- let amt = 128 - size;
- // truncate (shift left to drop out leftover values, shift right to fill with zeroes)
- Ok((value << amt) >> amt)
+ super::truncate(self.tcx.tcx, value, ty)
}
}
impl<'mir, 'tcx> Frame<'mir, 'tcx> {
pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> {
- self.locals[local].ok_or(EvalErrorKind::DeadLocal.into())
+ self.locals[local].ok_or_else(|| EvalErrorKind::DeadLocal.into())
}
fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> {
pub use self::memory::{Memory, MemoryKind, HasMemory};
pub use self::const_eval::{
- eval_body_with_mir,
+ eval_promoted,
mk_borrowck_eval_cx,
eval_body,
CompileTimeEvaluator,
pub use self::machine::Machine;
pub use self::memory::{write_target_uint, write_target_int, read_target_uint};
+
+use rustc::mir::interpret::{EvalResult, EvalErrorKind};
+use rustc::ty::{Ty, TyCtxt, ParamEnv};
+
+pub fn sign_extend<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
+ let param_env = ParamEnv::empty();
+ let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?;
+ let size = layout.size.bits();
+ assert!(layout.abi.is_signed());
+ // sign extend
+ let amt = 128 - size;
+ // shift the unsigned value to the left
+ // and back to the right as signed (essentially fills with FF on the left)
+ Ok((((value << amt) as i128) >> amt) as u128)
+}
+
+pub fn truncate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, value: u128, ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
+ let param_env = ParamEnv::empty();
+ let layout = tcx.layout_of(param_env.and(ty)).map_err(|layout| EvalErrorKind::Layout(layout))?;
+ let size = layout.size.bits();
+ let amt = 128 - size;
+ // truncate (shift left to drop out leftover values, shift right to fill with zeroes)
+ Ok((value << amt) >> amt)
+}
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(catch_expr)]
+#![feature(crate_visibility_modifier)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(decl_macro)]
#![feature(nonzero)]
#![feature(inclusive_range_fields)]
#![feature(crate_visibility_modifier)]
+#![feature(never_type)]
#![cfg_attr(stage0, feature(try_trait))]
extern crate arena;
param_substs: instance.substs,
}.visit_mir(&mir);
let param_env = ty::ParamEnv::reveal_all();
- for (i, promoted) in mir.promoted.iter().enumerate() {
+ for i in 0..mir.promoted.len() {
use rustc_data_structures::indexed_vec::Idx;
let cid = GlobalId {
instance,
};
match tcx.const_eval(param_env.and(cid)) {
Ok(val) => collect_const(tcx, val, instance.substs, output),
- Err(err) => {
- err.report(tcx, promoted.span, "promoted");
- }
+ Err(_) => {},
}
}
}
use rustc::middle::const_val::ConstVal;
use rustc::ty::{TyCtxt, self, Instance};
use rustc::mir::interpret::{Value, PrimVal, GlobalId};
-use interpret::{eval_body_with_mir, mk_borrowck_eval_cx, ValTy};
+use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
use transform::{MirPass, MirSource};
use syntax::codemap::Span;
use rustc::ty::subst::Substs;
};
// cannot use `const_eval` here, because that would require having the MIR
// for the current function available, but we're producing said MIR right now
- let (value, _, ty) = eval_body_with_mir(self.tcx, cid, self.mir, self.param_env)?;
+ let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
let val = (value, ty, c.span);
trace!("evaluated {:?} to {:?}", c, val);
Some(val)
let (msg, note) = if let UnstableFeatures::Disallow =
self.tcx.sess.opts.unstable_features {
(format!("calls in {}s are limited to \
- struct and enum constructors",
+ tuple structs and tuple variants",
self.mode),
Some("a limited form of compile-time function \
evaluation is available on a nightly \
} else {
(format!("calls in {}s are limited \
to constant functions, \
- struct and enum constructors",
+ tuple structs and tuple variants",
self.mode),
None)
};
self.err_handler().span_err(item.span, "inherent impls cannot be negative");
}
if defaultness == Defaultness::Default {
- self.err_handler().span_err(item.span, "inherent impls cannot be default");
+ self.err_handler()
+ .struct_span_err(item.span, "inherent impls cannot be default")
+ .note("only trait implementations may be annotated with default").emit();
}
}
ItemKind::ForeignMod(..) => {
RibKind<'a>),
}
-// The rib kind controls the translation of local
-// definitions (`Def::Local`) to upvars (`Def::Upvar`).
+/// The rib kind controls the translation of local
+/// definitions (`Def::Local`) to upvars (`Def::Upvar`).
#[derive(Copy, Clone, Debug)]
enum RibKind<'a> {
- // No translation needs to be applied.
+ /// No translation needs to be applied.
NormalRibKind,
- // We passed through a closure scope at the given node ID.
- // Translate upvars as appropriate.
+ /// We passed through a closure scope at the given node ID.
+ /// Translate upvars as appropriate.
ClosureRibKind(NodeId /* func id */),
- // We passed through an impl or trait and are now in one of its
- // methods or associated types. Allow references to ty params that impl or trait
- // binds. Disallow any other upvars (including other ty params that are
- // upvars).
+ /// We passed through an impl or trait and are now in one of its
+ /// methods or associated types. Allow references to ty params that impl or trait
+ /// binds. Disallow any other upvars (including other ty params that are
+ /// upvars).
TraitOrImplItemRibKind,
- // We passed through an item scope. Disallow upvars.
+ /// We passed through an item scope. Disallow upvars.
ItemRibKind,
- // We're in a constant item. Can't refer to dynamic stuff.
+ /// We're in a constant item. Can't refer to dynamic stuff.
ConstantItemRibKind,
- // We passed through a module.
+ /// We passed through a module.
ModuleRibKind(Module<'a>),
- // We passed through a `macro_rules!` statement
+ /// We passed through a `macro_rules!` statement
MacroDefinition(DefId),
- // All bindings in this rib are type parameters that can't be used
- // from the default of a type parameter because they're not declared
- // before said type parameter. Also see the `visit_generics` override.
+ /// All bindings in this rib are type parameters that can't be used
+ /// from the default of a type parameter because they're not declared
+ /// before said type parameter. Also see the `visit_generics` override.
ForwardTyParamBanRibKind,
}
}
}
-// Records a possibly-private value, type, or module definition.
+/// Records a possibly-private value, type, or module definition.
#[derive(Clone, Debug)]
pub struct NameBinding<'a> {
kind: NameBindingKind<'a>,
prelude: Option<Module<'a>>,
- // n.b. This is used only for better diagnostics, not name resolution itself.
+ /// n.b. This is used only for better diagnostics, not name resolution itself.
has_self: FxHashSet<DefId>,
- // Names of fields of an item `DefId` accessible with dot syntax.
- // Used for hints during error reporting.
+ /// Names of fields of an item `DefId` accessible with dot syntax.
+ /// Used for hints during error reporting.
field_names: FxHashMap<DefId, Vec<Name>>,
- // All imports known to succeed or fail.
+ /// All imports known to succeed or fail.
determined_imports: Vec<&'a ImportDirective<'a>>,
- // All non-determined imports.
+ /// All non-determined imports.
indeterminate_imports: Vec<&'a ImportDirective<'a>>,
- // The module that represents the current item scope.
+ /// The module that represents the current item scope.
current_module: Module<'a>,
- // The current set of local scopes for types and values.
- // FIXME #4948: Reuse ribs to avoid allocation.
+ /// The current set of local scopes for types and values.
+ /// FIXME #4948: Reuse ribs to avoid allocation.
ribs: PerNS<Vec<Rib<'a>>>,
- // The current set of local scopes, for labels.
+ /// The current set of local scopes, for labels.
label_ribs: Vec<Rib<'a>>,
- // The trait that the current context can refer to.
+ /// The trait that the current context can refer to.
current_trait_ref: Option<(Module<'a>, TraitRef)>,
- // The current self type if inside an impl (used for better errors).
+ /// The current self type if inside an impl (used for better errors).
current_self_type: Option<Ty>,
- // The idents for the primitive types.
+ /// The idents for the primitive types.
primitive_type_table: PrimitiveTypeTable,
def_map: DefMap,
pub export_map: ExportMap,
pub trait_map: TraitMap,
- // A map from nodes to anonymous modules.
- // Anonymous modules are pseudo-modules that are implicitly created around items
- // contained within blocks.
- //
- // For example, if we have this:
- //
- // fn f() {
- // fn g() {
- // ...
- // }
- // }
- //
- // There will be an anonymous module created around `g` with the ID of the
- // entry block for `f`.
+ /// A map from nodes to anonymous modules.
+ /// Anonymous modules are pseudo-modules that are implicitly created around items
+ /// contained within blocks.
+ ///
+ /// For example, if we have this:
+ ///
+ /// fn f() {
+ /// fn g() {
+ /// ...
+ /// }
+ /// }
+ ///
+ /// There will be an anonymous module created around `g` with the ID of the
+ /// entry block for `f`.
block_map: NodeMap<Module<'a>>,
module_map: FxHashMap<DefId, Module<'a>>,
extern_module_map: FxHashMap<(DefId, bool /* MacrosOnly? */), Module<'a>>,
arenas: &'a ResolverArenas<'a>,
dummy_binding: &'a NameBinding<'a>,
- use_extern_macros: bool, // true if `#![feature(use_extern_macros)]`
+ /// true if `#![feature(use_extern_macros)]`
+ use_extern_macros: bool,
crate_loader: &'a mut CrateLoader,
macro_names: FxHashSet<Ident>,
pub whitelisted_legacy_custom_derives: Vec<Name>,
pub found_unresolved_macro: bool,
- // List of crate local macros that we need to warn about as being unused.
- // Right now this only includes macro_rules! macros, and macros 2.0.
+ /// List of crate local macros that we need to warn about as being unused.
+ /// Right now this only includes macro_rules! macros, and macros 2.0.
unused_macros: FxHashSet<DefId>,
- // Maps the `Mark` of an expansion to its containing module or block.
+ /// Maps the `Mark` of an expansion to its containing module or block.
invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
- // Avoid duplicated errors for "name already defined".
+ /// Avoid duplicated errors for "name already defined".
name_already_seen: FxHashMap<Name, Span>,
- // If `#![feature(proc_macro)]` is set
+ /// If `#![feature(proc_macro)]` is set
proc_macro_enabled: bool,
- // A set of procedural macros imported by `#[macro_use]` that have already been warned about
+ /// A set of procedural macros imported by `#[macro_use]` that have already been warned about
warned_proc_macros: FxHashSet<Name>,
potentially_unused_imports: Vec<&'a ImportDirective<'a>>,
- // This table maps struct IDs into struct constructor IDs,
- // it's not used during normal resolution, only for better error reporting.
+ /// This table maps struct IDs into struct constructor IDs,
+ /// it's not used during normal resolution, only for better error reporting.
struct_constructors: DefIdMap<(Def, ty::Visibility)>,
- // Only used for better errors on `fn(): fn()`
+ /// Only used for better errors on `fn(): fn()`
current_type_ascription: Vec<Span>,
injected_crate: Option<Module<'a>>,
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
+ if path.segments.len() > 1 {
+ if !self.session.features_untracked().proc_macro_path_invoc {
+ emit_feature_err(
+ &self.session.parse_sess,
+ "proc_macro_path_invoc",
+ path.span,
+ GateIssue::Language,
+ "paths of length greater than one in macro invocations are \
+ currently unstable",
+ );
+ }
+ }
let def = self.resolve_macro_to_def_inner(scope, path, kind, force);
if def != Err(Determinacy::Undetermined) {
// Do not report duplicated errors on every undetermined resolution.
FromEnv(..) |
WellFormedTy(..) |
FromEnvTy(..) |
+ Normalize(..) |
RegionOutlives(..) |
TypeOutlives(..) => self,
}
-> Lrc<&'tcx Slice<Clause<'tcx>>>
{
let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
- let item = tcx.hir.expect_item(node_id);
- match item.node {
- hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
- hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
+ let node = tcx.hir.find(node_id).unwrap();
+ match node {
+ hir::map::Node::NodeItem(item) => match item.node {
+ hir::ItemTrait(..) => program_clauses_for_trait(tcx, def_id),
+ hir::ItemImpl(..) => program_clauses_for_impl(tcx, def_id),
+ _ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
+ }
+ hir::map::Node::NodeImplItem(item) => {
+ if let hir::ImplItemKind::Type(..) = item.node {
+ program_clauses_for_associated_type_value(tcx, def_id)
+ } else {
+ Lrc::new(tcx.mk_clauses(iter::empty::<Clause>()))
+ }
+ },
// FIXME: other constructions e.g. traits, associated types...
_ => Lrc::new(tcx.mk_clauses(iter::empty::<Clause>())),
Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
}
+pub fn program_clauses_for_associated_type_value<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item_id: DefId,
+) -> Lrc<&'tcx Slice<Clause<'tcx>>> {
+ // Rule Normalize-From-Impl (see rustc guide)
+ //
+ // ```impl<P0..Pn> Trait<A1..An> for A0
+ // {
+ // type AssocType<Pn+1..Pm> where WC = T;
+ // }```
+ //
+ // ```
+ // forall<P0..Pm> {
+ // forall<Pn+1..Pm> {
+ // Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T) :-
+ // Implemented(A0: Trait<A1..An>) && WC
+ // }
+ // }
+ // ```
+
+ let item = tcx.associated_item(item_id);
+ debug_assert_eq!(item.kind, ty::AssociatedKind::Type);
+ let impl_id = if let ty::AssociatedItemContainer::ImplContainer(impl_id) = item.container {
+ impl_id
+ } else {
+ bug!()
+ };
+ // `A0 as Trait<A1..An>`
+ let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
+ // `T`
+ let ty = tcx.type_of(item_id);
+ // `Implemented(A0: Trait<A1..An>)`
+ let trait_implemented = ty::Binder::dummy(ty::TraitPredicate { trait_ref }.lower());
+ // `WC`
+ let item_where_clauses = tcx.predicates_of(item_id).predicates.lower();
+ // `Implemented(A0: Trait<A1..An>) && WC`
+ let mut where_clauses = vec![trait_implemented];
+ where_clauses.extend(item_where_clauses);
+ // `<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm>`
+ let projection_ty = ty::ProjectionTy::from_ref_and_name(tcx, trait_ref, item.name);
+ // `Normalize(<A0 as Trait<A1..An>>::AssocType<Pn+1..Pm> -> T)`
+ let normalize_goal = DomainGoal::Normalize(ty::ProjectionPredicate { projection_ty, ty });
+ // `Normalize(... -> T) :- ...`
+ let clause = ProgramClause {
+ goal: normalize_goal,
+ hypotheses: tcx.mk_goals(
+ where_clauses.into_iter().map(|wc| Goal::from_poly_domain_goal(wc, tcx))
+ ),
+ };
+ Lrc::new(tcx.mk_clauses(iter::once(Clause::ForAll(ty::Binder::dummy(clause)))))
+}
+
pub fn dump_program_clauses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
if !tcx.features().rustc_attrs {
return;
AllocatorTy::Ptr => args.push(i8p),
AllocatorTy::Usize => args.push(usize),
- AllocatorTy::Bang |
AllocatorTy::ResultPtr |
AllocatorTy::Unit => panic!("invalid allocator arg"),
}
}
let output = match method.output {
- AllocatorTy::Bang => None,
AllocatorTy::ResultPtr => Some(i8p),
AllocatorTy::Unit => None,
// rustdoc needs to be able to document functions that use all the features, so
// whitelist them all
Lrc::new(llvm_util::all_known_features()
- .map(|c| c.to_string())
+ .map(|(a, b)| (a.to_string(), b.map(|s| s.to_string())))
.collect())
} else {
Lrc::new(llvm_util::target_feature_whitelist(tcx.sess)
.iter()
- .map(|c| c.to_string())
+ .map(|&(a, b)| (a.to_string(), b.map(|s| s.to_string())))
.collect())
}
};
fn finalize(&mut self) -> Command {
self.cmd.arg("--threads");
+ self.cmd.arg("-z").arg("stack-size=1048576");
// FIXME we probably shouldn't pass this but instead pass an explicit
// whitelist of symbols we'll allow to be undefined. Unfortunately
// You can also find more info on why Windows is whitelisted here in:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
if !cx.sess().no_landing_pads() ||
- cx.sess().target.target.options.is_like_windows {
+ cx.sess().target.target.options.requires_uwtable {
attributes::emit_uwtable(lldecl, true);
}
use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor,
DICompositeType, DILexicalBlock, DIFlags};
+use rustc::hir::TransFnAttrFlags;
use rustc::hir::def::CtorKind;
use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
use rustc::ty::fold::TypeVisitor;
use std::fmt::Write;
use std::ptr;
use std::path::{Path, PathBuf};
-use syntax::{ast, attr};
+use syntax::ast;
use syntax::symbol::{Interner, InternedString, Symbol};
use syntax_pos::{self, Span, FileName};
}
let tcx = cx.tcx;
- let no_mangle = attr::contains_name(&tcx.get_attrs(def_id), "no_mangle");
+ let attrs = tcx.trans_fn_attrs(def_id);
+
+ if attrs.flags.contains(TransFnAttrFlags::NO_DEBUG) {
+ return;
+ }
+
+ let no_mangle = attrs.flags.contains(TransFnAttrFlags::NO_MANGLE);
// We may want to remove the namespace scope if we're in an extern block, see:
// https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952
let var_scope = get_namespace_for_item(cx, def_id);
- let span = cx.tcx.def_span(def_id);
+ let span = tcx.def_span(def_id);
let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP {
let loc = span_start(cx, span);
use llvm;
use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags};
+use rustc::hir::TransFnAttrFlags;
use rustc::hir::def_id::{DefId, CrateNum};
use rustc::ty::subst::Substs;
use common::CodegenCx;
use builder::Builder;
use monomorphize::Instance;
-use rustc::ty::{self, ParamEnv, Ty};
+use rustc::ty::{self, ParamEnv, Ty, InstanceDef};
use rustc::mir;
use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
return FunctionDebugContext::DebugInfoDisabled;
}
- for attr in instance.def.attrs(cx.tcx).iter() {
- if attr.check_name("no_debug") {
+ if let InstanceDef::Item(def_id) = instance.def {
+ if cx.tcx.trans_fn_attrs(def_id).flags.contains(TransFnAttrFlags::NO_DEBUG) {
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
}
- let containing_scope = get_containing_scope(cx, instance);
let span = mir.span;
// This can be the case for functions inlined from another crate
}
let def_id = instance.def_id();
+ let containing_scope = get_containing_scope(cx, instance);
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate);
#![feature(slice_sort_by_cached_key)]
#![feature(optin_builtin_traits)]
#![feature(inclusive_range_fields)]
-#![feature(underscore_lifetimes)]
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::CString;
+use syntax::feature_gate::UnstableFeatures;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
-const ARM_WHITELIST: &'static [&'static str] = &["neon", "v7", "vfp2", "vfp3", "vfp4"];
-
-const AARCH64_WHITELIST: &'static [&'static str] = &["fp", "neon", "sve", "crc", "crypto",
- "ras", "lse", "rdm", "fp16", "rcpc",
- "dotprod", "v8.1a", "v8.2a", "v8.3a"];
-
-const X86_WHITELIST: &'static [&'static str] = &["aes", "avx", "avx2", "avx512bw",
- "avx512cd", "avx512dq", "avx512er",
- "avx512f", "avx512ifma", "avx512pf",
- "avx512vbmi", "avx512vl", "avx512vpopcntdq",
- "bmi1", "bmi2", "fma", "fxsr",
- "lzcnt", "mmx", "pclmulqdq",
- "popcnt", "rdrand", "rdseed",
- "sha",
- "sse", "sse2", "sse3", "sse4.1",
- "sse4.2", "sse4a", "ssse3",
- "tbm", "xsave", "xsavec",
- "xsaveopt", "xsaves"];
-
-const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx", "hvx-double"];
-
-const POWERPC_WHITELIST: &'static [&'static str] = &["altivec",
- "power8-altivec", "power9-altivec",
- "power8-vector", "power9-vector",
- "vsx"];
-
-const MIPS_WHITELIST: &'static [&'static str] = &["fp64", "msa"];
+const ARM_WHITELIST: &[(&str, Option<&str>)] = &[
+ ("neon", Some("arm_target_feature")),
+ ("v7", Some("arm_target_feature")),
+ ("vfp2", Some("arm_target_feature")),
+ ("vfp3", Some("arm_target_feature")),
+ ("vfp4", Some("arm_target_feature")),
+];
+
+const AARCH64_WHITELIST: &[(&str, Option<&str>)] = &[
+ ("fp", Some("aarch64_target_feature")),
+ ("neon", Some("aarch64_target_feature")),
+ ("sve", Some("aarch64_target_feature")),
+ ("crc", Some("aarch64_target_feature")),
+ ("crypto", Some("aarch64_target_feature")),
+ ("ras", Some("aarch64_target_feature")),
+ ("lse", Some("aarch64_target_feature")),
+ ("rdm", Some("aarch64_target_feature")),
+ ("fp16", Some("aarch64_target_feature")),
+ ("rcpc", Some("aarch64_target_feature")),
+ ("dotprod", Some("aarch64_target_feature")),
+ ("v8.1a", Some("aarch64_target_feature")),
+ ("v8.2a", Some("aarch64_target_feature")),
+ ("v8.3a", Some("aarch64_target_feature")),
+];
+
+const X86_WHITELIST: &[(&str, Option<&str>)] = &[
+ ("aes", None),
+ ("avx", None),
+ ("avx2", None),
+ ("avx512bw", Some("avx512_target_feature")),
+ ("avx512cd", Some("avx512_target_feature")),
+ ("avx512dq", Some("avx512_target_feature")),
+ ("avx512er", Some("avx512_target_feature")),
+ ("avx512f", Some("avx512_target_feature")),
+ ("avx512ifma", Some("avx512_target_feature")),
+ ("avx512pf", Some("avx512_target_feature")),
+ ("avx512vbmi", Some("avx512_target_feature")),
+ ("avx512vl", Some("avx512_target_feature")),
+ ("avx512vpopcntdq", Some("avx512_target_feature")),
+ ("bmi1", None),
+ ("bmi2", None),
+ ("fma", None),
+ ("fxsr", None),
+ ("lzcnt", None),
+ ("mmx", Some("mmx_target_feature")),
+ ("pclmulqdq", None),
+ ("popcnt", None),
+ ("rdrand", None),
+ ("rdseed", None),
+ ("sha", None),
+ ("sse", None),
+ ("sse2", None),
+ ("sse3", None),
+ ("sse4.1", None),
+ ("sse4.2", None),
+ ("sse4a", Some("sse4a_target_feature")),
+ ("ssse3", None),
+ ("tbm", Some("tbm_target_feature")),
+ ("xsave", None),
+ ("xsavec", None),
+ ("xsaveopt", None),
+ ("xsaves", None),
+];
+
+const HEXAGON_WHITELIST: &[(&str, Option<&str>)] = &[
+ ("hvx", Some("hexagon_target_feature")),
+ ("hvx-double", Some("hexagon_target_feature")),
+];
+
+const POWERPC_WHITELIST: &[(&str, Option<&str>)] = &[
+ ("altivec", Some("powerpc_target_feature")),
+ ("power8-altivec", Some("powerpc_target_feature")),
+ ("power9-altivec", Some("powerpc_target_feature")),
+ ("power8-vector", Some("powerpc_target_feature")),
+ ("power9-vector", Some("powerpc_target_feature")),
+ ("vsx", Some("powerpc_target_feature")),
+];
+
+const MIPS_WHITELIST: &[(&str, Option<&str>)] = &[
+ ("fp64", Some("mips_target_feature")),
+ ("msa", Some("mips_target_feature")),
+];
/// When rustdoc is running, provide a list of all known features so that all their respective
/// primtives may be documented.
///
/// IMPORTANT: If you're adding another whitelist to the above lists, make sure to add it to this
/// iterator!
-pub fn all_known_features() -> impl Iterator<Item=&'static str> {
+pub fn all_known_features() -> impl Iterator<Item=(&'static str, Option<&'static str>)> {
ARM_WHITELIST.iter().cloned()
.chain(AARCH64_WHITELIST.iter().cloned())
.chain(X86_WHITELIST.iter().cloned())
let target_machine = create_target_machine(sess, true);
target_feature_whitelist(sess)
.iter()
+ .filter_map(|&(feature, gate)| {
+ if UnstableFeatures::from_environment().is_nightly_build() || gate.is_none() {
+ Some(feature)
+ } else {
+ None
+ }
+ })
.filter(|feature| {
let llvm_feature = to_llvm_feature(sess, feature);
let cstr = CString::new(llvm_feature).unwrap();
.map(|feature| Symbol::intern(feature)).collect()
}
-pub fn target_feature_whitelist(sess: &Session) -> &'static [&'static str] {
+pub fn target_feature_whitelist(sess: &Session)
+ -> &'static [(&'static str, Option<&'static str>)]
+{
match &*sess.target.target.arch {
"arm" => ARM_WHITELIST,
"aarch64" => AARCH64_WHITELIST,
//! which do not.
use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::control_flow_graph::dominators::Dominators;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::{self, Location, TerminatorKind};
use rustc::mir::visit::{Visitor, PlaceContext};
use type_of::LayoutLlvmExt;
use super::FunctionCx;
-pub fn memory_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector {
+pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector {
let mir = fx.mir;
let mut analyzer = LocalAnalyzer::new(fx);
// (e.g. structs) into an alloca unconditionally, just so
// that we don't have to deal with having two pathways
// (gep vs extractvalue etc).
- analyzer.mark_as_memory(mir::Local::new(index));
+ analyzer.not_ssa(mir::Local::new(index));
}
}
- analyzer.memory_locals
+ analyzer.non_ssa_locals
}
struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> {
fx: &'mir FunctionCx<'a, 'tcx>,
- memory_locals: BitVector,
- seen_assigned: BitVector
+ dominators: Dominators<mir::BasicBlock>,
+ non_ssa_locals: BitVector,
+ // The location of the first visited direct assignment to each
+ // local, or an invalid location (out of bounds `block` index).
+ first_assignment: IndexVec<mir::Local, Location>
}
impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> {
fn new(fx: &'mir FunctionCx<'a, 'tcx>) -> LocalAnalyzer<'mir, 'a, 'tcx> {
+ let invalid_location =
+ mir::BasicBlock::new(fx.mir.basic_blocks().len()).start_location();
let mut analyzer = LocalAnalyzer {
fx,
- memory_locals: BitVector::new(fx.mir.local_decls.len()),
- seen_assigned: BitVector::new(fx.mir.local_decls.len())
+ dominators: fx.mir.dominators(),
+ non_ssa_locals: BitVector::new(fx.mir.local_decls.len()),
+ first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
};
// Arguments get assigned to by means of the function being called
- for idx in 0..fx.mir.arg_count {
- analyzer.seen_assigned.insert(idx + 1);
+ for arg in fx.mir.args_iter() {
+ analyzer.first_assignment[arg] = mir::START_BLOCK.start_location();
}
analyzer
}
- fn mark_as_memory(&mut self, local: mir::Local) {
- debug!("marking {:?} as memory", local);
- self.memory_locals.insert(local.index());
+ fn first_assignment(&self, local: mir::Local) -> Option<Location> {
+ let location = self.first_assignment[local];
+ if location.block.index() < self.fx.mir.basic_blocks().len() {
+ Some(location)
+ } else {
+ None
+ }
}
- fn mark_assigned(&mut self, local: mir::Local) {
- if !self.seen_assigned.insert(local.index()) {
- self.mark_as_memory(local);
+ fn not_ssa(&mut self, local: mir::Local) {
+ debug!("marking {:?} as non-SSA", local);
+ self.non_ssa_locals.insert(local.index());
+ }
+
+ fn assign(&mut self, local: mir::Local, location: Location) {
+ if self.first_assignment(local).is_some() {
+ self.not_ssa(local);
+ } else {
+ self.first_assignment[local] = location;
}
}
}
debug!("visit_assign(block={:?}, place={:?}, rvalue={:?})", block, place, rvalue);
if let mir::Place::Local(index) = *place {
- self.mark_assigned(index);
+ self.assign(index, location);
if !self.fx.rvalue_creates_operand(rvalue) {
- self.mark_as_memory(index);
+ self.not_ssa(index);
}
} else {
self.visit_place(place, PlaceContext::Store, location);
if layout.is_llvm_immediate() || layout.is_llvm_scalar_pair() {
// Recurse with the same context, instead of `Projection`,
// potentially stopping at non-operand projections,
- // which would trigger `mark_as_memory` on locals.
+ // which would trigger `not_ssa` on locals.
self.visit_place(&proj.base, context, location);
return;
}
}
fn visit_local(&mut self,
- &index: &mir::Local,
+ &local: &mir::Local,
context: PlaceContext<'tcx>,
- _: Location) {
+ location: Location) {
match context {
PlaceContext::Call => {
- self.mark_assigned(index);
+ self.assign(local, location);
}
PlaceContext::StorageLive |
PlaceContext::StorageDead |
- PlaceContext::Validate |
+ PlaceContext::Validate => {}
+
PlaceContext::Copy |
- PlaceContext::Move => {}
+ PlaceContext::Move => {
+ // Reads from uninitialized variables (e.g. in dead code, after
+ // optimizations) require locals to be in (uninitialized) memory.
+ // NB: there can be uninitialized reads of a local visited after
+ // an assignment to that local, if they happen on disjoint paths.
+ let ssa_read = match self.first_assignment(local) {
+ Some(assignment_location) => {
+ assignment_location.dominates(location, &self.dominators)
+ }
+ None => false
+ };
+ if !ssa_read {
+ self.not_ssa(local);
+ }
+ }
PlaceContext::Inspect |
PlaceContext::Store |
PlaceContext::AsmOutput |
PlaceContext::Borrow { .. } |
PlaceContext::Projection(..) => {
- self.mark_as_memory(index);
+ self.not_ssa(local);
}
PlaceContext::Drop => {
- let ty = mir::Place::Local(index).ty(self.fx.mir, self.fx.cx.tcx);
+ let ty = mir::Place::Local(local).ty(self.fx.mir, self.fx.cx.tcx);
let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx));
// Only need the place if we're actually dropping it.
if self.fx.cx.type_needs_drop(ty) {
- self.mark_as_memory(index);
+ self.not_ssa(local);
}
}
}
},
};
- let memory_locals = analyze::memory_locals(&fx);
+ let memory_locals = analyze::non_ssa_locals(&fx);
// Allocate variable and temp allocas
fx.locals = {
self.mir_constant_to_miri_value(bx, constant)
.and_then(|c| OperandRef::from_const(bx, c, ty))
.unwrap_or_else(|err| {
- err.report(bx.tcx(), constant.span, "const operand");
+ match constant.literal {
+ mir::Literal::Promoted { .. } => {
+ // don't report errors inside promoteds, just warnings.
+ },
+ mir::Literal::Value { .. } => {
+ err.report(bx.tcx(), constant.span, "const operand")
+ },
+ }
// We've errored, so we don't have to produce working code.
let layout = bx.cx.layout_of(ty);
PlaceRef::new_sized(
use rustc::middle::cstore::MetadataLoader;
use rustc::dep_graph::DepGraph;
use rustc_back::target::Target;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxHashMap;
use rustc_mir::monomorphize::collector;
use link::{build_link_meta, out_filename};
::symbol_names::provide(providers);
providers.target_features_whitelist = |_tcx, _cnum| {
- Lrc::new(FxHashSet()) // Just a dummy
+ Lrc::new(FxHashMap()) // Just a dummy
};
}
fn provide_extern(&self, _providers: &mut Providers) {}
&format!("{}, producing the closest possible value",
msg),
cast_suggestion);
- err.warn("casting here will cause undefined behavior if the value is \
- finite but larger or smaller than the largest or smallest \
- finite value representable by `f32` (this is a bug and will be \
- fixed)");
}
true
}
ty::TyStr => {
let lang_def_id = lang_items.str_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.str_alloc_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::TySlice(_) => {
let lang_def_id = lang_items.slice_impl();
let lang_def_id = lang_items.slice_u8_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.slice_alloc_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.slice_u8_alloc_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
let lang_def_id = lang_items.const_ptr_impl();
ty::TyFloat(ast::FloatTy::F32) => {
let lang_def_id = lang_items.f32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.f32_runtime_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
ty::TyFloat(ast::FloatTy::F64) => {
let lang_def_id = lang_items.f64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
+
+ let lang_def_id = lang_items.f64_runtime_impl();
+ self.assemble_inherent_impl_for_primitive(lang_def_id);
}
_ => {}
}
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
- // Non-numerics get replaced with !, unconstrained ints with i32,
+ // Non-numerics get replaced with ! or () (depending on whether
+ // feature(never_type) is enabled, unconstrained ints with i32,
// unconstrained floats with f64.
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to TyError.
_ if self.is_tainted_by_errors() => self.tcx().types.err,
UnconstrainedInt => self.tcx.types.i32,
UnconstrainedFloat => self.tcx.types.f64,
- Neither if self.type_var_diverges(ty) => self.tcx.types.never,
+ Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(),
Neither => return false,
};
debug!("default_type_parameters: defaulting `{:?}` to `{:?}`", ty, fallback);
ty::TyChar => {
self.check_primitive_impl(def_id,
lang_items.char_impl(),
+ None,
"char",
"char",
item.span);
ty::TyStr => {
self.check_primitive_impl(def_id,
lang_items.str_impl(),
+ lang_items.str_alloc_impl(),
"str",
"str",
item.span);
ty::TySlice(slice_item) if slice_item == self.tcx.types.u8 => {
self.check_primitive_impl(def_id,
lang_items.slice_u8_impl(),
+ lang_items.slice_u8_alloc_impl(),
"slice_u8",
"[u8]",
item.span);
ty::TySlice(_) => {
self.check_primitive_impl(def_id,
lang_items.slice_impl(),
+ lang_items.slice_alloc_impl(),
"slice",
"[T]",
item.span);
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
self.check_primitive_impl(def_id,
lang_items.const_ptr_impl(),
+ None,
"const_ptr",
"*const T",
item.span);
ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
self.check_primitive_impl(def_id,
lang_items.mut_ptr_impl(),
+ None,
"mut_ptr",
"*mut T",
item.span);
ty::TyInt(ast::IntTy::I8) => {
self.check_primitive_impl(def_id,
lang_items.i8_impl(),
+ None,
"i8",
"i8",
item.span);
ty::TyInt(ast::IntTy::I16) => {
self.check_primitive_impl(def_id,
lang_items.i16_impl(),
+ None,
"i16",
"i16",
item.span);
ty::TyInt(ast::IntTy::I32) => {
self.check_primitive_impl(def_id,
lang_items.i32_impl(),
+ None,
"i32",
"i32",
item.span);
ty::TyInt(ast::IntTy::I64) => {
self.check_primitive_impl(def_id,
lang_items.i64_impl(),
+ None,
"i64",
"i64",
item.span);
ty::TyInt(ast::IntTy::I128) => {
self.check_primitive_impl(def_id,
lang_items.i128_impl(),
+ None,
"i128",
"i128",
item.span);
ty::TyInt(ast::IntTy::Isize) => {
self.check_primitive_impl(def_id,
lang_items.isize_impl(),
+ None,
"isize",
"isize",
item.span);
ty::TyUint(ast::UintTy::U8) => {
self.check_primitive_impl(def_id,
lang_items.u8_impl(),
+ None,
"u8",
"u8",
item.span);
ty::TyUint(ast::UintTy::U16) => {
self.check_primitive_impl(def_id,
lang_items.u16_impl(),
+ None,
"u16",
"u16",
item.span);
ty::TyUint(ast::UintTy::U32) => {
self.check_primitive_impl(def_id,
lang_items.u32_impl(),
+ None,
"u32",
"u32",
item.span);
ty::TyUint(ast::UintTy::U64) => {
self.check_primitive_impl(def_id,
lang_items.u64_impl(),
+ None,
"u64",
"u64",
item.span);
ty::TyUint(ast::UintTy::U128) => {
self.check_primitive_impl(def_id,
lang_items.u128_impl(),
+ None,
"u128",
"u128",
item.span);
ty::TyUint(ast::UintTy::Usize) => {
self.check_primitive_impl(def_id,
lang_items.usize_impl(),
+ None,
"usize",
"usize",
item.span);
ty::TyFloat(ast::FloatTy::F32) => {
self.check_primitive_impl(def_id,
lang_items.f32_impl(),
+ lang_items.f32_runtime_impl(),
"f32",
"f32",
item.span);
ty::TyFloat(ast::FloatTy::F64) => {
self.check_primitive_impl(def_id,
lang_items.f64_impl(),
+ lang_items.f64_runtime_impl(),
"f64",
"f64",
item.span);
fn check_primitive_impl(&self,
impl_def_id: DefId,
lang_def_id: Option<DefId>,
+ lang_def_id2: Option<DefId>,
lang: &str,
ty: &str,
span: Span) {
- match lang_def_id {
- Some(lang_def_id) if lang_def_id == impl_def_id => {
+ match (lang_def_id, lang_def_id2) {
+ (Some(lang_def_id), _) if lang_def_id == impl_def_id => {
+ // OK
+ }
+ (_, Some(lang_def_id)) if lang_def_id == impl_def_id => {
// OK
}
_ => {
use rustc::ty::util::IntTypeExt;
use rustc::ty::util::Discr;
use rustc::util::captures::Captures;
-use rustc::util::nodemap::{FxHashSet, FxHashMap};
+use rustc::util::nodemap::FxHashMap;
use syntax::{abi, ast};
use syntax::ast::MetaItemKind;
use syntax::attr::{InlineAttr, list_contains_name, mark_used};
use syntax::codemap::Spanned;
use syntax::symbol::{Symbol, keywords};
+use syntax::feature_gate;
use syntax_pos::{Span, DUMMY_SP};
use rustc::hir::{self, map as hir_map, TransFnAttrs, TransFnAttrFlags, Unsafety};
fn from_target_feature(
tcx: TyCtxt,
attr: &ast::Attribute,
- whitelist: &FxHashSet<String>,
+ whitelist: &FxHashMap<String, Option<String>>,
target_features: &mut Vec<Symbol>,
) {
let list = match attr.meta_item_list() {
return
}
};
-
+ let rust_features = tcx.features();
for item in list {
+ // Only `enable = ...` is accepted in the meta item list
if !item.check_name("enable") {
let msg = "#[target_feature(..)] only accepts sub-keys of `enable` \
currently";
tcx.sess.span_err(item.span, &msg);
continue
}
+
+ // Must be of the form `enable = "..."` ( a string)
let value = match item.value_str() {
- Some(list) => list,
+ Some(value) => value,
None => {
let msg = "#[target_feature] attribute must be of the form \
#[target_feature(enable = \"..\")]";
continue
}
};
- let value = value.as_str();
- for feature in value.split(',') {
- if whitelist.contains(feature) {
- target_features.push(Symbol::intern(feature));
- continue
- }
-
- let msg = format!("the feature named `{}` is not valid for \
- this target", feature);
- let mut err = tcx.sess.struct_span_err(item.span, &msg);
- if feature.starts_with("+") {
- let valid = whitelist.contains(&feature[1..]);
- if valid {
- err.help("consider removing the leading `+` in the feature name");
+ // We allow comma separation to enable multiple features
+ for feature in value.as_str().split(',') {
+
+ // Only allow whitelisted features per platform
+ let feature_gate = match whitelist.get(feature) {
+ Some(g) => g,
+ None => {
+ let msg = format!("the feature named `{}` is not valid for \
+ this target", feature);
+ let mut err = tcx.sess.struct_span_err(item.span, &msg);
+
+ if feature.starts_with("+") {
+ let valid = whitelist.contains_key(&feature[1..]);
+ if valid {
+ err.help("consider removing the leading `+` in the feature name");
+ }
+ }
+ err.emit();
+ continue
}
+ };
+
+ // Only allow features whose feature gates have been enabled
+ let allowed = match feature_gate.as_ref().map(|s| &**s) {
+ Some("arm_target_feature") => rust_features.arm_target_feature,
+ Some("aarch64_target_feature") => rust_features.aarch64_target_feature,
+ Some("hexagon_target_feature") => rust_features.hexagon_target_feature,
+ Some("powerpc_target_feature") => rust_features.powerpc_target_feature,
+ Some("mips_target_feature") => rust_features.mips_target_feature,
+ Some("avx512_target_feature") => rust_features.avx512_target_feature,
+ Some("mmx_target_feature") => rust_features.mmx_target_feature,
+ Some("sse4a_target_feature") => rust_features.sse4a_target_feature,
+ Some("tbm_target_feature") => rust_features.tbm_target_feature,
+ Some(name) => bug!("unknown target feature gate {}", name),
+ None => true,
+ };
+ if !allowed {
+ feature_gate::emit_feature_err(
+ &tcx.sess.parse_sess,
+ feature_gate.as_ref().unwrap(),
+ item.span,
+ feature_gate::GateIssue::Language,
+ &format!("the target feature `{}` is currently unstable",
+ feature),
+ );
+ continue
}
- err.emit();
+ target_features.push(Symbol::intern(feature));
}
}
}
trans_fn_attrs.flags |= TransFnAttrFlags::NO_MANGLE;
} else if attr.check_name("rustc_std_internal_symbol") {
trans_fn_attrs.flags |= TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
+ } else if attr.check_name("no_debug") {
+ trans_fn_attrs.flags |= TransFnAttrFlags::NO_DEBUG;
} else if attr.check_name("inline") {
trans_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
if attr.path != "inline" {
.emit();
}
} else if attr.check_name("target_feature") {
- // handle deprecated #[target_feature = "..."]
- if let Some(val) = attr.value_str() {
- for feat in val.as_str().split(",").map(|f| f.trim()) {
- if !feat.is_empty() && !feat.contains('\0') {
- trans_fn_attrs.target_features.push(Symbol::intern(feat));
- }
- }
- let msg = "#[target_feature = \"..\"] is deprecated and will \
- eventually be removed, use \
- #[target_feature(enable = \"..\")] instead";
- tcx.sess.span_warn(attr.span, &msg);
- continue
- }
-
if tcx.fn_sig(id).unsafety() == Unsafety::Normal {
let msg = "#[target_feature(..)] can only be applied to \
`unsafe` function";
The error happens on numeric literals:
```compile_fail,E0689
-2.0.powi(2);
+2.0.recip();
```
and on numeric bindings without an identified concrete type:
```compile_fail,E0689
let x = 2.0;
-x.powi(2); // same error as above
+x.recip(); // same error as above
```
Because of this, you must give the numeric literal or binding a type:
```
-let _ = 2.0_f32.powi(2);
+let _ = 2.0_f32.recip();
let x: f32 = 2.0;
-let _ = x.powi(2);
-let _ = (2.0 as f32).powi(2);
+let _ = x.recip();
+let _ = (2.0 as f32).recip();
```
"##,
#![feature(slice_patterns)]
#![feature(slice_sort_by_cached_key)]
#![feature(dyn_trait)]
-#![feature(underscore_lifetimes)]
+#![feature(never_type)]
#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
//! Support for inlining external documentation into the current AST.
-use std::collections::BTreeMap;
-use std::io;
use std::iter::once;
-use rustc_data_structures::sync::Lrc;
use syntax::ast;
use rustc::hir;
lang_items.u128_impl(),
lang_items.f32_impl(),
lang_items.f64_impl(),
+ lang_items.f32_runtime_impl(),
+ lang_items.f64_runtime_impl(),
lang_items.char_impl(),
lang_items.str_impl(),
lang_items.slice_impl(),
lang_items.slice_u8_impl(),
+ lang_items.str_alloc_impl(),
+ lang_items.slice_alloc_impl(),
+ lang_items.slice_u8_alloc_impl(),
lang_items.const_ptr_impl(),
lang_items.mut_ptr_impl(),
];
}
}
-struct InlinedConst {
- nested_bodies: Lrc<BTreeMap<hir::BodyId, hir::Body>>
-}
-
-impl hir::print::PpAnn for InlinedConst {
- fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested)
- -> io::Result<()> {
- if let hir::print::Nested::Body(body) = nested {
- state.print_expr(&self.nested_bodies[&body].value)
- } else {
- Ok(())
- }
- }
-}
-
pub fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
- let body = cx.tcx.extern_const_body(did).body;
- let inlined = InlinedConst {
- nested_bodies: cx.tcx.item_body_nested_bodies(did).nested_bodies
- };
- hir::print::to_string(&inlined, |s| s.print_expr(&body.value))
+ cx.tcx.rendered_const(did)
}
fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
Type,
}
+fn resolution_failure(cx: &DocContext, path_str: &str) {
+ cx.sess().warn(&format!("[{}] cannot be resolved, ignoring it...", path_str));
+}
+
impl Clean<Attributes> for [ast::Attribute] {
fn clean(&self, cx: &DocContext) -> Attributes {
let mut attrs = Attributes::from_ast(cx.sess().diagnostic(), self);
if let Ok(def) = resolve(cx, path_str, true) {
def
} else {
+ resolution_failure(cx, path_str);
// this could just be a normal link or a broken link
// we could potentially check if something is
// "intra-doc-link-like" and warn in that case
if let Ok(def) = resolve(cx, path_str, false) {
def
} else {
+ resolution_failure(cx, path_str);
// this could just be a normal link
continue;
}
} else if let Ok(value_def) = resolve(cx, path_str, true) {
value_def
} else {
+ resolution_failure(cx, path_str);
// this could just be a normal link
continue;
}
if let Some(def) = macro_resolve(cx, path_str) {
(def, None)
} else {
+ resolution_failure(cx, path_str);
continue
}
}
use rustc::ty::{self, TyCtxt, AllArenas};
use rustc::hir::map as hir_map;
use rustc::lint;
+use rustc::session::config::ErrorOutputType;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_resolve as resolve;
use rustc_metadata::creader::CrateLoader;
use syntax::codemap;
use syntax::edition::Edition;
use syntax::feature_gate::UnstableFeatures;
+use syntax::json::JsonEmitter;
use errors;
-use errors::emitter::ColorConfig;
+use errors::emitter::{Emitter, EmitterWriter};
use std::cell::{RefCell, Cell};
use std::mem;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
use std::rc::Rc;
use std::path::PathBuf;
}
}
-
pub fn run_core(search_paths: SearchPaths,
cfgs: Vec<String>,
externs: config::Externs,
crate_name: Option<String>,
force_unstable_if_unmarked: bool,
edition: Edition,
- cg: CodegenOptions) -> (clean::Crate, RenderInfo)
+ cg: CodegenOptions,
+ error_format: ErrorOutputType) -> (clean::Crate, RenderInfo)
{
// Parse, resolve, and typecheck the given crate.
let warning_lint = lint::builtin::WARNINGS.name_lower();
let host_triple = TargetTriple::from_triple(config::host_triple());
+ // plays with error output here!
let sessopts = config::Options {
maybe_sysroot,
search_paths,
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions {
force_unstable_if_unmarked,
- edition,
..config::basic_debugging_options()
},
+ error_format,
+ edition,
..config::basic_options().clone()
};
let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
- let diagnostic_handler = errors::Handler::with_tty_emitter(ColorConfig::Auto,
- true,
- false,
- Some(codemap.clone()));
+ let emitter: Box<dyn Emitter + sync::Send> = match error_format {
+ ErrorOutputType::HumanReadable(color_config) => Box::new(
+ EmitterWriter::stderr(
+ color_config,
+ Some(codemap.clone()),
+ false,
+ sessopts.debugging_opts.teach,
+ ).ui_testing(sessopts.debugging_opts.ui_testing)
+ ),
+ ErrorOutputType::Json(pretty) => Box::new(
+ JsonEmitter::stderr(
+ None,
+ codemap.clone(),
+ pretty,
+ sessopts.debugging_opts.approximate_suggestions,
+ ).ui_testing(sessopts.debugging_opts.ui_testing)
+ ),
+ ErrorOutputType::Short(color_config) => Box::new(
+ EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
+ ),
+ };
+
+ let diagnostic_handler = errors::Handler::with_emitter_and_flags(
+ emitter,
+ errors::HandlerFlags {
+ can_emit_warnings: true,
+ treat_err_as_bug: false,
+ external_macro_backtrace: false,
+ ..Default::default()
+ },
+ );
let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, codemap,
/// discriminants. JavaScript then is used to decode them into the original value.
/// Consequently, every change to this type should be synchronized to
/// the `itemTypes` mapping table in `static/main.js`.
-#[derive(Copy, PartialEq, Clone)]
+#[derive(Copy, PartialEq, Clone, Debug)]
pub enum ItemType {
Module = 0,
ExternCrate = 1,
-> io::Result<()>
{
write!(dst,
-r##"<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <meta name="generator" content="rustdoc">
- <meta name="description" content="{description}">
- <meta name="keywords" content="{keywords}">
-
- <title>{title}</title>
-
- <link rel="stylesheet" type="text/css" href="{root_path}normalize{suffix}.css">
- <link rel="stylesheet" type="text/css" href="{root_path}rustdoc{suffix}.css"
- id="mainThemeStyle">
- {themes}
- <link rel="stylesheet" type="text/css" href="{root_path}dark{suffix}.css">
- <link rel="stylesheet" type="text/css" href="{root_path}light{suffix}.css" id="themeStyle">
- <script src="{root_path}storage{suffix}.js"></script>
- {css_extension}
-
- {favicon}
- {in_header}
-</head>
-<body class="rustdoc {css_class}">
- <!--[if lte IE 8]>
- <div class="warning">
- This old browser is unsupported and will most likely display funky
- things.
- </div>
- <![endif]-->
-
- {before_content}
-
- <nav class="sidebar">
- <div class="sidebar-menu">☰</div>
- {logo}
- {sidebar}
- </nav>
-
- <div class="theme-picker">
- <button id="theme-picker" aria-label="Pick another theme!">
- <img src="{root_path}brush{suffix}.svg" width="18" alt="Pick another theme!">
- </button>
- <div id="theme-choices"></div>
- </div>
- <script src="{root_path}theme{suffix}.js"></script>
- <nav class="sub">
- <form class="search-form js-only">
- <div class="search-container">
- <input class="search-input" name="search"
- autocomplete="off"
- placeholder="Click or press ‘S’ to search, ‘?’ for more options…"
- type="search">
- </div>
- </form>
- </nav>
-
- <section id='main' class="content">{content}</section>
- <section id='search' class="content hidden"></section>
-
- <section class="footer"></section>
-
- <aside id="help" class="hidden">
- <div>
- <h1 class="hidden">Help</h1>
-
- <div class="shortcuts">
- <h2>Keyboard Shortcuts</h2>
-
- <dl>
- <dt><kbd>?</kbd></dt>
- <dd>Show this help dialog</dd>
- <dt><kbd>S</kbd></dt>
- <dd>Focus the search field</dd>
- <dt><kbd>↑</kbd></dt>
- <dd>Move up in search results</dd>
- <dt><kbd>↓</kbd></dt>
- <dd>Move down in search results</dd>
- <dt><kbd>↹</kbd></dt>
- <dd>Switch tab</dd>
- <dt><kbd>⏎</kbd></dt>
- <dd>Go to active search result</dd>
- <dt><kbd>+</kbd></dt>
- <dd>Expand all sections</dd>
- <dt><kbd>-</kbd></dt>
- <dd>Collapse all sections</dd>
- </dl>
- </div>
-
- <div class="infos">
- <h2>Search Tricks</h2>
-
- <p>
- Prefix searches with a type followed by a colon (e.g.
- <code>fn:</code>) to restrict the search to a given type.
- </p>
-
- <p>
- Accepted types are: <code>fn</code>, <code>mod</code>,
- <code>struct</code>, <code>enum</code>,
- <code>trait</code>, <code>type</code>, <code>macro</code>,
- and <code>const</code>.
- </p>
-
- <p>
- Search functions by type signature (e.g.
- <code>vec -> usize</code> or <code>* -> vec</code>)
- </p>
- </div>
- </div>
- </aside>
-
- {after_content}
-
- <script>
- window.rootPath = "{root_path}";
- window.currentCrate = "{krate}";
- </script>
- <script src="{root_path}main{suffix}.js"></script>
- <script defer src="{root_path}search-index.js"></script>
-</body>
-</html>"##,
+"<!DOCTYPE html>\
+<html lang=\"en\">\
+<head>\
+ <meta charset=\"utf-8\">\
+ <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
+ <meta name=\"generator\" content=\"rustdoc\">\
+ <meta name=\"description\" content=\"{description}\">\
+ <meta name=\"keywords\" content=\"{keywords}\">\
+ <title>{title}</title>\
+ <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}normalize{suffix}.css\">\
+ <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}rustdoc{suffix}.css\" \
+ id=\"mainThemeStyle\">\
+ {themes}\
+ <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}dark{suffix}.css\">\
+ <link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}light{suffix}.css\" \
+ id=\"themeStyle\">\
+ <script src=\"{root_path}storage{suffix}.js\"></script>\
+ {css_extension}\
+ {favicon}\
+ {in_header}\
+</head>\
+<body class=\"rustdoc {css_class}\">\
+ <!--[if lte IE 8]>\
+ <div class=\"warning\">\
+ This old browser is unsupported and will most likely display funky \
+ things.\
+ </div>\
+ <![endif]-->\
+ {before_content}\
+ <nav class=\"sidebar\">\
+ <div class=\"sidebar-menu\">☰</div>\
+ {logo}\
+ {sidebar}\
+ </nav>\
+ <div class=\"theme-picker\">\
+ <button id=\"theme-picker\" aria-label=\"Pick another theme!\">\
+ <img src=\"{root_path}brush{suffix}.svg\" width=\"18\" alt=\"Pick another theme!\">\
+ </button>\
+ <div id=\"theme-choices\"></div>\
+ </div>\
+ <script src=\"{root_path}theme{suffix}.js\"></script>\
+ <nav class=\"sub\">\
+ <form class=\"search-form js-only\">\
+ <div class=\"search-container\">\
+ <input class=\"search-input\" name=\"search\" \
+ autocomplete=\"off\" \
+ placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
+ type=\"search\">\
+ <a id=\"settings-menu\" href=\"{root_path}settings.html\">\
+ <img src=\"{root_path}wheel{suffix}.svg\" width=\"18\" alt=\"Change settings\">\
+ </a>\
+ </div>\
+ </form>\
+ </nav>\
+ <section id=\"main\" class=\"content\">{content}</section>\
+ <section id=\"search\" class=\"content hidden\"></section>\
+ <section class=\"footer\"></section>\
+ <aside id=\"help\" class=\"hidden\">\
+ <div>\
+ <h1 class=\"hidden\">Help</h1>\
+ <div class=\"shortcuts\">\
+ <h2>Keyboard Shortcuts</h2>\
+ <dl>\
+ <dt><kbd>?</kbd></dt>\
+ <dd>Show this help dialog</dd>\
+ <dt><kbd>S</kbd></dt>\
+ <dd>Focus the search field</dd>\
+ <dt><kbd>↑</kbd></dt>\
+ <dd>Move up in search results</dd>\
+ <dt><kbd>↓</kbd></dt>\
+ <dd>Move down in search results</dd>\
+ <dt><kbd>↹</kbd></dt>\
+ <dd>Switch tab</dd>\
+ <dt><kbd>⏎</kbd></dt>\
+ <dd>Go to active search result</dd>\
+ <dt><kbd>+</kbd></dt>\
+ <dd>Expand all sections</dd>\
+ <dt><kbd>-</kbd></dt>\
+ <dd>Collapse all sections</dd>\
+ </dl>\
+ </div>\
+ <div class=\"infos\">\
+ <h2>Search Tricks</h2>\
+ <p>\
+ Prefix searches with a type followed by a colon (e.g. \
+ <code>fn:</code>) to restrict the search to a given type.\
+ </p>\
+ <p>\
+ Accepted types are: <code>fn</code>, <code>mod</code>, \
+ <code>struct</code>, <code>enum</code>, \
+ <code>trait</code>, <code>type</code>, <code>macro</code>, \
+ and <code>const</code>.\
+ </p>\
+ <p>\
+ Search functions by type signature (e.g. \
+ <code>vec -> usize</code> or <code>* -> vec</code>)\
+ </p>\
+ <p>\
+ Search multiple things at once by splitting your query with comma (e.g. \
+ <code>str,u8</code> or <code>String,struct:Vec,test</code>)\
+ </p>\
+ </div>\
+ </div>\
+ </aside>\
+ {after_content}\
+ <script>\
+ window.rootPath = \"{root_path}\";\
+ window.currentCrate = \"{krate}\";\
+ </script>\
+ <script src=\"{root_path}main{suffix}.js\"></script>\
+ <script defer src=\"{root_path}search-index.js\"></script>\
+ <script defer src=\"{root_path}aliases.js\"></script>\
+</body>\
+</html>",
css_extension = if css_file_extension {
format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">",
root_path = page.root_path,
themes = themes.iter()
.filter_map(|t| t.file_stem())
.filter_map(|t| t.to_str())
- .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}">"#,
+ .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}{}.css">"#,
page.root_path,
- t.replace(".css", &format!("{}.css", page.resource_suffix))))
+ t,
+ page.resource_suffix))
.collect::<String>(),
suffix=page.resource_suffix,
)
/// This describes the layout of each page, and is not modified after
/// creation of the context (contains info like the favicon and added html).
pub layout: layout::Layout,
- /// This flag indicates whether [src] links should be generated or not. If
+ /// This flag indicates whether `[src]` links should be generated or not. If
/// the source files are present in the html rendering, then this will be
/// `true`.
pub include_sources: bool,
// yet when its implementation methods are being indexed. Caches such methods
// and their parent id here and indexes them at the end of crate parsing.
orphan_impl_items: Vec<(DefId, clean::Item)>,
+
+ /// Aliases added through `#[doc(alias = "...")]`. Since a few items can have the same alias,
+ /// we need the alias element to have an array of items.
+ aliases: FxHashMap<String, Vec<IndexItem>>,
}
/// Temporary storage for data obtained during `RustdocVisitor::clean()`.
/// Struct representing one entry in the JS search index. These are all emitted
/// by hand to a large JS file at the end of cache-creation.
+#[derive(Debug)]
struct IndexItem {
ty: ItemType,
name: String,
}
/// A type used for the search index.
+#[derive(Debug)]
struct Type {
name: Option<String>,
generics: Option<Vec<String>>,
}
/// Full type of functions/methods in the search index.
+#[derive(Debug)]
struct IndexItemFunctionType {
inputs: Vec<Type>,
- output: Option<Type>
+ output: Option<Type>,
}
impl ToJson for IndexItemFunctionType {
owned_box_did,
masked_crates: mem::replace(&mut krate.masked_crates, FxHashSet()),
typarams: external_typarams,
+ aliases: FxHashMap(),
};
// Cache where all our extern crates are located
write(cx.dst.join(&format!("rustdoc{}.css", cx.shared.resource_suffix)),
include_bytes!("static/rustdoc.css"))?;
+ write(cx.dst.join(&format!("settings{}.css", cx.shared.resource_suffix)),
+ include_bytes!("static/settings.css"))?;
// To avoid "light.css" to be overwritten, we'll first run over the received themes and only
// then we'll run over the "official" styles.
write(cx.dst.join(&format!("brush{}.svg", cx.shared.resource_suffix)),
include_bytes!("static/brush.svg"))?;
+ write(cx.dst.join(&format!("wheel{}.svg", cx.shared.resource_suffix)),
+ include_bytes!("static/wheel.svg"))?;
write(cx.dst.join(&format!("light{}.css", cx.shared.resource_suffix)),
include_bytes!("static/themes/light.css"))?;
themes.insert("light".to_owned());
switchTheme(currentTheme, mainTheme, item);
}};
themes.appendChild(but);
-}});
-"#,
+}});"#,
themes.iter()
.map(|s| format!("\"{}\"", s))
.collect::<Vec<String>>()
write(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
include_bytes!("static/main.js"))?;
+ write(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
+ include_bytes!("static/settings.js"))?;
{
let mut data = format!("var resourcesSuffix = \"{}\";\n",
write(cx.dst.join("COPYRIGHT.txt"),
include_bytes!("static/COPYRIGHT.txt"))?;
- fn collect(path: &Path, krate: &str,
- key: &str) -> io::Result<Vec<String>> {
+ fn collect(path: &Path, krate: &str, key: &str) -> io::Result<Vec<String>> {
let mut ret = Vec::new();
if path.exists() {
for line in BufReader::new(File::open(path)?).lines() {
Ok(ret)
}
+ fn show_item(item: &IndexItem, krate: &str) -> String {
+ format!("{{'crate':'{}','ty':{},'name':'{}','path':'{}'{}}}",
+ krate, item.ty as usize, item.name, item.path,
+ if let Some(p) = item.parent_idx {
+ format!(",'parent':{}", p)
+ } else {
+ String::new()
+ })
+ }
+
+ let dst = cx.dst.join("aliases.js");
+ {
+ let mut all_aliases = try_err!(collect(&dst, &krate.name, "ALIASES"), &dst);
+ let mut w = try_err!(File::create(&dst), &dst);
+ let mut output = String::with_capacity(100);
+ for (alias, items) in &cache.aliases {
+ if items.is_empty() {
+ continue
+ }
+ output.push_str(&format!("\"{}\":[{}],",
+ alias,
+ items.iter()
+ .map(|v| show_item(v, &krate.name))
+ .collect::<Vec<_>>()
+ .join(",")));
+ }
+ all_aliases.push(format!("ALIASES['{}'] = {{{}}};", krate.name, output));
+ all_aliases.sort();
+ try_err!(writeln!(&mut w, "var ALIASES = {{}};"), &dst);
+ for aliases in &all_aliases {
+ try_err!(writeln!(&mut w, "{}", aliases), &dst);
+ }
+ }
+
// Update the search index
let dst = cx.dst.join("search-index.js");
let mut all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
// `public_items` map, so we can skip inserting into the
// paths map if there was already an entry present and we're
// not a public item.
- if
- !self.paths.contains_key(&item.def_id) ||
- self.access_levels.is_public(item.def_id)
+ if !self.paths.contains_key(&item.def_id) ||
+ self.access_levels.is_public(item.def_id)
{
self.paths.insert(item.def_id,
(self.stack.clone(), item.type_()));
}
+ self.add_aliases(&item);
}
// Link variants to their parent enum because pages aren't emitted
// for each variant.
}
clean::PrimitiveItem(..) if item.visibility.is_some() => {
+ self.add_aliases(&item);
self.paths.insert(item.def_id, (self.stack.clone(),
item.type_()));
}
}
}
}
+
+ fn add_aliases(&mut self, item: &clean::Item) {
+ if item.def_id.index == CRATE_DEF_INDEX {
+ return
+ }
+ if let Some(ref item_name) = item.name {
+ let path = self.paths.get(&item.def_id)
+ .map(|p| p.0.join("::").to_string())
+ .unwrap_or("std".to_owned());
+ for alias in item.attrs.lists("doc")
+ .filter(|a| a.check_name("alias"))
+ .filter_map(|a| a.value_str()
+ .map(|s| s.to_string().replace("\"", "")))
+ .filter(|v| !v.is_empty())
+ .collect::<FxHashSet<_>>()
+ .into_iter() {
+ self.aliases.entry(alias)
+ .or_insert(Vec::with_capacity(1))
+ .push(IndexItem {
+ ty: item.type_(),
+ name: item_name.to_string(),
+ path: path.clone(),
+ desc: String::new(),
+ parent: None,
+ parent_idx: None,
+ search_type: get_index_search_type(&item),
+ });
+ }
+ }
+ }
}
#[derive(Debug, Eq, PartialEq, Hash)]
}
}
+#[derive(Debug)]
+struct Settings<'a> {
+ // (id, explanation, default value)
+ settings: Vec<(&'static str, &'static str, bool)>,
+ root_path: &'a str,
+ suffix: &'a str,
+}
+
+impl<'a> Settings<'a> {
+ pub fn new(root_path: &'a str, suffix: &'a str) -> Settings<'a> {
+ Settings {
+ settings: vec![
+ ("item-declarations", "Auto-hide item declarations.", true),
+ ("item-attributes", "Auto-hide item attributes.", true),
+ ],
+ root_path,
+ suffix,
+ }
+ }
+}
+
+impl<'a> fmt::Display for Settings<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f,
+"<h1 class='fqn'>\
+ <span class='in-band'>Rustdoc settings</span>\
+</h1>\
+<div class='settings'>{}</div>\
+<script src='{}settings{}.js'></script>",
+ self.settings.iter()
+ .map(|(id, text, enabled)| {
+ format!("<div class='setting-line'>\
+ <label class='toggle'>\
+ <input type='checkbox' id='{}' {}>\
+ <span class='slider'></span>\
+ </label>\
+ <div>{}</div>\
+ </div>", id, if *enabled { " checked" } else { "" }, text)
+ })
+ .collect::<String>(),
+ self.root_path,
+ self.suffix)
+ }
+}
+
impl Context {
/// String representation of how to get back to the root path of the 'doc/'
/// folder in terms of a relative URL.
};
let final_file = self.dst.join(&krate.name)
.join("all.html");
+ let settings_file = self.dst.join("settings.html");
+
let crate_name = krate.name.clone();
item.name = Some(krate.name);
if !root_path.ends_with('/') {
root_path.push('/');
}
- let page = layout::Page {
+ let mut page = layout::Page {
title: "List of all items in this crate",
css_class: "mod",
root_path: "../",
self.shared.css_file_extension.is_some(),
&self.shared.themes),
&final_file);
+
+ // Generating settings page.
+ let settings = Settings::new("./", &self.shared.resource_suffix);
+ page.title = "Rustdoc settings";
+ page.description = "Settings of Rustdoc";
+ page.root_path = "./";
+
+ let mut w = BufWriter::new(try_err!(File::create(&settings_file), &settings_file));
+ let mut themes = self.shared.themes.clone();
+ let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>";
+ themes.push(PathBuf::from("settings.css"));
+ let mut layout = self.shared.layout.clone();
+ layout.krate = String::new();
+ layout.logo = String::new();
+ layout.favicon = String::new();
+ try_err!(layout::render(&mut w, &layout,
+ &page, &sidebar, &settings,
+ self.shared.css_file_extension.is_some(),
+ &themes),
+ &settings_file);
+
Ok(())
}
let mut dst = try_err!(File::create(&joint_dst), &joint_dst);
try_err!(dst.write_all(&buf), &joint_dst);
- all.append(full_path(self, &item), &item_type);
+ if !self.render_redirect_pages {
+ all.append(full_path(self, &item), &item_type);
+ }
// Redirect from a sane URL using the namespace to Rustdoc's
// URL for the page.
let redir_name = format!("{}.{}.html", name, item_type.name_space());
return false;
}
var end = start + className.length;
- if (end < elemClass.length && elemClass[end] !== ' ') {
- return false;
- }
- return true;
+ return !(end < elemClass.length && elemClass[end] !== ' ');
}
if (start > 0 && elemClass[start - 1] !== ' ') {
return false;
}
var end = start + className.length;
- if (end < elemClass.length && elemClass[end] !== ' ') {
- return false;
- }
- return true;
+ return !(end < elemClass.length && elemClass[end] !== ' ');
}
return false;
}
} else if (ev.target.tagName === 'SPAN' && hasClass(ev.target.parentNode, 'line-numbers')) {
var prev_id = 0;
- var set_fragment = function (name) {
+ var set_fragment = function(name) {
if (browserSupportsHistoryApi()) {
history.replaceState(null, null, '#' + name);
window.hashchange();
query.search = val;
// searching by type
} else if (val.search("->") > -1) {
- var trimmer = function (s) { return s.trim(); };
+ var trimmer = function(s) { return s.trim(); };
var parts = val.split("->").map(trimmer);
var input = parts[0];
// sort inputs so that order does not matter
}
}
- return {
+ var ret = {
'in_args': sortResults(results_in_args, true),
'returned': sortResults(results_returned, true),
'others': sortResults(results),
};
+ if (ALIASES[window.currentCrate][query.raw]) {
+ var aliases = ALIASES[window.currentCrate][query.raw];
+ for (var i = 0; i < aliases.length; ++i) {
+ ret['others'].unshift(aliases[i]);
+ if (ret['others'].length > MAX_RESULTS) {
+ ret['others'].pop();
+ }
+ }
+ }
+ return ret;
}
/**
array.forEach(function(item) {
var name, type, href, displayPath;
- if (shown.indexOf(item) !== -1) {
+ var id_ty = item.ty + item.path + item.name;
+ if (shown.indexOf(id_ty) !== -1) {
return;
}
- shown.push(item);
+ console.log(item);
+ shown.push(id_ty);
name = item.name;
type = itemTypes[item.ty];
printTab(currentTab);
}
+ function execSearch(query, searchWords) {
+ var queries = query.raw.split(",");
+ var results = {
+ 'in_args': [],
+ 'returned': [],
+ 'others': [],
+ };
+
+ for (var i = 0; i < queries.length; ++i) {
+ var query = queries[i].trim();
+ if (query.length !== 0) {
+ var tmp = execQuery(getQuery(query), searchWords);
+
+ results['in_args'].push(tmp['in_args']);
+ results['returned'].push(tmp['returned']);
+ results['others'].push(tmp['others']);
+ }
+ }
+ if (queries.length > 1) {
+ function getSmallest(arrays, positions) {
+ var start = null;
+
+ for (var it = 0; it < positions.length; ++it) {
+ if (arrays[it].length > positions[it] &&
+ (start === null || start > arrays[it][positions[it]].lev)) {
+ start = arrays[it][positions[it]].lev;
+ }
+ }
+ return start;
+ }
+
+ function mergeArrays(arrays) {
+ var ret = [];
+ var positions = [];
+
+ for (var x = 0; x < arrays.length; ++x) {
+ positions.push(0);
+ }
+ while (ret.length < MAX_RESULTS) {
+ var smallest = getSmallest(arrays, positions);
+ if (smallest === null) {
+ break;
+ }
+ for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) {
+ if (arrays[x].length > positions[x] &&
+ arrays[x][positions[x]].lev === smallest) {
+ ret.push(arrays[x][positions[x]]);
+ positions[x] += 1;
+ }
+ }
+ }
+ return ret;
+ }
+
+ return {
+ 'in_args': mergeArrays(results['in_args']),
+ 'returned': mergeArrays(results['returned']),
+ 'others': mergeArrays(results['others']),
+ };
+ } else {
+ return {
+ 'in_args': results['in_args'][0],
+ 'returned': results['returned'][0],
+ 'others': results['others'][0],
+ };
+ }
+ }
+
function search(e) {
- var query,
- obj, i, len,
- results = {"in_args": [], "returned": [], "others": []},
- resultIndex;
var params = getQueryStringParams();
+ var query = getQuery(document.getElementsByClassName('search-input')[0].value.trim());
- query = getQuery(document.getElementsByClassName('search-input')[0].value);
if (e) {
e.preventDefault();
}
}
}
- results = execQuery(query, index);
- showResults(results);
+ showResults(execSearch(query, index));
}
function buildIndex(rawSearchIndex) {
startSearch();
// Draw a convenient sidebar of known crates if we have a listing
- if (rootPath === '../') {
+ if (rootPath === '../' || rootPath === "./") {
var sidebar = document.getElementsByClassName('sidebar-elems')[0];
if (sidebar) {
var div = document.createElement('div');
crates.sort();
for (var i = 0; i < crates.length; ++i) {
var klass = 'crate';
- if (crates[i] === window.currentCrate) {
+ if (rootPath !== "./" && crates[i] === window.currentCrate) {
klass += ' current';
}
var link = document.createElement('a');
- link.href = '../' + crates[i] + '/index.html';
+ link.href = rootPath + crates[i] + '/index.html';
link.title = rawSearchIndex[crates[i]].doc;
link.className = klass;
link.textContent = crates[i];
otherMessage = ' Show type declaration';
}
e.parentNode.insertBefore(createToggle(otherMessage), e);
- if (otherMessage) {
+ if (otherMessage && getCurrentValue('rustdoc-item-declarations') !== "false") {
collapseDocs(e.previousSibling.childNodes[0], "toggle");
}
}
onEach(document.getElementById('main').getElementsByTagName('pre'), function(e) {
onEach(e.getElementsByClassName('attributes'), function(i_e) {
i_e.parentNode.insertBefore(createToggleWrapper(), i_e);
- collapseDocs(i_e.previousSibling.childNodes[0], "toggle");
+ if (getCurrentValue("rustdoc-item-attributes") !== "false") {
+ collapseDocs(i_e.previousSibling.childNodes[0], "toggle");
+ }
});
});
.block a.current.crate { font-weight: 500; }
+.search-container {
+ position: relative;
+}
+.search-container > .top-button {
+ position: absolute;
+ right: 0;
+ top: 10px;
+}
.search-input {
- width: 100%;
+ width: calc(100% - 34px);
/* Override Normalize.css: we have margins and do
not want to overflow - the `moz` attribute is necessary
until Firefox 29, too early to drop at this point */
outline: none;
}
-#theme-picker {
+#settings-menu {
+ position: absolute;
+ right: 0;
+ top: 10px;
+ outline: none;
+}
+
+#theme-picker, #settings-menu {
padding: 4px;
width: 27px;
height: 29px;
--- /dev/null
+/**
+ * Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+ * file at the top-level directory of this distribution and at
+ * http://rust-lang.org/COPYRIGHT.
+ *
+ * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+ * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+ * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+ * option. This file may not be copied, modified, or distributed
+ * except according to those terms.
+ */
+
+.setting-line {
+ padding: 5px;
+}
+
+.setting-line > div {
+ max-width: calc(100% - 74px);
+ display: inline-block;
+ vertical-align: top;
+ font-size: 17px;
+ padding-top: 2px;
+}
+
+.toggle {
+ position: relative;
+ display: inline-block;
+ width: 45px;
+ height: 27px;
+ margin-right: 20px;
+}
+
+.toggle input {
+ display: none;
+}
+
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: #ccc;
+ -webkit-transition: .3s;
+ transition: .3s;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 19px;
+ width: 19px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: .3s;
+ transition: .3s;
+}
+
+input:checked + .slider {
+ background-color: #2196F3;
+}
+
+input:focus + .slider {
+ box-shadow: 0 0 1px #2196F3;
+}
+
+input:checked + .slider:before {
+ -webkit-transform: translateX(19px);
+ -ms-transform: translateX(19px);
+ transform: translateX(19px);
+}
\ No newline at end of file
--- /dev/null
+/*!
+ * Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+ * file at the top-level directory of this distribution and at
+ * http://rust-lang.org/COPYRIGHT.
+ *
+ * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+ * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+ * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+ * option. This file may not be copied, modified, or distributed
+ * except according to those terms.
+ */
+
+(function () {
+ function changeSetting(settingName, isEnabled) {
+ updateLocalStorage('rustdoc-' + settingName, isEnabled);
+ }
+
+ function getSettingValue(settingName) {
+ return getCurrentValue('rustdoc-' + settingName);
+ }
+
+ function setEvents() {
+ var elems = document.getElementsByClassName("slider");
+ if (!elems || elems.length === 0) {
+ return;
+ }
+ for (var i = 0; i < elems.length; ++i) {
+ var toggle = elems[i].previousElementSibling;
+ var settingId = toggle.id;
+ var settingValue = getSettingValue(settingId);
+ if (settingValue !== null) {
+ toggle.checked = settingValue === "true";
+ }
+ toggle.onchange = function() {
+ changeSetting(this.id, this.checked);
+ };
+ }
+ }
+
+ setEvents();
+})();
box-shadow-color: #c6cbd1;
}
-#theme-picker {
+#theme-picker, #settings-menu {
border-color: #e0e0e0;
background: #f0f0f0;
}
-#theme-picker:hover, #theme-picker:focus {
+#theme-picker:hover, #theme-picker:focus,
+#settings-menu:hover, #settings-menu:focus {
border-color: #ffb900;
}
box-shadow-color: #c6cbd1;
}
-#theme-picker {
+#theme-picker, #settings-menu {
border-color: #e0e0e0;
background-color: #fff;
}
-#theme-picker:hover, #theme-picker:focus {
+#theme-picker:hover, #theme-picker:focus,
+#settings-menu:hover, #settings-menu:focus {
border-color: #717171;
}
--- /dev/null
+<?xml version="1.0" ?><!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'><svg enable-background="new 0 0 27.434 29.5" height="29.5px" id="Capa_1" version="1.1" viewBox="0 0 27.434 29.5" width="27.434px" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g><path d="M27.315,18.389c-0.165-0.604-0.509-1.113-0.981-1.459c-0.042-0.144-0.083-0.429-0.015-0.761l0.037-0.177v-0.182V14.8 c0-1.247-0.006-1.277-0.048-1.472c-0.076-0.354-0.035-0.653,0.007-0.803c0.477-0.346,0.828-0.861,0.996-1.476 c0.261-0.956,0.076-2.091-0.508-3.114l-0.591-1.032c-0.746-1.307-1.965-2.119-3.182-2.119c-0.378,0-0.75,0.081-1.085,0.235 c-0.198-0.025-0.554-0.15-0.855-0.389l-0.103-0.082l-0.114-0.065l-1.857-1.067L18.92,3.36l-0.105-0.044 c-0.376-0.154-0.658-0.41-0.768-0.556C17.918,1.172,16.349,0,14.296,0H13.14c-2.043,0-3.608,1.154-3.749,2.721 C9.277,2.862,8.999,3.104,8.633,3.25l-0.1,0.039L8.439,3.341L6.495,4.406L6.363,4.479L6.245,4.573 C5.936,4.82,5.596,4.944,5.416,4.977c-0.314-0.139-0.66-0.21-1.011-0.21c-1.198,0-2.411,0.819-3.165,2.139L0.65,7.938 c-0.412,0.72-0.642,1.521-0.644,2.258c-0.003,0.952,0.362,1.756,1.013,2.256c0.034,0.155,0.061,0.448-0.016,0.786 c-0.038,0.168-0.062,0.28-0.062,1.563c0,1.148,0,1.148,0.015,1.262l0.009,0.073l0.017,0.073c0.073,0.346,0.045,0.643,0.011,0.802 C0.348,17.512-0.01,18.314,0,19.268c0.008,0.729,0.238,1.523,0.648,2.242l0.589,1.031c0.761,1.331,1.967,2.159,3.15,2.159 c0.324,0,0.645-0.064,0.938-0.187c0.167,0.038,0.492,0.156,0.813,0.416l0.11,0.088l0.124,0.07l2.045,1.156l0.102,0.057l0.107,0.043 c0.364,0.147,0.646,0.381,0.766,0.521c0.164,1.52,1.719,2.634,3.745,2.634h1.155c2.037,0,3.598-1.134,3.747-2.675 c0.117-0.145,0.401-0.393,0.774-0.549l0.111-0.047l0.105-0.062l1.96-1.159l0.105-0.062l0.097-0.075 c0.309-0.246,0.651-0.371,0.832-0.402c0.313,0.138,0.662,0.212,1.016,0.212c1.199,0,2.412-0.82,3.166-2.139l0.59-1.032 C27.387,20.48,27.575,19.342,27.315,18.389z M25.274,20.635l-0.59,1.032c-0.438,0.765-1.104,1.251-1.639,1.251 c-0.133,0-0.258-0.029-0.369-0.094c-0.15-0.086-0.346-0.127-0.566-0.127c-0.596,0-1.383,0.295-2.01,0.796l-1.96,1.157 c-1.016,0.425-1.846,1.291-1.846,1.929s-0.898,1.159-1.998,1.159H13.14c-1.1,0-1.998-0.514-1.998-1.141s-0.834-1.477-1.854-1.888 l-2.046-1.157c-0.636-0.511-1.425-0.814-2.006-0.814c-0.202,0-0.379,0.037-0.516,0.115c-0.101,0.057-0.214,0.084-0.333,0.084 c-0.518,0-1.179-0.498-1.62-1.271l-0.591-1.032c-0.545-0.954-0.556-1.983-0.024-2.286c0.532-0.305,0.78-1.432,0.551-2.506 c0,0,0-0.003,0-1.042c0-1.088,0.021-1.18,0.021-1.18c0.238-1.072-0.01-2.203-0.552-2.513C1.631,10.8,1.634,9.765,2.18,8.812 L2.769,7.78c0.438-0.766,1.103-1.251,1.636-1.251c0.131,0,0.255,0.029,0.365,0.092C4.92,6.707,5.114,6.747,5.334,6.747 c0.596,0,1.38-0.296,2.007-0.795l1.944-1.065c1.021-0.407,1.856-1.277,1.856-1.933c0-0.656,0.898-1.192,1.998-1.192h1.156V1.761 c1.1,0,1.998,0.545,1.998,1.211c0,0.667,0.832,1.554,1.849,1.973L20,6.013c0.618,0.489,1.401,0.775,2.012,0.775 c0.24,0,0.454-0.045,0.62-0.139c0.122-0.069,0.259-0.102,0.403-0.102c0.551,0,1.221,0.476,1.653,1.231l0.59,1.032 c0.544,0.953,0.518,2.004-0.062,2.334c-0.577,0.331-0.859,1.48-0.627,2.554c0,0,0.01,0.042,0.01,1.103c0,1.012,0,1.012,0,1.012 c-0.218,1.049,0.068,2.174,0.636,2.498C25.802,18.635,25.819,19.68,25.274,20.635z"/><path d="M13.61,7.611c-3.913,0-7.084,3.173-7.084,7.085c0,3.914,3.171,7.085,7.084,7.085s7.085-3.172,7.085-7.085 C20.695,10.784,17.523,7.611,13.61,7.611z M13.61,20.02c-2.936,0-5.323-2.388-5.323-5.323c0-2.935,2.388-5.323,5.323-5.323 s5.324,2.388,5.324,5.323C18.934,17.632,16.546,20.02,13.61,20.02z"/><path d="M13.682,9.908c-2.602,0-4.718,2.116-4.718,4.718c0,2.601,2.116,4.716,4.718,4.716c2.601,0,4.717-2.115,4.717-4.716 C18.399,12.024,16.283,9.908,13.682,9.908z M13.682,17.581c-1.633,0-2.956-1.323-2.956-2.955s1.323-2.956,2.956-2.956 c1.632,0,2.956,1.324,2.956,2.956S15.314,17.581,13.682,17.581z"/></g></svg>
\ No newline at end of file
#![feature(test)]
#![feature(vec_remove_item)]
#![feature(entry_and_modify)]
+#![feature(dyn_trait)]
extern crate arena;
extern crate getopts;
extern crate serialize as rustc_serialize; // used by deriving
+use errors::ColorConfig;
+
use std::collections::{BTreeMap, BTreeSet};
use std::default::Default;
use std::env;
pub fn main() {
const STACK_SIZE: usize = 32_000_000; // 32MB
+ rustc_driver::set_sigpipe_handler();
env_logger::init();
let res = std::thread::Builder::new().stack_size(STACK_SIZE).spawn(move || {
syntax::with_globals(move || {
"edition to use when compiling rust code (default: 2015)",
"EDITION")
}),
+ unstable("color", |o| {
+ o.optopt("",
+ "color",
+ "Configure coloring of output:
+ auto = colorize, if output goes to a tty (default);
+ always = always colorize output;
+ never = never colorize output",
+ "auto|always|never")
+ }),
+ unstable("error-format", |o| {
+ o.optopt("",
+ "error-format",
+ "How errors and other messages are produced",
+ "human|json|short")
+ }),
]
}
}
let input = &matches.free[0];
+ let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
+ Some("auto") => ColorConfig::Auto,
+ Some("always") => ColorConfig::Always,
+ Some("never") => ColorConfig::Never,
+ None => ColorConfig::Auto,
+ Some(arg) => {
+ print_error(&format!("argument for --color must be `auto`, `always` or `never` \
+ (instead was `{}`)", arg));
+ return 1;
+ }
+ };
+ let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
+ Some("human") => ErrorOutputType::HumanReadable(color),
+ Some("json") => ErrorOutputType::Json(false),
+ Some("pretty-json") => ErrorOutputType::Json(true),
+ Some("short") => ErrorOutputType::Short(color),
+ None => ErrorOutputType::HumanReadable(color),
+ Some(arg) => {
+ print_error(&format!("argument for --error-format must be `human`, `json` or \
+ `short` (instead was `{}`)", arg));
+ return 1;
+ }
+ };
+
let mut libs = SearchPaths::new();
for s in &matches.opt_strs("L") {
- libs.add_path(s, ErrorOutputType::default());
+ libs.add_path(s, error_format);
}
let externs = match parse_externs(&matches) {
Ok(ex) => ex,
}
let output_format = matches.opt_str("w");
- let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, move |out| {
+
+ let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, error_format,
+ move |out| {
let Output { krate, passes, renderinfo } = out;
info!("going to format");
match output_format.as_ref().map(|s| &**s) {
edition: Edition,
cg: CodegenOptions,
matches: &getopts::Matches,
+ error_format: ErrorOutputType,
f: F)
-> Result<R, String>
where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
match matches.opt_str("r").as_ref().map(|s| &**s) {
- Some("rust") => Ok(rust_input(input, externs, edition, cg, matches, f)),
+ Some("rust") => Ok(rust_input(input, externs, edition, cg, matches, error_format, f)),
Some(s) => Err(format!("unknown input format: {}", s)),
- None => Ok(rust_input(input, externs, edition, cg, matches, f))
+ None => Ok(rust_input(input, externs, edition, cg, matches, error_format, f))
}
}
edition: Edition,
cg: CodegenOptions,
matches: &getopts::Matches,
+ error_format: ErrorOutputType,
f: F) -> R
where R: 'static + Send,
F: 'static + Send + FnOnce(Output) -> R
let (mut krate, renderinfo) =
core::run_core(paths, cfgs, externs, Input::File(cratefile), triple, maybe_sysroot,
display_warnings, crate_name.clone(),
- force_unstable_if_unmarked, edition, cg);
+ force_unstable_if_unmarked, edition, cg, error_format);
info!("finished with rustc");
lint_cap: Some(::rustc::lint::Level::Allow),
actually_rustdoc: true,
debugging_opts: config::DebuggingOptions {
- edition,
..config::basic_debugging_options()
},
+ edition,
..config::basic_options().clone()
};
test: as_test_harness,
unstable_features: UnstableFeatures::from_environment(),
debugging_opts: config::DebuggingOptions {
- edition,
..config::basic_debugging_options()
},
+ edition,
..config::basic_options().clone()
};
for line in s.lines() {
let trimline = line.trim();
- let header = trimline.is_whitespace() ||
+ let header = trimline.chars().all(|c| c.is_whitespace()) ||
trimline.starts_with("#![") ||
trimline.starts_with("#[macro_use] extern crate") ||
trimline.starts_with("extern crate");
#![unstable(issue = "32838", feature = "allocator_api")]
#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
-#[doc(inline)] pub use alloc_crate::alloc::Global;
+#[doc(inline)] pub use alloc_crate::alloc::{Global, oom};
#[doc(inline)] pub use alloc_system::System;
#[doc(inline)] pub use core::alloc::*;
+#[cfg(not(stage0))]
+#[cfg(not(test))]
+#[doc(hidden)]
+#[lang = "oom"]
+pub extern fn rust_oom() -> ! {
+ rtabort!("memory allocation failed");
+}
+
#[cfg(not(test))]
#[doc(hidden)]
#[allow(unused_attributes)]
System.alloc(layout) as *mut u8
}
+ #[cfg(stage0)]
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_oom() -> ! {
- System.oom()
+ super::oom()
}
#[no_mangle]
use self::Entry::*;
use self::VacantEntryState::*;
-use alloc::{Global, Alloc, CollectionAllocErr};
+use alloc::{CollectionAllocErr, oom};
use cell::Cell;
use borrow::Borrow;
use cmp::max;
pub fn reserve(&mut self, additional: usize) {
match self.try_reserve(additional) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
- Err(CollectionAllocErr::AllocErr) => Global.oom(),
+ Err(CollectionAllocErr::AllocErr) => oom(),
Ok(()) => { /* yay */ }
}
}
/// # Examples
///
/// ```
- /// #![feature(hash_map_remove_entry)]
/// use std::collections::HashMap;
///
/// # fn main() {
/// assert_eq!(map.remove(&1), None);
/// # }
/// ```
- #[unstable(feature = "hash_map_remove_entry", issue = "46344")]
+ #[stable(feature = "hash_map_remove_entry", since = "1.27.0")]
pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
where K: Borrow<Q>,
Q: Hash + Eq
/// assert_eq!(map["poneyland"], 43);
/// ```
#[stable(feature = "entry_and_modify", since = "1.26.0")]
- pub fn and_modify<F>(self, mut f: F) -> Self
- where F: FnMut(&mut V)
+ pub fn and_modify<F>(self, f: F) -> Self
+ where F: FnOnce(&mut V)
{
match self {
Occupied(mut entry) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use alloc::{Global, Alloc, Layout, CollectionAllocErr};
+use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom};
use cmp;
use hash::{BuildHasher, Hash, Hasher};
use marker;
unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
match Self::try_new_uninitialized(capacity) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
- Err(CollectionAllocErr::AllocErr) => Global.oom(),
+ Err(CollectionAllocErr::AllocErr) => oom(),
Ok(table) => { table }
}
}
pub fn new(capacity: usize) -> RawTable<K, V> {
match Self::try_new(capacity) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
- Err(CollectionAllocErr::AllocErr) => Global.oom(),
+ Err(CollectionAllocErr::AllocErr) => oom(),
Ok(table) => { table }
}
}
impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
fn drop(&mut self) {
- for _ in self {}
+ self.for_each(drop);
}
}
}
}
-#[stable(feature = "never_type", since = "1.26.0")]
+#[unstable(feature = "never_type", issue = "35121")]
impl Error for ! {
fn description(&self) -> &str { *self }
}
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl Error for num::TryFromIntError {
fn description(&self) -> &str {
self.__description()
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl Error for array::TryFromSliceError {
fn description(&self) -> &str {
self.__description()
}
}
-#[stable(feature = "try_from", since = "1.26.0")]
+#[unstable(feature = "try_from", issue = "33417")]
impl Error for char::CharTryFromError {
fn description(&self) -> &str {
"converted integer out of range for `char`"
#![allow(missing_docs)]
#[cfg(not(test))]
-use core::num;
+#[cfg(stage0)]
+use core::num::Float;
#[cfg(not(test))]
use intrinsics;
#[cfg(not(test))]
+#[cfg(stage0)]
use num::FpCategory;
#[cfg(not(test))]
use sys::cmath;
pub use core::f32::consts;
#[cfg(not(test))]
-#[lang = "f32"]
+#[cfg_attr(stage0, lang = "f32")]
+#[cfg_attr(not(stage0), lang = "f32_runtime")]
impl f32 {
- /// Returns `true` if this value is `NaN` and false otherwise.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let nan = f32::NAN;
- /// let f = 7.0_f32;
- ///
- /// assert!(nan.is_nan());
- /// assert!(!f.is_nan());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_nan(self) -> bool { num::Float::is_nan(self) }
-
- /// Returns `true` if this value is positive infinity or negative infinity and
- /// false otherwise.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let f = 7.0f32;
- /// let inf = f32::INFINITY;
- /// let neg_inf = f32::NEG_INFINITY;
- /// let nan = f32::NAN;
- ///
- /// assert!(!f.is_infinite());
- /// assert!(!nan.is_infinite());
- ///
- /// assert!(inf.is_infinite());
- /// assert!(neg_inf.is_infinite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) }
-
- /// Returns `true` if this number is neither infinite nor `NaN`.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let f = 7.0f32;
- /// let inf = f32::INFINITY;
- /// let neg_inf = f32::NEG_INFINITY;
- /// let nan = f32::NAN;
- ///
- /// assert!(f.is_finite());
- ///
- /// assert!(!nan.is_finite());
- /// assert!(!inf.is_finite());
- /// assert!(!neg_inf.is_finite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_finite(self) -> bool { num::Float::is_finite(self) }
-
- /// Returns `true` if the number is neither zero, infinite,
- /// [subnormal][subnormal], or `NaN`.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let min = f32::MIN_POSITIVE; // 1.17549435e-38f32
- /// let max = f32::MAX;
- /// let lower_than_min = 1.0e-40_f32;
- /// let zero = 0.0_f32;
- ///
- /// assert!(min.is_normal());
- /// assert!(max.is_normal());
- ///
- /// assert!(!zero.is_normal());
- /// assert!(!f32::NAN.is_normal());
- /// assert!(!f32::INFINITY.is_normal());
- /// // Values between `0` and `min` are Subnormal.
- /// assert!(!lower_than_min.is_normal());
- /// ```
- /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
-
- /// Returns the floating point category of the number. If only one property
- /// is going to be tested, it is generally faster to use the specific
- /// predicate instead.
- ///
- /// ```
- /// use std::num::FpCategory;
- /// use std::f32;
- ///
- /// let num = 12.4_f32;
- /// let inf = f32::INFINITY;
- ///
- /// assert_eq!(num.classify(), FpCategory::Normal);
- /// assert_eq!(inf.classify(), FpCategory::Infinite);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn classify(self) -> FpCategory { num::Float::classify(self) }
+ #[cfg(stage0)]
+ f32_core_methods!();
/// Returns the largest integer less than or equal to a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn abs(self) -> f32 { num::Float::abs(self) }
+ pub fn abs(self) -> f32 {
+ unsafe { intrinsics::fabsf32(self) }
+ }
/// Returns a number that represents the sign of `self`.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn signum(self) -> f32 { num::Float::signum(self) }
-
- /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
- /// positive sign bit and positive infinity.
- ///
- /// ```
- /// let f = 7.0_f32;
- /// let g = -7.0_f32;
- ///
- /// assert!(f.is_sign_positive());
- /// assert!(!g.is_sign_positive());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
- /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
- /// negative sign bit and negative infinity.
- ///
- /// ```
- /// let f = 7.0f32;
- /// let g = -7.0f32;
- ///
- /// assert!(!f.is_sign_negative());
- /// assert!(g.is_sign_negative());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) }
+ pub fn signum(self) -> f32 {
+ if self.is_nan() {
+ NAN
+ } else {
+ unsafe { intrinsics::copysignf32(1.0, self) }
+ }
+ }
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than
}
- /// Takes the reciprocal (inverse) of a number, `1/x`.
- ///
- /// ```
- /// use std::f32;
- ///
- /// let x = 2.0_f32;
- /// let abs_difference = (x.recip() - (1.0/x)).abs();
- ///
- /// assert!(abs_difference <= f32::EPSILON);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn recip(self) -> f32 { num::Float::recip(self) }
-
/// Raises a number to an integer power.
///
/// Using this function is generally faster than using `powf`
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn powi(self, n: i32) -> f32 { num::Float::powi(self, n) }
+ pub fn powi(self, n: i32) -> f32 {
+ unsafe { intrinsics::powif32(self, n) }
+ }
/// Raises a number to a floating point power.
///
return unsafe { intrinsics::log10f32(self) };
}
- /// Converts radians to degrees.
- ///
- /// ```
- /// use std::f32::{self, consts};
- ///
- /// let angle = consts::PI;
- ///
- /// let abs_difference = (angle.to_degrees() - 180.0).abs();
- ///
- /// assert!(abs_difference <= f32::EPSILON);
- /// ```
- #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
- #[inline]
- pub fn to_degrees(self) -> f32 { num::Float::to_degrees(self) }
-
- /// Converts degrees to radians.
- ///
- /// ```
- /// use std::f32::{self, consts};
- ///
- /// let angle = 180.0f32;
- ///
- /// let abs_difference = (angle.to_radians() - consts::PI).abs();
- ///
- /// assert!(abs_difference <= f32::EPSILON);
- /// ```
- #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")]
- #[inline]
- pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
-
- /// Returns the maximum of the two numbers.
- ///
- /// ```
- /// let x = 1.0f32;
- /// let y = 2.0f32;
- ///
- /// assert_eq!(x.max(y), y);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn max(self, other: f32) -> f32 {
- num::Float::max(self, other)
- }
-
- /// Returns the minimum of the two numbers.
- ///
- /// ```
- /// let x = 1.0f32;
- /// let y = 2.0f32;
- ///
- /// assert_eq!(x.min(y), x);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn min(self, other: f32) -> f32 {
- num::Float::min(self, other)
- }
-
/// The positive difference of two numbers.
///
/// * If `self <= other`: `0:0`
pub fn atanh(self) -> f32 {
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
}
-
- /// Raw transmutation to `u32`.
- ///
- /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms.
- ///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// assert_ne!((1f32).to_bits(), 1f32 as u32); // to_bits() is not casting!
- /// assert_eq!((12.5f32).to_bits(), 0x41480000);
- ///
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn to_bits(self) -> u32 {
- num::Float::to_bits(self)
- }
-
- /// Raw transmutation from `u32`.
- ///
- /// This is currently identical to `transmute::<u32, f32>(v)` on all platforms.
- /// It turns out this is incredibly portable, for two reasons:
- ///
- /// * Floats and Ints have the same endianness on all supported platforms.
- /// * IEEE-754 very precisely specifies the bit layout of floats.
- ///
- /// However there is one caveat: prior to the 2008 version of IEEE-754, how
- /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
- /// (notably x86 and ARM) picked the interpretation that was ultimately
- /// standardized in 2008, but some didn't (notably MIPS). As a result, all
- /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
- ///
- /// Rather than trying to preserve signaling-ness cross-platform, this
- /// implementation favours preserving the exact bits. This means that
- /// any payloads encoded in NaNs will be preserved even if the result of
- /// this method is sent over the network from an x86 machine to a MIPS one.
- ///
- /// If the results of this method are only manipulated by the same
- /// architecture that produced them, then there is no portability concern.
- ///
- /// If the input isn't NaN, then there is no portability concern.
- ///
- /// If you don't care about signalingness (very likely), then there is no
- /// portability concern.
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::f32;
- /// let v = f32::from_bits(0x41480000);
- /// let difference = (v - 12.5).abs();
- /// assert!(difference <= 1e-5);
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn from_bits(v: u32) -> Self {
- num::Float::from_bits(v)
- }
}
#[cfg(test)]
#![allow(missing_docs)]
#[cfg(not(test))]
-use core::num;
+#[cfg(stage0)]
+use core::num::Float;
#[cfg(not(test))]
use intrinsics;
#[cfg(not(test))]
+#[cfg(stage0)]
use num::FpCategory;
#[cfg(not(test))]
use sys::cmath;
pub use core::f64::consts;
#[cfg(not(test))]
-#[lang = "f64"]
+#[cfg_attr(stage0, lang = "f64")]
+#[cfg_attr(not(stage0), lang = "f64_runtime")]
impl f64 {
- /// Returns `true` if this value is `NaN` and false otherwise.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let nan = f64::NAN;
- /// let f = 7.0_f64;
- ///
- /// assert!(nan.is_nan());
- /// assert!(!f.is_nan());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_nan(self) -> bool { num::Float::is_nan(self) }
-
- /// Returns `true` if this value is positive infinity or negative infinity and
- /// false otherwise.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let f = 7.0f64;
- /// let inf = f64::INFINITY;
- /// let neg_inf = f64::NEG_INFINITY;
- /// let nan = f64::NAN;
- ///
- /// assert!(!f.is_infinite());
- /// assert!(!nan.is_infinite());
- ///
- /// assert!(inf.is_infinite());
- /// assert!(neg_inf.is_infinite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_infinite(self) -> bool { num::Float::is_infinite(self) }
-
- /// Returns `true` if this number is neither infinite nor `NaN`.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let f = 7.0f64;
- /// let inf: f64 = f64::INFINITY;
- /// let neg_inf: f64 = f64::NEG_INFINITY;
- /// let nan: f64 = f64::NAN;
- ///
- /// assert!(f.is_finite());
- ///
- /// assert!(!nan.is_finite());
- /// assert!(!inf.is_finite());
- /// assert!(!neg_inf.is_finite());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_finite(self) -> bool { num::Float::is_finite(self) }
-
- /// Returns `true` if the number is neither zero, infinite,
- /// [subnormal][subnormal], or `NaN`.
- ///
- /// ```
- /// use std::f64;
- ///
- /// let min = f64::MIN_POSITIVE; // 2.2250738585072014e-308f64
- /// let max = f64::MAX;
- /// let lower_than_min = 1.0e-308_f64;
- /// let zero = 0.0f64;
- ///
- /// assert!(min.is_normal());
- /// assert!(max.is_normal());
- ///
- /// assert!(!zero.is_normal());
- /// assert!(!f64::NAN.is_normal());
- /// assert!(!f64::INFINITY.is_normal());
- /// // Values between `0` and `min` are Subnormal.
- /// assert!(!lower_than_min.is_normal());
- /// ```
- /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_normal(self) -> bool { num::Float::is_normal(self) }
-
- /// Returns the floating point category of the number. If only one property
- /// is going to be tested, it is generally faster to use the specific
- /// predicate instead.
- ///
- /// ```
- /// use std::num::FpCategory;
- /// use std::f64;
- ///
- /// let num = 12.4_f64;
- /// let inf = f64::INFINITY;
- ///
- /// assert_eq!(num.classify(), FpCategory::Normal);
- /// assert_eq!(inf.classify(), FpCategory::Infinite);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn classify(self) -> FpCategory { num::Float::classify(self) }
+ #[cfg(stage0)]
+ f64_core_methods!();
/// Returns the largest integer less than or equal to a number.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn abs(self) -> f64 { num::Float::abs(self) }
+ pub fn abs(self) -> f64 {
+ unsafe { intrinsics::fabsf64(self) }
+ }
/// Returns a number that represents the sign of `self`.
///
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn signum(self) -> f64 { num::Float::signum(self) }
-
- /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with
- /// positive sign bit and positive infinity.
- ///
- /// ```
- /// let f = 7.0_f64;
- /// let g = -7.0_f64;
- ///
- /// assert!(f.is_sign_positive());
- /// assert!(!g.is_sign_positive());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")]
- #[inline]
- pub fn is_positive(self) -> bool { num::Float::is_sign_positive(self) }
-
- /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with
- /// negative sign bit and negative infinity.
- ///
- /// ```
- /// let f = 7.0_f64;
- /// let g = -7.0_f64;
- ///
- /// assert!(!f.is_sign_negative());
- /// assert!(g.is_sign_negative());
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn is_sign_negative(self) -> bool { num::Float::is_sign_negative(self) }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")]
- #[inline]
- pub fn is_negative(self) -> bool { num::Float::is_sign_negative(self) }
+ pub fn signum(self) -> f64 {
+ if self.is_nan() {
+ NAN
+ } else {
+ unsafe { intrinsics::copysignf64(1.0, self) }
+ }
+ }
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than
}
}
- /// Takes the reciprocal (inverse) of a number, `1/x`.
- ///
- /// ```
- /// let x = 2.0_f64;
- /// let abs_difference = (x.recip() - (1.0/x)).abs();
- ///
- /// assert!(abs_difference < 1e-10);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn recip(self) -> f64 { num::Float::recip(self) }
-
/// Raises a number to an integer power.
///
/// Using this function is generally faster than using `powf`
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn powi(self, n: i32) -> f64 { num::Float::powi(self, n) }
+ pub fn powi(self, n: i32) -> f64 {
+ unsafe { intrinsics::powif64(self, n) }
+ }
/// Raises a number to a floating point power.
///
self.log_wrapper(|n| { unsafe { intrinsics::log10f64(n) } })
}
- /// Converts radians to degrees.
- ///
- /// ```
- /// use std::f64::consts;
- ///
- /// let angle = consts::PI;
- ///
- /// let abs_difference = (angle.to_degrees() - 180.0).abs();
- ///
- /// assert!(abs_difference < 1e-10);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn to_degrees(self) -> f64 { num::Float::to_degrees(self) }
-
- /// Converts degrees to radians.
- ///
- /// ```
- /// use std::f64::consts;
- ///
- /// let angle = 180.0_f64;
- ///
- /// let abs_difference = (angle.to_radians() - consts::PI).abs();
- ///
- /// assert!(abs_difference < 1e-10);
- /// ```
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn to_radians(self) -> f64 { num::Float::to_radians(self) }
-
- /// Returns the maximum of the two numbers.
- ///
- /// ```
- /// let x = 1.0_f64;
- /// let y = 2.0_f64;
- ///
- /// assert_eq!(x.max(y), y);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn max(self, other: f64) -> f64 {
- num::Float::max(self, other)
- }
-
- /// Returns the minimum of the two numbers.
- ///
- /// ```
- /// let x = 1.0_f64;
- /// let y = 2.0_f64;
- ///
- /// assert_eq!(x.min(y), x);
- /// ```
- ///
- /// If one of the arguments is NaN, then the other argument is returned.
- #[stable(feature = "rust1", since = "1.0.0")]
- #[inline]
- pub fn min(self, other: f64) -> f64 {
- num::Float::min(self, other)
- }
-
/// The positive difference of two numbers.
///
/// * If `self <= other`: `0:0`
}
}
}
-
- /// Raw transmutation to `u64`.
- ///
- /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms.
- ///
- /// See `from_bits` for some discussion of the portability of this operation
- /// (there are almost no issues).
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
- /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
- ///
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn to_bits(self) -> u64 {
- num::Float::to_bits(self)
- }
-
- /// Raw transmutation from `u64`.
- ///
- /// This is currently identical to `transmute::<u64, f64>(v)` on all platforms.
- /// It turns out this is incredibly portable, for two reasons:
- ///
- /// * Floats and Ints have the same endianness on all supported platforms.
- /// * IEEE-754 very precisely specifies the bit layout of floats.
- ///
- /// However there is one caveat: prior to the 2008 version of IEEE-754, how
- /// to interpret the NaN signaling bit wasn't actually specified. Most platforms
- /// (notably x86 and ARM) picked the interpretation that was ultimately
- /// standardized in 2008, but some didn't (notably MIPS). As a result, all
- /// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
- ///
- /// Rather than trying to preserve signaling-ness cross-platform, this
- /// implementation favours preserving the exact bits. This means that
- /// any payloads encoded in NaNs will be preserved even if the result of
- /// this method is sent over the network from an x86 machine to a MIPS one.
- ///
- /// If the results of this method are only manipulated by the same
- /// architecture that produced them, then there is no portability concern.
- ///
- /// If the input isn't NaN, then there is no portability concern.
- ///
- /// If you don't care about signalingness (very likely), then there is no
- /// portability concern.
- ///
- /// Note that this function is distinct from `as` casting, which attempts to
- /// preserve the *numeric* value, and not the bitwise value.
- ///
- /// # Examples
- ///
- /// ```
- /// use std::f64;
- /// let v = f64::from_bits(0x4029000000000000);
- /// let difference = (v - 12.5).abs();
- /// assert!(difference <= 1e-5);
- /// ```
- #[stable(feature = "float_bits_conv", since = "1.20.0")]
- #[inline]
- pub fn from_bits(v: u64) -> Self {
- num::Float::from_bits(v)
- }
}
#[cfg(test)]
/// # Conversions
///
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
-/// the traits which `OsString` implements for conversions from/to native representations.
+/// the traits which `OsString` implements for [conversions] from/to native representations.
///
/// [`OsStr`]: struct.OsStr.html
/// [`&OsStr`]: struct.OsStr.html
/// [`new`]: #method.new
/// [`push`]: #method.push
/// [`as_os_str`]: #method.as_os_str
+/// [conversions]: index.html#conversions
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct OsString {
/// references; the latter are owned strings.
///
/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
-/// the traits which `OsStr` implements for conversions from/to native representations.
+/// the traits which `OsStr` implements for [conversions] from/to native representations.
///
/// [`OsString`]: struct.OsString.html
/// [`&str`]: ../primitive.str.html
//!
//! Once you are familiar with the contents of the standard library you may
//! begin to find the verbosity of the prose distracting. At this stage in your
-//! development you may want to press the **[-]** button near the top of the
+//! development you may want to press the `[-]` button near the top of the
//! page to collapse it into a more skimmable view.
//!
-//! While you are looking at that **[-]** button also notice the **[src]**
+//! While you are looking at that `[-]` button also notice the `[src]`
//! button. Rust's API documentation comes with the source code and you are
//! encouraged to read it. The standard library source is generally high
//! quality and a peek behind the curtains is often enlightening.
#![feature(collections_range)]
#![feature(compiler_builtins_lib)]
#![feature(const_fn)]
-#![feature(core_float)]
+#![cfg_attr(stage0, feature(core_float))]
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
#![feature(fs_read_write)]
#![feature(fixed_size_array)]
#![feature(float_from_str_radix)]
+#![cfg_attr(stage0, feature(float_internals))]
#![feature(fn_traits)]
#![feature(fnbox)]
#![cfg_attr(stage0, feature(generic_param_attrs))]
#![feature(macro_reexport)]
#![feature(macro_vis_matcher)]
#![feature(needs_panic_runtime)]
-#![feature(nonnull_cast)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(nonzero)]
#![feature(num_bits_bytes)]
#![feature(rand)]
#![feature(raw)]
#![feature(rustc_attrs)]
+#![feature(std_internals)]
#![feature(stdsimd)]
#![feature(shrink_to)]
#![feature(slice_bytes)]
#![feature(test, rustc_private)]
#![feature(thread_local)]
#![feature(toowned_clone_into)]
+#![feature(try_from)]
#![feature(try_reserve)]
#![feature(unboxed_closures)]
#![feature(untagged_unions)]
#![feature(doc_spotlight)]
#![cfg_attr(test, feature(update_panic_count))]
#![cfg_attr(windows, feature(used))]
+#![feature(doc_alias)]
#![default_lib_allocator]
pub mod process;
pub mod sync;
pub mod time;
-pub mod alloc;
#[unstable(feature = "allocator_api", issue = "32838")]
#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
mod sys_common;
mod sys;
+pub mod alloc;
+
// Private support modules
mod panicking;
mod memchr;
#[unstable(feature = "stdsimd", issue = "48556")]
#[cfg(all(not(stage0), not(test)))]
pub use stdsimd::simd;
-#[unstable(feature = "stdsimd", issue = "48556")]
+#[stable(feature = "simd_arch", since = "1.27.0")]
#[cfg(all(not(stage0), not(test)))]
pub use stdsimd::arch;
}
}
-/// A macro for defining #[cfg] if-else statements.
+/// A macro for defining `#[cfg]` if-else statements.
///
/// This is similar to the `if/elif` C preprocessor macro by allowing definition
/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
/// first.
///
-/// This allows you to conveniently provide a long list #[cfg]'d blocks of code
+/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
/// without having to rewrite each clause multiple times.
macro_rules! cfg_if {
($(
#[allow(deprecated)]
use os::android::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::bitrig::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::dragonfly::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::emscripten::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::freebsd::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
use fs::Metadata;
use sys_common::AsInner;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext2", since = "1.8.0")]
#[allow(deprecated)]
use os::haiku::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::ios::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::linux::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::macos::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::netbsd::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::openbsd::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
#[allow(deprecated)]
use os::solaris::raw;
-/// OS-specific extension methods for `fs::Metadata`
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
//! * Executing a panic up to doing the actual implementation
//! * Shims around "try"
+use core::panic::BoxMeUp;
+
use io::prelude::*;
use any::Any;
use mem;
use ptr;
use raw;
-use sys::stdio::Stderr;
+use sys::stdio::{Stderr, stderr_prints_nothing};
use sys_common::rwlock::RWLock;
use sys_common::thread_info;
use sys_common::util;
data_ptr: *mut usize,
vtable_ptr: *mut usize) -> u32;
#[unwind(allowed)]
- fn __rust_start_panic(data: usize, vtable: usize) -> u32;
+ fn __rust_start_panic(payload: usize) -> u32;
}
#[derive(Copy, Clone)]
};
let location = info.location().unwrap(); // The current implementation always returns Some
- let file = location.file();
- let line = location.line();
- let col = location.column();
let msg = match info.payload().downcast_ref::<&'static str>() {
Some(s) => *s,
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
let write = |err: &mut ::io::Write| {
- let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}:{}",
- name, msg, file, line, col);
+ let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
+ name, msg, location);
#[cfg(feature = "backtrace")]
{
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
match (prev, err.as_mut()) {
- (Some(mut stderr), _) => {
- write(&mut *stderr);
- let mut s = Some(stderr);
- LOCAL_STDERR.with(|slot| {
- *slot.borrow_mut() = s.take();
- });
- }
- (None, Some(ref mut err)) => { write(err) }
- _ => {}
+ (Some(mut stderr), _) => {
+ write(&mut *stderr);
+ let mut s = Some(stderr);
+ LOCAL_STDERR.with(|slot| {
+ *slot.borrow_mut() = s.take();
+ });
+ }
+ (None, Some(ref mut err)) => { write(err) }
+ _ => {}
}
}
// panic + OOM properly anyway (see comment in begin_panic
// below).
- let mut s = String::new();
- let _ = s.write_fmt(*msg);
- rust_panic_with_hook(Box::new(s), Some(msg), file_line_col)
+ rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col);
+
+ struct PanicPayload<'a> {
+ inner: &'a fmt::Arguments<'a>,
+ string: Option<String>,
+ }
+
+ impl<'a> PanicPayload<'a> {
+ fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
+ PanicPayload { inner, string: None }
+ }
+
+ fn fill(&mut self) -> &mut String {
+ let inner = self.inner;
+ self.string.get_or_insert_with(|| {
+ let mut s = String::new();
+ drop(s.write_fmt(*inner));
+ s
+ })
+ }
+ }
+
+ unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
+ fn box_me_up(&mut self) -> *mut (Any + Send) {
+ let contents = mem::replace(self.fill(), String::new());
+ Box::into_raw(Box::new(contents))
+ }
+
+ fn get(&mut self) -> &(Any + Send) {
+ self.fill()
+ }
+ }
}
/// This is the entry point of panicking for panic!() and assert!().
// be performed in the parent of this thread instead of the thread that's
// panicking.
- rust_panic_with_hook(Box::new(msg), None, file_line_col)
+ rust_panic_with_hook(&mut PanicPayload::new(msg), None, file_line_col);
+
+ struct PanicPayload<A> {
+ inner: Option<A>,
+ }
+
+ impl<A: Send + 'static> PanicPayload<A> {
+ fn new(inner: A) -> PanicPayload<A> {
+ PanicPayload { inner: Some(inner) }
+ }
+ }
+
+ unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
+ fn box_me_up(&mut self) -> *mut (Any + Send) {
+ let data = match self.inner.take() {
+ Some(a) => Box::new(a) as Box<Any + Send>,
+ None => Box::new(()),
+ };
+ Box::into_raw(data)
+ }
+
+ fn get(&mut self) -> &(Any + Send) {
+ match self.inner {
+ Some(ref a) => a,
+ None => &(),
+ }
+ }
+ }
}
-/// Executes the primary logic for a panic, including checking for recursive
-/// panics and panic hooks.
+/// Central point for dispatching panics.
///
-/// This is the entry point or panics from libcore, formatted panics, and
-/// `Box<Any>` panics. Here we'll verify that we're not panicking recursively,
-/// run panic hooks, and then delegate to the actual implementation of panics.
-#[inline(never)]
-#[cold]
-fn rust_panic_with_hook(payload: Box<Any + Send>,
+/// Executes the primary logic for a panic, including checking for recursive
+/// panics, panic hooks, and finally dispatching to the panic runtime to either
+/// abort or unwind.
+fn rust_panic_with_hook(payload: &mut BoxMeUp,
message: Option<&fmt::Arguments>,
file_line_col: &(&'static str, u32, u32)) -> ! {
let (file, line, col) = *file_line_col;
}
unsafe {
- let info = PanicInfo::internal_constructor(
- &*payload,
+ let mut info = PanicInfo::internal_constructor(
message,
Location::internal_constructor(file, line, col),
);
HOOK_LOCK.read();
match HOOK {
- Hook::Default => default_hook(&info),
- Hook::Custom(ptr) => (*ptr)(&info),
+ // Some platforms know that printing to stderr won't ever actually
+ // print anything, and if that's the case we can skip the default
+ // hook.
+ Hook::Default if stderr_prints_nothing() => {}
+ Hook::Default => {
+ info.set_payload(payload.get());
+ default_hook(&info);
+ }
+ Hook::Custom(ptr) => {
+ info.set_payload(payload.get());
+ (*ptr)(&info);
+ }
}
HOOK_LOCK.read_unlock();
}
/// Shim around rust_panic. Called by resume_unwind.
pub fn update_count_then_panic(msg: Box<Any + Send>) -> ! {
update_panic_count(1);
- rust_panic(msg)
+
+ struct RewrapBox(Box<Any + Send>);
+
+ unsafe impl BoxMeUp for RewrapBox {
+ fn box_me_up(&mut self) -> *mut (Any + Send) {
+ Box::into_raw(mem::replace(&mut self.0, Box::new(())))
+ }
+
+ fn get(&mut self) -> &(Any + Send) {
+ &*self.0
+ }
+ }
+
+ rust_panic(&mut RewrapBox(msg))
}
/// A private no-mangle function on which to slap yer breakpoints.
#[no_mangle]
#[allow(private_no_mangle_fns)] // yes we get it, but we like breakpoints
-pub fn rust_panic(msg: Box<Any + Send>) -> ! {
+pub fn rust_panic(mut msg: &mut BoxMeUp) -> ! {
let code = unsafe {
- let obj = mem::transmute::<_, raw::TraitObject>(msg);
- __rust_start_panic(obj.data as usize, obj.vtable as usize)
+ let obj = &mut msg as *mut &mut BoxMeUp;
+ __rust_start_panic(obj as usize)
};
rtabort!("failed to initiate panic, error {}", code)
}
// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
// `iter` after having exhausted `prefix`.
-fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I>
- where I: Iterator<Item = A> + Clone,
- J: Iterator<Item = A>,
- A: PartialEq
+fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
+ where I: Iterator<Item = Component<'a>> + Clone,
+ J: Iterator<Item = Component<'b>>,
{
loop {
let mut iter_next = iter.clone();
/// # Examples
///
/// ```
- /// use std::path::Path;
+ /// use std::path::{Path, PathBuf};
///
/// let path = Path::new("/test/haha/foo.txt");
///
/// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
/// assert_eq!(path.strip_prefix("test").is_ok(), false);
/// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
+ ///
+ /// let prefix = PathBuf::from("/test/");
+ /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
/// ```
#[stable(since = "1.7.0", feature = "path_strip_prefix")]
- pub fn strip_prefix<'a, P: ?Sized>(&'a self, base: &'a P)
- -> Result<&'a Path, StripPrefixError>
+ pub fn strip_prefix<P>(&self, base: P)
+ -> Result<&Path, StripPrefixError>
where P: AsRef<Path>
{
self._strip_prefix(base.as_ref())
}
- fn _strip_prefix<'a>(&'a self, base: &'a Path)
- -> Result<&'a Path, StripPrefixError> {
+ fn _strip_prefix(&self, base: &Path)
+ -> Result<&Path, StripPrefixError> {
iter_after(self.components(), base.components())
.map(|c| c.as_path())
.ok_or(StripPrefixError(()))
// except according to those terms.
#[doc(primitive = "bool")]
+#[doc(alias = "true")]
+#[doc(alias = "false")]
//
/// The boolean type.
///
mod prim_bool { }
#[doc(primitive = "never")]
+#[doc(alias = "!")]
//
/// The `!` type, also called "never".
///
/// write:
///
/// ```
+/// #![feature(never_type)]
/// # fn foo() -> u32 {
/// let x: ! = {
/// return 123
/// for example:
///
/// ```
+/// #![feature(never_type)]
/// # use std::fmt;
/// # trait Debug {
/// # fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result;
mod prim_array { }
#[doc(primitive = "slice")]
+#[doc(alias = "[")]
+#[doc(alias = "]")]
+#[doc(alias = "[]")]
//
/// A dynamically-sized view into a contiguous sequence, `[T]`.
///
mod prim_str { }
#[doc(primitive = "tuple")]
+#[doc(alias = "(")]
+#[doc(alias = ")")]
+#[doc(alias = "()")]
//
/// A finite heterogeneous sequence, `(T, U, ..)`.
///
mod prim_usize { }
#[doc(primitive = "reference")]
+#[doc(alias = "&")]
//
/// References, both shared and mutable.
///
}
impl Child {
- /// Forces the child to exit. This is equivalent to sending a
- /// SIGKILL on unix platforms.
+ /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
+ /// error is returned.
+ ///
+ /// The mapping to [`ErrorKind`]s is not part of the compatibility contract of the function,
+ /// especially the [`Other`] kind might change to more specific kinds in the future.
+ ///
+ /// This is equivalent to sending a SIGKILL on Unix platforms.
///
/// # Examples
///
/// println!("yes command didn't start");
/// }
/// ```
+ ///
+ /// [`ErrorKind`]: ../io/enum.ErrorKind.html
+ /// [`InvalidInput`]: ../io/enum.ErrorKind.html#variant.InvalidInput
+ /// [`Other`]: ../io/enum.ErrorKind.html#variant.Other
#[stable(feature = "process", since = "1.0.0")]
pub fn kill(&mut self) -> io::Result<()> {
self.handle.kill()
}
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn stderr_prints_nothing() -> bool {
+ false
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Unix-specific extension to the primitives in the `std::ffi` module
+//! Redox-specific extension to the primitives in the `std::ffi` module.
#![stable(feature = "rust1", since = "1.0.0")]
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
-/// Unix-specific extensions to `OsString`.
+/// Redox-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an `OsString` from a byte vector.
}
}
-/// Unix-specific extensions to `OsStr`.
+/// Redox-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
-/// Redox-specific extensions to `Permissions`
+/// Redox-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `mode_t` bits that are the standard Redox
}
}
-/// Redox-specific extensions to `OpenOptions`
+/// Redox-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
}
}
-// Hm, why are there casts here to the returned type, shouldn't the types always
-// be the same? Right you are! Turns out, however, on android at least the types
-// in the raw `stat` structure are not the same as the types being returned. Who
-// knew!
-//
-// As a result to make sure this compiles for all platforms we do the manual
-// casts and rely on manual lowering to `stat` if the raw type is desired.
+/// Redox-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blocks(&self) -> u64;
}
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 {
}
}
-/// Add special Redox types (block/char device, fifo and socket)
+/// Redox-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
sys::fs::symlink(src.as_ref(), dst.as_ref())
}
+/// Redox-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
#[stable(feature = "dir_builder", since = "1.6.0")]
-/// An extension trait for `fs::DirBuilder` for Redox-specific options.
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Unix-specific extensions to primitives in the `std::process` module.
+//! Redox-specific extensions to primitives in the `std::process` module.
#![stable(feature = "rust1", since = "1.0.0")]
use sys;
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
-/// Unix-specific extensions to the `std::process::Command` builder
+/// Redox-specific extensions to the [`process::Command`] builder,
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user id. This translates to a
}
}
-/// Unix-specific extensions to `std::process::ExitStatus`
+/// Redox-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Unix-specific extensions to primitives in the `std::thread` module.
+//! Redox-specific extensions to primitives in the `std::thread` module.
#![stable(feature = "thread_extensions", since = "1.9.0")]
#[allow(deprecated)]
pub type RawPthread = usize;
-/// Unix-specific extensions to `std::thread::JoinHandle`
+/// Redox-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
}
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn stderr_prints_nothing() -> bool {
+ false
+}
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
-/// Unix-specific extensions to `OsString`.
+/// Unix-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an [`OsString`] from a byte vector.
}
}
-/// Unix-specific extensions to `OsStr`.
+/// Unix-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// Unix-specific extensions to `Permissions`
+/// Unix-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `st_mode` bits that contain the standard
}
}
-/// Unix-specific extensions to `OpenOptions`
+/// Unix-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
}
}
-// Hm, why are there casts here to the returned type, shouldn't the types always
-// be the same? Right you are! Turns out, however, on android at least the types
-// in the raw `stat` structure are not the same as the types being returned. Who
-// knew!
-//
-// As a result to make sure this compiles for all platforms we do the manual
-// casts and rely on manual lowering to `stat` if the raw type is desired.
+/// Unix-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Returns the ID of the device containing the file.
fn blocks(&self) -> u64 { self.st_blocks() }
}
-/// Add support for special unix types (block/char device, fifo and socket).
+/// Unix-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
sys::fs::symlink(src.as_ref(), dst.as_ref())
}
-#[stable(feature = "dir_builder", since = "1.6.0")]
-/// An extension trait for [`fs::DirBuilder`] for unix-specific options.
+/// Unix-specific extensions to [`fs::DirBuilder`].
///
/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
use sys;
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
-/// Unix-specific extensions to the `std::process::Command` builder
+/// Unix-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user id. This translates to a
}
}
-/// Unix-specific extensions to `std::process::ExitStatus`
+/// Unix-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
#[allow(deprecated)]
pub type RawPthread = pthread_t;
-/// Unix-specific extensions to `std::thread::JoinHandle`
+/// Unix-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
reset_sigpipe();
}
- #[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))]
+ #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
unsafe fn reset_sigpipe() {
assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
}
- #[cfg(any(target_os = "emscripten", target_os="fuchsia"))]
+ #[cfg(any(target_os = "emscripten", target_os = "fuchsia"))]
unsafe fn reset_sigpipe() {}
}
}
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn stderr_prints_nothing() -> bool {
+ false
+}
if *mode >= 0 {
*mode += 1;
} else {
- panic!("rwlock locked for writing");
+ rtabort!("rwlock locked for writing");
}
}
if *mode == 0 {
*mode = -1;
} else {
- panic!("rwlock locked for reading")
+ rtabort!("rwlock locked for reading")
}
}
pub fn is_ebadf(_err: &io::Error) -> bool {
true
}
+
+pub fn stderr_prints_nothing() -> bool {
+ !cfg!(feature = "wasm_syscall")
+}
#[stable(feature = "rust1", since = "1.0.0")]
pub use sys_common::wtf8::EncodeWide;
-/// Windows-specific extensions to `OsString`.
+/// Windows-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an `OsString` from a potentially ill-formed UTF-16 slice of
}
}
-/// Windows-specific extensions to `OsStr`.
+/// Windows-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
/// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially
}
}
-/// Windows-specific extensions to [`OpenOptions`].
+/// Windows-specific extensions to [`fs::OpenOptions`].
///
-/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "open_options_ext", since = "1.10.0")]
pub trait OpenOptionsExt {
/// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`]
}
}
-/// Extension methods for [`fs::Metadata`] to access the raw fields contained
-/// within.
+/// Windows-specific extensions to [`fs::Metadata`].
///
/// The data members that this trait exposes correspond to the members
/// of the [`BY_HANDLE_FILE_INFORMATION`] structure.
///
-/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
/// [`BY_HANDLE_FILE_INFORMATION`]:
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn file_size(&self) -> u64 { self.as_inner().size() }
}
-/// Add support for the Windows specific fact that a symbolic link knows whether it is a file
-/// or directory.
+/// Windows-specific extensions to [`FileType`].
+///
+/// On Windows, a symbolic link knows whether it is a file or directory.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[unstable(feature = "windows_file_type_ext", issue = "0")]
pub trait FileTypeExt {
/// Returns whether this file type is a symbolic link that is also a directory.
}
}
-/// Windows-specific extensions to `std::process::ExitStatus`
+/// Windows-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "exit_status_from", since = "1.12.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `u32` return value of
}
}
-/// Windows-specific extensions to the `std::process::Command` builder
+/// Windows-specific extensions to the [`process::Command`] builder.
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
pub trait CommandExt {
/// Sets the [process creation flags][1] to be passed to `CreateProcess`.
0 => {}
n => return n as *mut _,
}
- let mut re = Box::new(ReentrantMutex::uninitialized());
+ let mut re = box ReentrantMutex::uninitialized();
re.init();
let re = Box::into_raw(re);
match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) {
// idea is that on windows we use a slightly smaller buffer that's
// been seen to be acceptable.
pub const STDIN_BUF_SIZE: usize = 8 * 1024;
+
+pub fn stderr_prints_nothing() -> bool {
+ false
+}
/// Controls how the backtrace should be formatted.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PrintFormat {
- /// Show all the frames with absolute path for files.
- Full = 2,
/// Show only relevant data from the backtrace.
- Short = 3,
+ Short = 2,
+ /// Show all the frames with absolute path for files.
+ Full = 3,
}
// For now logging is turned off by default, and this function checks to see
pub fn log_enabled() -> Option<PrintFormat> {
static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
match ENABLED.load(Ordering::SeqCst) {
- 0 => {},
+ 0 => {}
1 => return None,
- 2 => return Some(PrintFormat::Full),
- 3 => return Some(PrintFormat::Short),
- _ => unreachable!(),
+ 2 => return Some(PrintFormat::Short),
+ _ => return Some(PrintFormat::Full),
}
let val = match env::var_os("RUST_BACKTRACE") {
use sync::Once;
use sys;
+macro_rules! rtabort {
+ ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
+}
+
+macro_rules! rtassert {
+ ($e:expr) => (if !$e {
+ rtabort!(concat!("assertion failed: ", stringify!($e)));
+ })
+}
+
pub mod at_exit_imp;
#[cfg(feature = "backtrace")]
pub mod backtrace;
if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())}
}
-macro_rules! rtabort {
- ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*)))
-}
-
/// One-time runtime cleanup.
pub fn cleanup() {
static CLEANUP: Once = Once::new();
self.key.store(key, Ordering::SeqCst);
}
INIT_LOCK.unlock();
- assert!(key != 0);
+ rtassert!(key != 0);
return key
}
imp::destroy(key1);
key2
};
- assert!(key != 0);
+ rtassert!(key != 0);
match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
// The CAS succeeded, so we've created the actual key
0 => key as usize,
use fmt;
use io::prelude::*;
-use sys::stdio::Stderr;
+use sys::stdio::{Stderr, stderr_prints_nothing};
use thread;
pub fn dumb_print(args: fmt::Arguments) {
+ if stderr_prints_nothing() {
+ return
+ }
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
}
}
impl Wtf8 {
- pub fn is_ascii(&self) -> bool {
- self.bytes.is_ascii()
- }
- pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
- Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() }
- }
- pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
- Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() }
- }
- pub fn eq_ignore_ascii_case(&self, other: &Wtf8) -> bool {
- self.bytes.eq_ignore_ascii_case(&other.bytes)
- }
-
pub fn make_ascii_uppercase(&mut self) { self.bytes.make_ascii_uppercase() }
- pub fn make_ascii_lowercase(&mut self) { self.bytes.make_ascii_lowercase() }
}
#[cfg(test)]
&'static $crate::cell::UnsafeCell<
$crate::option::Option<$t>>>
{
+ #[cfg(target_arch = "wasm32")]
+ static __KEY: $crate::thread::__StaticLocalKeyInner<$t> =
+ $crate::thread::__StaticLocalKeyInner::new();
+
#[thread_local]
- #[cfg(target_thread_local)]
+ #[cfg(all(target_thread_local, not(target_arch = "wasm32")))]
static __KEY: $crate::thread::__FastLocalKeyInner<$t> =
$crate::thread::__FastLocalKeyInner::new();
- #[cfg(not(target_thread_local))]
+ #[cfg(all(not(target_thread_local), not(target_arch = "wasm32")))]
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
$crate::thread::__OsLocalKeyInner::new();
}
}
+/// On some platforms like wasm32 there's no threads, so no need to generate
+/// thread locals and we can instead just use plain statics!
+#[doc(hidden)]
+#[cfg(target_arch = "wasm32")]
+pub mod statik {
+ use cell::UnsafeCell;
+ use fmt;
+
+ pub struct Key<T> {
+ inner: UnsafeCell<Option<T>>,
+ }
+
+ unsafe impl<T> ::marker::Sync for Key<T> { }
+
+ impl<T> fmt::Debug for Key<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("Key { .. }")
+ }
+ }
+
+ impl<T> Key<T> {
+ pub const fn new() -> Key<T> {
+ Key {
+ inner: UnsafeCell::new(None),
+ }
+ }
+
+ pub unsafe fn get(&self) -> Option<&'static UnsafeCell<Option<T>>> {
+ Some(&*(&self.inner as *const _))
+ }
+ }
+}
+
#[doc(hidden)]
#[cfg(target_thread_local)]
pub mod fast {
// where fast TLS was not available; end-user code is compiled with fast TLS
// where available, but both are needed.
+#[unstable(feature = "libstd_thread_internals", issue = "0")]
+#[cfg(target_arch = "wasm32")]
+#[doc(hidden)] pub use self::local::statik::Key as __StaticLocalKeyInner;
#[unstable(feature = "libstd_thread_internals", issue = "0")]
#[cfg(target_thread_local)]
#[doc(hidden)] pub use self::local::fast::Key as __FastLocalKeyInner;
Cooked,
/// A raw string, like `r##"foo"##`
///
- /// The uint is the number of `#` symbols used
- Raw(usize)
+ /// The value is the number of `#` symbols used.
+ Raw(u16)
}
/// A literal
// when adding new editions, be sure to update:
//
- // - the list in the `parse_edition` static in librustc::session::config
+ // - Update the `ALL_EDITIONS` const
+ // - Update the EDITION_NAME_LIST const
// - add a `rust_####()` function to the session
// - update the enum in Cargo's sources as well
- //
- // When -Zedition becomes --edition, there will
- // also be a check for the edition being nightly-only
- // somewhere. That will need to be updated
- // whenever we're stabilizing/introducing a new edition
- // as well as changing the default Cargo template.
}
// must be in order from oldest to newest
pub const ALL_EDITIONS: &[Edition] = &[Edition::Edition2015, Edition::Edition2018];
+pub const EDITION_NAME_LIST: &'static str = "2015|2018";
+
+pub const DEFAULT_EDITION: Edition = Edition::Edition2015;
+
impl fmt::Display for Edition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s = match *self {
Edition::Edition2018 => "rust_2018_preview",
}
}
+
+ pub fn is_stable(&self) -> bool {
+ match *self {
+ Edition::Edition2015 => true,
+ Edition::Edition2018 => false,
+ }
+ }
}
impl FromStr for Edition {
fn expr_usize(&self, span: Span, i: usize) -> P<ast::Expr>;
fn expr_isize(&self, sp: Span, i: isize) -> P<ast::Expr>;
fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr>;
+ fn expr_u16(&self, sp: Span, u: u16) -> P<ast::Expr>;
fn expr_u32(&self, sp: Span, u: u32) -> P<ast::Expr>;
fn expr_bool(&self, sp: Span, value: bool) -> P<ast::Expr>;
self.expr_lit(sp, ast::LitKind::Int(u as u128,
ast::LitIntType::Unsigned(ast::UintTy::U32)))
}
+ fn expr_u16(&self, sp: Span, u: u16) -> P<ast::Expr> {
+ self.expr_lit(sp, ast::LitKind::Int(u as u128,
+ ast::LitIntType::Unsigned(ast::UintTy::U16)))
+ }
fn expr_u8(&self, sp: Span, u: u8) -> P<ast::Expr> {
self.expr_lit(sp, ast::LitKind::Int(u as u128, ast::LitIntType::Unsigned(ast::UintTy::U8)))
}
Some(kind.expect_from_annotatables(items))
}
AttrProcMacro(ref mac) => {
+ self.gate_proc_macro_attr_item(attr.span, &item);
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
Annotatable::Item(item) => token::NtItem(item),
Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()),
Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()),
Annotatable::Expr(expr) => token::NtExpr(expr),
})).into();
- let tok_result = mac.expand(self.cx, attr.span, attr.tokens, item_tok);
+ let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span);
+ let tok_result = mac.expand(self.cx, attr.span, input, item_tok);
self.parse_expansion(tok_result, kind, &attr.path, attr.span)
}
ProcMacroDerive(..) | BuiltinDerive(..) => {
}
}
+ fn extract_proc_macro_attr_input(&self, tokens: TokenStream, span: Span) -> TokenStream {
+ let mut trees = tokens.trees();
+ match trees.next() {
+ Some(TokenTree::Delimited(_, delim)) => {
+ if trees.next().is_none() {
+ return delim.tts.into()
+ }
+ }
+ Some(TokenTree::Token(..)) => {}
+ None => return TokenStream::empty(),
+ }
+ self.cx.span_err(span, "custom attribute invocations must be \
+ of the form #[foo] or #[foo(..)], the macro name must only be \
+ followed by a delimiter token");
+ TokenStream::empty()
+ }
+
+ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) {
+ let (kind, gate) = match *item {
+ Annotatable::Item(ref item) => {
+ match item.node {
+ ItemKind::Mod(_) if self.cx.ecfg.proc_macro_mod() => return,
+ ItemKind::Mod(_) => ("modules", "proc_macro_mod"),
+ _ => return,
+ }
+ }
+ Annotatable::TraitItem(_) => return,
+ Annotatable::ImplItem(_) => return,
+ Annotatable::ForeignItem(_) => return,
+ Annotatable::Stmt(_) |
+ Annotatable::Expr(_) if self.cx.ecfg.proc_macro_expr() => return,
+ Annotatable::Stmt(_) => ("statements", "proc_macro_expr"),
+ Annotatable::Expr(_) => ("expressions", "proc_macro_expr"),
+ };
+ emit_feature_err(
+ self.cx.parse_sess,
+ gate,
+ span,
+ GateIssue::Language,
+ &format!("custom attributes cannot be applied to {}", kind),
+ );
+ }
+
/// Expand a macro invocation. Returns the result of expansion.
fn expand_bang_invoc(&mut self,
invoc: Invocation,
self.cx.trace_macros_diag();
kind.dummy(span)
} else {
+ self.gate_proc_macro_expansion_kind(span, kind);
invoc.expansion_data.mark.set_expn_info(ExpnInfo {
call_site: span,
callee: NameAndSpan {
}
}
+ fn gate_proc_macro_expansion_kind(&self, span: Span, kind: ExpansionKind) {
+ let kind = match kind {
+ ExpansionKind::Expr => "expressions",
+ ExpansionKind::OptExpr => "expressions",
+ ExpansionKind::Pat => "patterns",
+ ExpansionKind::Ty => "types",
+ ExpansionKind::Stmts => "statements",
+ ExpansionKind::Items => return,
+ ExpansionKind::TraitItems => return,
+ ExpansionKind::ImplItems => return,
+ ExpansionKind::ForeignItems => return,
+ };
+ if self.cx.ecfg.proc_macro_non_items() {
+ return
+ }
+ emit_feature_err(
+ self.cx.parse_sess,
+ "proc_macro_non_items",
+ span,
+ GateIssue::Language,
+ &format!("procedural macros cannot be expanded to {}", kind),
+ );
+ }
+
/// Expand a derive invocation. Returns the result of expansion.
fn expand_derive_invoc(&mut self,
invoc: Invocation,
fn enable_custom_derive = custom_derive,
fn proc_macro_enabled = proc_macro,
fn macros_in_extern_enabled = macros_in_extern,
+ fn proc_macro_mod = proc_macro_mod,
+ fn proc_macro_expr = proc_macro_expr,
+ fn proc_macro_non_items = proc_macro_non_items,
}
}
($name: expr, $suffix: expr, $content: expr $(, $count: expr)*) => {{
let name = mk_name(cx, sp, ast::Ident::with_empty_ctxt($content));
let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![
- name $(, cx.expr_usize(sp, $count))*
+ name $(, cx.expr_u16(sp, $count))*
]);
let suffix = match $suffix {
Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
// allow `repr(simd)`, and importing the various simd intrinsics
(active, repr_simd, "1.4.0", Some(27731), None),
- // Allows cfg(target_feature = "...").
- (active, cfg_target_feature, "1.4.0", Some(29717), None),
-
// allow `extern "platform-intrinsic" { ... }`
(active, platform_intrinsics, "1.4.0", Some(27731), None),
// Allows cfg(target_has_atomic = "...").
(active, cfg_target_has_atomic, "1.9.0", Some(32976), None),
+ // The `!` type. Does not imply exhaustive_patterns (below) any more.
+ (active, never_type, "1.13.0", Some(35121), None),
+
// Allows exhaustive pattern matching on types that contain uninhabited types.
(active, exhaustive_patterns, "1.13.0", None, None),
(active, use_extern_macros, "1.15.0", Some(35896), None),
- // Allows #[target_feature(...)]
- (active, target_feature, "1.15.0", None, None),
-
// `extern "ptx-*" fn()`
(active, abi_ptx, "1.15.0", None, None),
// Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
(active, non_exhaustive, "1.22.0", Some(44109), None),
- // allow `'_` placeholder lifetimes
- (active, underscore_lifetimes, "1.22.0", Some(44524), None),
-
- // Default match binding modes (RFC 2005)
- (active, match_default_bindings, "1.22.0", Some(42640), None),
-
// Trait object syntax with `dyn` prefix
(active, dyn_trait, "1.22.0", Some(44662), Some(Edition::Edition2018)),
// Allows macro invocations in `extern {}` blocks
(active, macros_in_extern, "1.27.0", Some(49476), None),
+
+ // unstable #[target_feature] directives
+ (active, arm_target_feature, "1.27.0", None, None),
+ (active, aarch64_target_feature, "1.27.0", None, None),
+ (active, hexagon_target_feature, "1.27.0", None, None),
+ (active, powerpc_target_feature, "1.27.0", None, None),
+ (active, mips_target_feature, "1.27.0", None, None),
+ (active, avx512_target_feature, "1.27.0", None, None),
+ (active, mmx_target_feature, "1.27.0", None, None),
+ (active, sse4a_target_feature, "1.27.0", None, None),
+ (active, tbm_target_feature, "1.27.0", None, None),
+
+ // Allows macro invocations of the form `#[foo::bar]`
+ (active, proc_macro_path_invoc, "1.27.0", None, None),
+
+ // Allows macro invocations on modules expressions and statements and
+ // procedural macros to expand to non-items.
+ (active, proc_macro_mod, "1.27.0", None, None),
+ (active, proc_macro_expr, "1.27.0", None, None),
+ (active, proc_macro_non_items, "1.27.0", None, None),
+
+ // #[doc(alias = "...")]
+ (active, doc_alias, "1.27.0", Some(50146), None),
);
declare_features! (
(accepted, underscore_lifetimes, "1.26.0", Some(44524), None),
// Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
(accepted, generic_param_attrs, "1.26.0", Some(48848), None),
+ // Allows cfg(target_feature = "...").
+ (accepted, cfg_target_feature, "1.27.0", Some(29717), None),
+ // Allows #[target_feature(...)]
+ (accepted, target_feature, "1.27.0", None, None),
);
// If you change this, please modify src/doc/unstable-book as well. You must
"the `#[naked]` attribute \
is an experimental feature",
cfg_fn!(naked_functions))),
- ("target_feature", Whitelisted, Gated(
- Stability::Unstable, "target_feature",
- "the `#[target_feature]` attribute is an experimental feature",
- cfg_fn!(target_feature))),
+ ("target_feature", Normal, Ungated),
("export_name", Whitelisted, Ungated),
("inline", Whitelisted, Ungated),
("link", Whitelisted, Ungated),
// cfg(...)'s that are feature gated
const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
// (name in cfg, feature, function to check if the feature is enabled)
- ("target_feature", "cfg_target_feature", cfg_fn!(cfg_target_feature)),
("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
gate_feature_post!(&self, doc_spotlight, attr.span,
"#[doc(spotlight)] is experimental"
);
+ } else if content.iter().any(|c| c.check_name("alias")) {
+ gate_feature_post!(&self, doc_alias, attr.span,
+ "#[doc(alias = \"...\")] is experimental"
+ );
}
}
}
ast::TyKind::BareFn(ref bare_fn_ty) => {
self.check_abi(bare_fn_ty.abi, ty.span);
}
+ ast::TyKind::Never => {
+ gate_feature_post!(&self, never_type, ty.span,
+ "The `!` type is experimental");
+ }
ast::TyKind::TraitObject(_, ast::TraitObjectSyntax::Dyn) => {
gate_feature_post!(&self, dyn_trait, ty.span,
"`dyn Trait` syntax is unstable");
}
}
ast::TraitItemKind::Type(_, ref default) => {
- // We use two if statements instead of something like match guards so that both
- // of these errors can be emitted if both cases apply.
+ // We use three if statements instead of something like match guards so that all
+ // of these errors can be emitted if all cases apply.
if default.is_some() {
gate_feature_post!(&self, associated_type_defaults, ti.span,
"associated type defaults are unstable");
gate_feature_post!(&self, generic_associated_types, ti.span,
"generic associated types are unstable");
}
+ if !ti.generics.where_clause.predicates.is_empty() {
+ gate_feature_post!(&self, generic_associated_types, ti.span,
+ "where clauses on associated types are unstable");
+ }
}
_ => {}
}
Ok(ret_val)
}
- fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: usize) {
+ fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: u16) {
let mut err = self.struct_span_fatal(pos, pos, "unterminated raw string");
err.span_label(self.mk_sp(pos, pos), "unterminated raw string");
if hash_count > 0 {
err.note(&format!("this raw string should be terminated with `\"{}`",
- "#".repeat(hash_count)));
+ "#".repeat(hash_count as usize)));
}
err.emit();
FatalError.raise();
'r' => {
let start_bpos = self.pos;
self.bump();
- let mut hash_count = 0;
+ let mut hash_count: u16 = 0;
while self.ch_is('#') {
self.bump();
hash_count += 1;
'u' => {
assert_eq!(lit.as_bytes()[2], b'{');
let idx = lit.find('}').unwrap();
- let s = &lit[3..idx].chars().filter(|&c| c != '_').collect::<String>();
- let v = u32::from_str_radix(&s, 16).unwrap();
+
+ // All digits and '_' are ascii, so treat each byte as a char.
+ let mut v: u32 = 0;
+ for c in lit[3..idx].bytes() {
+ let c = char::from(c);
+ if c != '_' {
+ let x = c.to_digit(16).unwrap();
+ v = v.checked_mul(16).unwrap().checked_add(x).unwrap();
+ }
+ }
let c = char::from_u32(v).unwrap_or_else(|| {
if let Some((span, diag)) = diag {
let mut diag = diag.struct_span_err(span, "invalid unicode character escape");
self.token_cursor.next()
};
if next.sp == syntax_pos::DUMMY_SP {
- next.sp = self.prev_span;
+ // Tweak the location for better diagnostics, but keep syntactic context intact.
+ next.sp = self.prev_span.with_ctxt(next.sp.ctxt());
}
next
}
vis: Visibility,
attrs: Vec<Attribute> )
-> PResult<'a, StructField> {
+ let mut seen_comma: bool = false;
let a_var = self.parse_name_and_ty(lo, vis, attrs)?;
+ if self.token == token::Comma {
+ seen_comma = true;
+ }
match self.token {
token::Comma => {
self.bump();
}
token::CloseDelim(token::Brace) => {}
token::DocComment(_) => {
+ let previous_span = self.prev_span;
let mut err = self.span_fatal_err(self.span, Error::UselessDocComment);
self.bump(); // consume the doc comment
- if self.eat(&token::Comma) || self.token == token::CloseDelim(token::Brace) {
+ let comma_after_doc_seen = self.eat(&token::Comma);
+ // `seen_comma` is always false, because we are inside doc block
+ // condition is here to make code more readable
+ if seen_comma == false && comma_after_doc_seen == true {
+ seen_comma = true;
+ }
+ if comma_after_doc_seen || self.token == token::CloseDelim(token::Brace) {
err.emit();
} else {
+ if seen_comma == false {
+ let sp = self.sess.codemap().next_point(previous_span);
+ err.span_suggestion(sp, "missing comma here", ",".into());
+ }
return Err(err);
}
}
use tokenstream;
use std::{cmp, fmt};
+use std::mem;
use rustc_data_structures::sync::{Lrc, Lock};
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
Integer(ast::Name),
Float(ast::Name),
Str_(ast::Name),
- StrRaw(ast::Name, usize), /* raw str delimited by n hash symbols */
+ StrRaw(ast::Name, u16), /* raw str delimited by n hash symbols */
ByteStr(ast::Name),
- ByteStrRaw(ast::Name, usize), /* raw byte str delimited by n hash symbols */
+ ByteStrRaw(ast::Name, u16), /* raw byte str delimited by n hash symbols */
}
impl Lit {
ByteStr(_) | ByteStrRaw(..) => "byte string"
}
}
+
+ // See comments in `interpolated_to_tokenstream` for why we care about
+ // *probably* equal here rather than actual equality
+ fn probably_equal_for_proc_macro(&self, other: &Lit) -> bool {
+ mem::discriminant(self) == mem::discriminant(other)
+ }
}
pub(crate) fn ident_can_begin_expr(ident: ast::Ident, is_raw: bool) -> bool {
// stream they came from. Here we attempt to extract these
// lossless token streams before we fall back to the
// stringification.
- //
- // During early phases of the compiler, though, the AST could
- // get modified directly (e.g. attributes added or removed) and
- // the internal cache of tokens my not be invalidated or
- // updated. Consequently if the "lossless" token stream
- // disagrees with our actuall stringification (which has
- // historically been much more battle-tested) then we go with
- // the lossy stream anyway (losing span information).
let mut tokens = None;
match nt.0 {
let source = pprust::token_to_string(self);
parse_stream_from_source_str(FileName::MacroExpansion, source, sess, Some(span))
});
+
+ // During early phases of the compiler the AST could get modified
+ // directly (e.g. attributes added or removed) and the internal cache
+ // of tokens my not be invalidated or updated. Consequently if the
+ // "lossless" token stream disagrees with our actual stringification
+ // (which has historically been much more battle-tested) then we go
+ // with the lossy stream anyway (losing span information).
+ //
+ // Note that the comparison isn't `==` here to avoid comparing spans,
+ // but it *also* is a "probable" equality which is a pretty weird
+ // definition. We mostly want to catch actual changes to the AST
+ // like a `#[cfg]` being processed or some weird `macro_rules!`
+ // expansion.
+ //
+ // What we *don't* want to catch is the fact that a user-defined
+ // literal like `0xf` is stringified as `15`, causing the cached token
+ // stream to not be literal `==` token-wise (ignoring spans) to the
+ // token stream we got from stringification.
+ //
+ // Instead the "probably equal" check here is "does each token
+ // recursively have the same discriminant?" We basically don't look at
+ // the token values here and assume that such fine grained modifications
+ // of token streams doesn't happen.
if let Some(tokens) = tokens {
- if tokens.eq_unspanned(&tokens_for_real) {
+ if tokens.probably_equal_for_proc_macro(&tokens_for_real) {
return tokens
}
}
return tokens_for_real
}
+
+ // See comments in `interpolated_to_tokenstream` for why we care about
+ // *probably* equal here rather than actual equality
+ pub fn probably_equal_for_proc_macro(&self, other: &Token) -> bool {
+ if mem::discriminant(self) != mem::discriminant(other) {
+ return false
+ }
+ match (self, other) {
+ (&Eq, &Eq) |
+ (&Lt, &Lt) |
+ (&Le, &Le) |
+ (&EqEq, &EqEq) |
+ (&Ne, &Ne) |
+ (&Ge, &Ge) |
+ (&Gt, &Gt) |
+ (&AndAnd, &AndAnd) |
+ (&OrOr, &OrOr) |
+ (&Not, &Not) |
+ (&Tilde, &Tilde) |
+ (&At, &At) |
+ (&Dot, &Dot) |
+ (&DotDot, &DotDot) |
+ (&DotDotDot, &DotDotDot) |
+ (&DotDotEq, &DotDotEq) |
+ (&DotEq, &DotEq) |
+ (&Comma, &Comma) |
+ (&Semi, &Semi) |
+ (&Colon, &Colon) |
+ (&ModSep, &ModSep) |
+ (&RArrow, &RArrow) |
+ (&LArrow, &LArrow) |
+ (&FatArrow, &FatArrow) |
+ (&Pound, &Pound) |
+ (&Dollar, &Dollar) |
+ (&Question, &Question) |
+ (&Whitespace, &Whitespace) |
+ (&Comment, &Comment) |
+ (&Eof, &Eof) => true,
+
+ (&BinOp(a), &BinOp(b)) |
+ (&BinOpEq(a), &BinOpEq(b)) => a == b,
+
+ (&OpenDelim(a), &OpenDelim(b)) |
+ (&CloseDelim(a), &CloseDelim(b)) => a == b,
+
+ (&DocComment(a), &DocComment(b)) |
+ (&Shebang(a), &Shebang(b)) => a == b,
+
+ (&Lifetime(a), &Lifetime(b)) => a.name == b.name,
+ (&Ident(a, b), &Ident(c, d)) => a.name == c.name && b == d,
+
+ (&Literal(ref a, b), &Literal(ref c, d)) => {
+ b == d && a.probably_equal_for_proc_macro(c)
+ }
+
+ (&Interpolated(_), &Interpolated(_)) => false,
+
+ _ => panic!("forgot to add a token?"),
+ }
+ }
}
#[derive(Clone, RustcEncodable, RustcDecodable, Eq, Hash)]
token::Integer(c) => c.to_string(),
token::Str_(s) => format!("\"{}\"", s),
token::StrRaw(s, n) => format!("r{delim}\"{string}\"{delim}",
- delim=repeat("#", n),
+ delim=repeat("#", n as usize),
string=s),
token::ByteStr(v) => format!("b\"{}\"", v),
token::ByteStrRaw(s, n) => format!("br{delim}\"{string}\"{delim}",
- delim=repeat("#", n),
+ delim=repeat("#", n as usize),
string=s),
};
}
ast::StrStyle::Raw(n) => {
(format!("r{delim}\"{string}\"{delim}",
- delim=repeat("#", n),
+ delim=repeat("#", n as usize),
string=st))
}
};
&["std"]
};
- for name in names {
+ // .rev() to preserve ordering above in combination with insert(0, ...)
+ for name in names.iter().rev() {
krate.module.items.insert(0, P(ast::Item {
attrs: vec![attr::mk_attr_outer(DUMMY_SP,
attr::mk_attr_id(),
}
}
+ // See comments in `interpolated_to_tokenstream` for why we care about
+ // *probably* equal here rather than actual equality
+ //
+ // This is otherwise the same as `eq_unspanned`, only recursing with a
+ // different method.
+ pub fn probably_equal_for_proc_macro(&self, other: &TokenTree) -> bool {
+ match (self, other) {
+ (&TokenTree::Token(_, ref tk), &TokenTree::Token(_, ref tk2)) => {
+ tk.probably_equal_for_proc_macro(tk2)
+ }
+ (&TokenTree::Delimited(_, ref dl), &TokenTree::Delimited(_, ref dl2)) => {
+ dl.delim == dl2.delim &&
+ dl.stream().probably_equal_for_proc_macro(&dl2.stream())
+ }
+ (_, _) => false,
+ }
+ }
+
/// Retrieve the TokenTree's span.
pub fn span(&self) -> Span {
match *self {
t1.next().is_none() && t2.next().is_none()
}
+ // See comments in `interpolated_to_tokenstream` for why we care about
+ // *probably* equal here rather than actual equality
+ //
+ // This is otherwise the same as `eq_unspanned`, only recursing with a
+ // different method.
+ pub fn probably_equal_for_proc_macro(&self, other: &TokenStream) -> bool {
+ let mut t1 = self.trees();
+ let mut t2 = other.trees();
+ for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
+ if !t1.probably_equal_for_proc_macro(&t2) {
+ return false;
+ }
+ }
+ t1.next().is_none() && t2.next().is_none()
+ }
+
/// Precondition: `self` consists of a single token tree.
/// Returns true if the token tree is a joint operation w.r.t. `proc_macro::TokenNode`.
pub fn as_tree(self) -> (TokenTree, bool /* joint? */) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Machinery for hygienic macros, inspired by the MTWT[1] paper.
+//! Machinery for hygienic macros, inspired by the `MTWT[1]` paper.
//!
-//! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012.
+//! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012.
//! *Macros that work together: Compile-time bindings, partial expansion,
//! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
//! DOI=10.1017/S0956796812000093 <http://dx.doi.org/10.1017/S0956796812000093>
(46, Offsetof, "offsetof")
(47, Override, "override")
(48, Priv, "priv")
- (49, Proc, "proc")
- (50, Pure, "pure")
- (51, Sizeof, "sizeof")
- (52, Typeof, "typeof")
- (53, Unsized, "unsized")
- (54, Virtual, "virtual")
- (55, Yield, "yield")
+ (49, Pure, "pure")
+ (50, Sizeof, "sizeof")
+ (51, Typeof, "typeof")
+ (52, Unsized, "unsized")
+ (53, Virtual, "virtual")
+ (54, Yield, "yield")
// Special lifetime names
- (56, UnderscoreLifetime, "'_")
- (57, StaticLifetime, "'static")
+ (55, UnderscoreLifetime, "'_")
+ (56, StaticLifetime, "'static")
// Weak keywords, have special meaning only in specific contexts.
- (58, Auto, "auto")
- (59, Catch, "catch")
- (60, Default, "default")
- (61, Dyn, "dyn")
- (62, Union, "union")
+ (57, Auto, "auto")
+ (58, Catch, "catch")
+ (59, Default, "default")
+ (60, Dyn, "dyn")
+ (61, Union, "union")
}
// If an interner exists, return it. Otherwise, prepare a fresh one.
pub fn filter_tests(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> Vec<TestDescAndFn> {
let mut filtered = tests;
-
// Remove tests that don't match the test filter
filtered = match opts.filter {
None => filtered,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-/// A macro for defining #[cfg] if-else statements.
+/// A macro for defining `#[cfg]` if-else statements.
///
/// This is similar to the `if/elif` C preprocessor macro by allowing definition
/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
/// first.
///
-/// This allows you to conveniently provide a long list #[cfg]'d blocks of code
+/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code
/// without having to rewrite each clause multiple times.
macro_rules! cfg_if {
($(
extern crate rustc_driver;
-fn main() { rustc_driver::main() }
+fn main() {
+ rustc_driver::set_sigpipe_handler();
+ rustc_driver::main()
+}
-Subproject commit bcb720e55861c38db47f2ebdf26b7198338cb39d
+Subproject commit 1ea18a5cb431e24aa838b652ac305acc5e394d6b
// aux-build:nounwind.rs
// compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a
// ignore-windows
+// ignore-android
#![crate_type = "lib"]
//! Attributes producing expressions in invalid locations
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(proc_macro, stmt_expr_attributes, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{duplicate, no_output};
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr};
fn test1() {
let a: i32 = "foo";
//~^ ERROR: mismatched types
+ let b: i32 = "f'oo";
+ //~^ ERROR: mismatched types
}
fn test2() {
// aux-build:attributes-included.rs
// ignore-stage1
-#![feature(proc_macro, rustc_attrs)]
+#![feature(proc_macro, rustc_attrs, proc_macro_path_invoc)]
#![warn(unused)]
extern crate attributes_included;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+// force-host
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn m(a: TokenStream) -> TokenStream {
+ a
+}
+
+#[proc_macro_attribute]
+pub fn a(_a: TokenStream, b: TokenStream) -> TokenStream {
+ b
+}
// aux-build:bang_proc_macro2.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![allow(unused_macros)]
extern crate bang_proc_macro2;
// aux-build:bang_proc_macro.rs
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#[macro_use]
extern crate bang_proc_macro;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:proc-macro-gates.rs
+// gate-test-proc_macro_non_items
+// gate-test-proc_macro_path_invoc
+// gate-test-proc_macro_mod line
+// gate-test-proc_macro_expr
+// gate-test-proc_macro_mod
+
+#![feature(proc_macro, stmt_expr_attributes)]
+
+extern crate proc_macro_gates as foo;
+
+use foo::*;
+
+#[foo::a] //~ ERROR: paths of length greater than one
+fn _test() {}
+
+#[a] //~ ERROR: custom attributes cannot be applied to modules
+mod _test2 {}
+
+#[a = y] //~ ERROR: must only be followed by a delimiter token
+fn _test3() {}
+
+#[a = ] //~ ERROR: must only be followed by a delimiter token
+fn _test4() {}
+
+#[a () = ] //~ ERROR: must only be followed by a delimiter token
+fn _test5() {}
+
+fn main() {
+ #[a] //~ ERROR: custom attributes cannot be applied to statements
+ let _x = 2;
+ let _x = #[a] 2;
+ //~^ ERROR: custom attributes cannot be applied to expressions
+
+ let _x: m!(u32) = 3;
+ //~^ ERROR: procedural macros cannot be expanded to types
+ if let m!(Some(_x)) = Some(3) {
+ //~^ ERROR: procedural macros cannot be expanded to patterns
+ }
+ let _x = m!(3);
+ //~^ ERROR: procedural macros cannot be expanded to expressions
+ m!(let _x = 3;);
+ //~^ ERROR: procedural macros cannot be expanded to statements
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:proc-macro-gates.rs
+
+#![feature(proc_macro, stmt_expr_attributes)]
+
+extern crate proc_macro_gates as foo;
+
+use foo::*;
+
+// NB. these errors aren't the best errors right now, but they're definitely
+// intended to be errors. Somehow using a custom attribute in these positions
+// should either require a feature gate or not be allowed on stable.
+
+fn _test6<#[a] T>() {}
+//~^ ERROR: unknown to the compiler
+
+fn _test7() {
+ match 1 {
+ #[a] //~ ERROR: unknown to the compiler
+ 0 => {}
+ _ => {}
+ }
+}
+
+fn main() {
+}
inside_closure(a)
};
outside_closure_1(a); //[ast]~ ERROR cannot borrow `*a` as mutable because previous closure requires unique access
- //[mir]~^ ERROR cannot borrow `*a` as mutable because previous closure requires unique access
+ //[mir]~^ ERROR cannot borrow `*a` as mutable because previous closure requires unique access
outside_closure_2(a); //[ast]~ ERROR cannot borrow `*a` as immutable because previous closure requires unique access
- //[mir]~^ ERROR cannot borrow `*a` as immutable because previous closure requires unique access
+ //[mir]~^ ERROR cannot borrow `*a` as immutable because previous closure requires unique access
+
+ drop(bar);
}
fn main() {
//~| the trait bound `usize:
//~| the trait bound `usize:
//~| the trait bound `usize:
-//~| the trait bound `usize:
fn main() {}
// ignore-sparc
// revisions: ast mir
-//[mir]compile-flags: -Z borrowck=mir -Z nll
+//[mir]compile-flags: -Z borrowck=mir
#![feature(asm)]
let mut x = 3;
let c1 = || x = 4;
let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x`
- //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+ //[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+ drop(c1);
}
fn b() {
let c1 = || set(&mut x);
let c2 = || get(&x); //[ast]~ ERROR cannot borrow `x`
//[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+ drop(c1);
}
fn c() {
let c1 = || set(&mut x);
let c2 = || x * 5; //[ast]~ ERROR cannot borrow `x`
//[mir]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
+ drop(c1);
}
fn d() {
let c2 = || x * 5;
x = 5; //[ast]~ ERROR cannot assign
//[mir]~^ ERROR cannot assign to `x` because it is borrowed
+ drop(c2);
}
fn e() {
let c1 = || get(&x);
x = 5; //[ast]~ ERROR cannot assign
//[mir]~^ ERROR cannot assign to `x` because it is borrowed
+ drop(c1);
}
fn f() {
let c1 = || get(&*x);
*x = 5; //[ast]~ ERROR cannot assign to `*x`
//[mir]~^ ERROR cannot assign to `*x` because it is borrowed
+ drop(c1);
}
fn g() {
let c1 = || get(&*x.f);
*x.f = 5; //[ast]~ ERROR cannot assign to `*x.f`
//[mir]~^ ERROR cannot assign to `*x.f` because it is borrowed
+ drop(c1);
}
fn h() {
let c1 = || get(&*x.f);
let c2 = || *x.f = 5; //[ast]~ ERROR cannot borrow `x` as mutable
//[mir]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+ drop(c1);
}
fn main() {
// Local and field from struct
{
let mut f = Foo { x: 22 };
- let _x = f.x();
+ let x = f.x();
f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed
- //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed
+ //[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed
+ drop(x);
}
// Local and field from tuple-struct
{
let mut g = Bar(22);
- let _0 = g.x();
+ let x = g.x();
g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed
//[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed
+ drop(x);
}
// Local and field from tuple
{
let mut h = (22, 23);
- let _0 = &mut h.0;
+ let x = &mut h.0;
h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed
//[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed
+ drop(x);
}
// Local and field from enum
{
let mut e = Baz::X(2);
- let _e0 = e.x();
+ let x = e.x();
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
Baz::X(value) => value
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
};
+ drop(x);
}
// Local and field from union
unsafe {
let mut u = U { b: 0 };
- let _ra = &mut u.a;
+ let x = &mut u.a;
u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
//[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed
+ drop(x);
}
// Deref and field from struct
{
let mut f = Box::new(Foo { x: 22 });
- let _x = f.x();
+ let x = f.x();
f.x; //[ast]~ ERROR cannot use `f.x` because it was mutably borrowed
//[mir]~^ ERROR cannot use `f.x` because it was mutably borrowed
+ drop(x);
}
// Deref and field from tuple-struct
{
let mut g = Box::new(Bar(22));
- let _0 = g.x();
+ let x = g.x();
g.0; //[ast]~ ERROR cannot use `g.0` because it was mutably borrowed
//[mir]~^ ERROR cannot use `g.0` because it was mutably borrowed
+ drop(x);
}
// Deref and field from tuple
{
let mut h = Box::new((22, 23));
- let _0 = &mut h.0;
+ let x = &mut h.0;
h.0; //[ast]~ ERROR cannot use `h.0` because it was mutably borrowed
//[mir]~^ ERROR cannot use `h.0` because it was mutably borrowed
+ drop(x);
}
// Deref and field from enum
{
let mut e = Box::new(Baz::X(3));
- let _e0 = e.x();
+ let x = e.x();
match *e { //[mir]~ ERROR cannot use `*e` because it was mutably borrowed
Baz::X(value) => value
//[ast]~^ ERROR cannot use `e.0` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `e.0` because it was mutably borrowed
};
+ drop(x);
}
// Deref and field from union
unsafe {
let mut u = Box::new(U { b: 0 });
- let _ra = &mut u.a;
+ let x = &mut u.a;
u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
//[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed
+ drop(x);
}
// Constant index
{
let mut v = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
- let _v = &mut v;
+ let x = &mut v;
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[x, _, .., _, _] => println!("{}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
+ drop(x);
}
// Subslices
{
let mut v = &[1, 2, 3, 4, 5];
- let _v = &mut v;
+ let x = &mut v;
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[x..] => println!("{:?}", x),
//[ast]~^ ERROR cannot use `v[..]` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..]` because it was mutably borrowed
_ => panic!("other case"),
}
+ drop(x);
}
// Downcasted field
{
enum E<X> { A(X), B { x: X } }
let mut e = E::A(3);
- let _e = &mut e;
+ let x = &mut e;
match e { //[mir]~ ERROR cannot use `e` because it was mutably borrowed
E::A(ref ax) =>
//[ast]~^ ERROR cannot borrow `e.0` as immutable because `e` is also borrowed as mutable
//[mir]~^^ ERROR cannot borrow `e.x` as immutable because it is also borrowed as mutable
println!("e.bx: {:?}", bx),
}
+ drop(x);
}
// Field in field
{
struct F { x: u32, y: u32 };
struct S { x: F, y: (u32, u32), };
let mut s = S { x: F { x: 1, y: 2}, y: (999, 998) };
- let _s = &mut s;
+ let x = &mut s;
match s { //[mir]~ ERROR cannot use `s` because it was mutably borrowed
S { y: (ref y0, _), .. } =>
//[ast]~^ ERROR cannot borrow `s.y.0` as immutable because `s` is also borrowed as mutable
println!("x0: {:?}", x0),
_ => panic!("other case"),
}
+ drop(x);
}
// Field of ref
{
let p: &'a u8 = &*block.current;
//[mir]~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable
// No errors in AST because of issue rust#38899
+ drop(x);
}
}
// Field of ptr
let p : *const u8 = &*(*block).current;
//[mir]~^ ERROR cannot borrow `*block.current` as immutable because it is also borrowed as mutable
// No errors in AST because of issue rust#38899
+ drop(x);
}
}
// Field of index
{
struct F {x: u32, y: u32};
let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
- let _v = &mut v;
+ let x = &mut v;
v[0].y;
//[ast]~^ ERROR cannot use `v[..].y` because it was mutably borrowed
//[mir]~^^ ERROR cannot use `v[..].y` because it was mutably borrowed
//[mir]~| ERROR cannot use `*v` because it was mutably borrowed
+ drop(x);
}
// Field of constant index
{
struct F {x: u32, y: u32};
let mut v = &[F{x: 1, y: 2}, F{x: 3, y: 4}];
- let _v = &mut v;
+ let x = &mut v;
match v { //[mir]~ ERROR cannot use `v` because it was mutably borrowed
&[_, F {x: ref xf, ..}] => println!("{}", xf),
//[mir]~^ ERROR cannot borrow `v[..].x` as immutable because it is also borrowed as mutable
// No errors in AST
_ => panic!("other case")
}
+ drop(x);
}
// Field from upvar
{
}
// Field from upvar nested
{
+ // FIXME(#49824) -- the free region error below should probably not be there
let mut x = 0;
|| {
- || {
- let y = &mut x;
- &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
- //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
- *y = 1;
+ || { //[mir]~ ERROR free region `` does not outlive
+ let y = &mut x;
+ &mut x; //[ast]~ ERROR cannot borrow `**x` as mutable more than once at a time
+ //[mir]~^ ERROR cannot borrow `x` as mutable more than once at a time
+ *y = 1;
+ drop(y);
}
};
}
fn main() {
let mut _a = 3;
- let _b = &mut _a;
+ let b = &mut _a;
{
- let _c = &*_b;
+ let c = &*b;
_a = 4; //[ast]~ ERROR cannot assign to `_a`
- //[mir]~^ ERROR cannot assign to `_a` because it is borrowed
+ //[mir]~^ ERROR cannot assign to `_a` because it is borrowed
+ drop(c);
}
+ drop(b);
}
// fact no outstanding loan of x!
x = Some(0);
}
- Some(ref __isize) => {
+ Some(ref r) => {
x = Some(1); //[ast]~ ERROR cannot assign
- //[mir]~^ ERROR cannot assign to `x` because it is borrowed
+ //[mir]~^ ERROR cannot assign to `x` because it is borrowed
+ drop(r);
}
}
x.clone(); // just to prevent liveness warnings
Foo::A(x) => x //[ast]~ ERROR [E0503]
//[mir]~^ ERROR [E0503]
};
+ drop(p);
}
fn main() {
let mut x = 1;
- let _x = &mut x;
+ let r = &mut x;
let _ = match x { //[mir]~ ERROR [E0503]
x => x + 1, //[ast]~ ERROR [E0503]
//[mir]~^ ERROR [E0503]
y => y + 2, //[ast]~ ERROR [E0503]
//[mir]~^ ERROR [E0503]
};
+ drop(r);
}
fn main() {
let mut x = 1;
- let mut addr;
+ let mut addr = vec![];
loop {
match 1 {
- 1 => { addr = &mut x; } //[ast]~ ERROR [E0499]
+ 1 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
//[mir]~^ ERROR [E0499]
- 2 => { addr = &mut x; } //[ast]~ ERROR [E0499]
+ 2 => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
//[mir]~^ ERROR [E0499]
- _ => { addr = &mut x; } //[ast]~ ERROR [E0499]
+ _ => { addr.push(&mut x); } //[ast]~ ERROR [E0499]
//[mir]~^ ERROR [E0499]
}
}
s[2] = 20;
//[ast]~^ ERROR cannot assign to immutable indexed content
//[mir]~^^ ERROR cannot assign to immutable item
+ drop(rs);
}
Some(ref i) => {
// But on this branch, `i` is an outstanding borrow
x = Some(*i+1); //[ast]~ ERROR cannot assign to `x`
- //[mir]~^ ERROR cannot assign to `x` because it is borrowed
+ //[mir]~^ ERROR cannot assign to `x` because it is borrowed
+ drop(i);
}
}
x.clone(); // just to prevent liveness warnings
{
let ra = &u.a;
let ra2 = &u.a; // OK
+ drop(ra);
}
{
let ra = &u.a;
let a = u.a; // OK
+ drop(ra);
}
{
let ra = &u.a;
let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
//[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
+ drop(ra);
}
{
let ra = &u.a;
u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
+ drop(ra);
}
// Imm borrow, other field
{
let ra = &u.a;
let rb = &u.b; // OK
+ drop(ra);
}
{
let ra = &u.a;
let b = u.b; // OK
+ drop(ra);
}
{
let ra = &u.a;
let rmb = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
//[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable
+ drop(ra);
}
{
let ra = &u.a;
u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
+ drop(ra);
}
// Mut borrow, same field
{
let rma = &mut u.a;
let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
//[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
+ drop(rma);
}
{
let ra = &mut u.a;
let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
//[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed
+ drop(ra);
}
{
let rma = &mut u.a;
let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time
//[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time
+ drop(rma);
}
{
let rma = &mut u.a;
u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
+ drop(rma);
}
// Mut borrow, other field
{
let rma = &mut u.a;
let rb = &u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
//[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable
+ drop(rma);
}
{
let ra = &mut u.a;
let b = u.b; //[ast]~ ERROR cannot use `u.b` because it was mutably borrowed
//[mir]~^ ERROR cannot use `u.b` because it was mutably borrowed
+ drop(ra);
}
{
let rma = &mut u.a;
let rmb2 = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
//[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time
+ drop(rma);
}
{
let rma = &mut u.a;
u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
+ drop(rma);
}
}
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that a borrow which starts as a 2-phase borrow and gets
+// carried around a loop winds up conflicting with itself.
+
+#![feature(nll)]
+
+struct Foo { x: String }
+
+impl Foo {
+ fn get_string(&mut self) -> &str {
+ &self.x
+ }
+}
+
+fn main() {
+ let mut foo = Foo { x: format!("Hello, world") };
+ let mut strings = vec![];
+
+ loop {
+ strings.push(foo.get_string()); //~ ERROR cannot borrow `foo` as mutable
+ if strings.len() > 2 { break; }
+ }
+
+ println!("{:?}", strings);
+}
// revisions: nll_target
// The following revisions are disabled due to missing support from two-phase beyond autorefs
-//[lxl_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
-//[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref -Z nll
+//[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
-//[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+//[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows
// This is an important corner case pointed out by Niko: one is
// allowed to initiate a shared borrow during a reservation, but it
// revisions: nll_target
// The following revisions are disabled due to missing support for two_phase_beyond_autoref
-//[lxl_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two_phase_beyond_autoref
-//[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two_phase_beyond_autoref -Z nll
+//[nll_beyond] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two_phase_beyond_autoref
-
-//[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+//[nll_target] compile-flags: -Z borrowck=mir -Z two-phase-borrows
// This is the second counter-example from Niko's blog post
// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
/*3*/ *p += 1; // (mutable borrow of `i` starts here, since `p` is used)
- /*4*/ let k = i; //[lxl_beyond]~ ERROR cannot use `i` because it was mutably borrowed [E0503]
- //[nll_beyond]~^ ERROR cannot use `i` because it was mutably borrowed [E0503]
- //[nll_target]~^^ ERROR cannot use `i` because it was mutably borrowed [E0503]
+ /*4*/ let k = i; //[nll_beyond]~ ERROR cannot use `i` because it was mutably borrowed [E0503]
+ //[nll_target]~^ ERROR cannot use `i` because it was mutably borrowed [E0503]
/*5*/ *p += 1;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lxl nll
-//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+// compile-flags: -Z borrowck=mir -Z two-phase-borrows
// This is the third counter-example from Niko's blog post
// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
vec.get({
vec.push(2);
- //[lxl]~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
- //[nll]~^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
+ //~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
0
});
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: ast lxl nll
+// revisions: ast nll
//[ast]compile-flags:
-//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[g2p]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll -Z two-phase-beyond-autoref
+//[g2p]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
// the above revision is disabled until two-phase-beyond-autoref support is better
// This is a test checking that when we limit two-phase borrows to
fn twice_ten_sm<F: FnMut(i32) -> i32>(f: &mut F) {
f(f(10));
- //[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
- //[nll]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
- //[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
- //[ast]~^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[nll]~^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[g2p]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[ast]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
}
fn twice_ten_si<F: Fn(i32) -> i32>(f: &mut F) {
f(f(10));
}
fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
f(f(10));
- //[lxl]~^ ERROR use of moved value: `*f`
- //[nll]~^^ ERROR use of moved value: `*f`
- //[g2p]~^^^ ERROR use of moved value: `*f`
- //[ast]~^^^^ ERROR use of moved value: `*f`
+ //[nll]~^ ERROR use of moved value: `*f`
+ //[g2p]~^^ ERROR use of moved value: `*f`
+ //[ast]~^^^ ERROR use of moved value: `*f`
}
fn twice_ten_om(f: &mut FnMut(i32) -> i32) {
f(f(10));
- //[lxl]~^ ERROR cannot borrow `*f` as mutable more than once at a time
- //[nll]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
- //[g2p]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
- //[ast]~^^^^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[nll]~^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[g2p]~^^ ERROR cannot borrow `*f` as mutable more than once at a time
+ //[ast]~^^^ ERROR cannot borrow `*f` as mutable more than once at a time
}
fn twice_ten_oi(f: &mut Fn(i32) -> i32) {
f(f(10));
}
fn twice_ten_oo(f: Box<FnOnce(i32) -> i32>) {
f(f(10));
- //[lxl]~^ ERROR cannot move a value of type
- //[lxl]~^^ ERROR cannot move a value of type
- //[lxl]~^^^ ERROR use of moved value: `*f`
- //[nll]~^^^^ ERROR cannot move a value of type
- //[nll]~^^^^^ ERROR cannot move a value of type
- //[nll]~^^^^^^ ERROR use of moved value: `*f`
- //[g2p]~^^^^^^^ ERROR cannot move a value of type
- //[g2p]~^^^^^^^^ ERROR cannot move a value of type
- //[g2p]~^^^^^^^^^ ERROR use of moved value: `*f`
- //[ast]~^^^^^^^^^^ ERROR use of moved value: `*f`
+ //[nll]~^ ERROR cannot move a value of type
+ //[nll]~^^ ERROR cannot move a value of type
+ //[nll]~^^^ ERROR use of moved value: `*f`
+ //[g2p]~^^^^ ERROR cannot move a value of type
+ //[g2p]~^^^^^ ERROR cannot move a value of type
+ //[g2p]~^^^^^^ ERROR use of moved value: `*f`
+ //[ast]~^^^^^^^ ERROR use of moved value: `*f`
}
twice_ten_sm(&mut |x| x + 1);
// This is not okay.
double_access(&mut a, &a);
- //[lxl]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
- //[nll]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
- //[g2p]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
- //[ast]~^^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ //[nll]~^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ //[g2p]~^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
+ //[ast]~^^^ ERROR cannot borrow `a` as immutable because it is also borrowed as mutable [E0502]
// But this is okay.
a.m(a.i(10));
fn coerce_index_op() {
let mut i = I(10);
i[i[3]] = 4;
- //[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
- //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
- //[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[nll]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[ast]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
i[3] = i[4];
i[i[3]] = i[4];
- //[lxl]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
- //[nll]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
- //[ast]~^^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[nll]~^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
+ //[ast]~^^ ERROR cannot borrow `i` as immutable because it is also borrowed as mutable [E0502]
}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lxl nll
-//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+// compile-flags: -Z borrowck=mir -Z two-phase-borrows
// This is similar to two-phase-reservation-sharing-interference.rs
// in that it shows a reservation that overlaps with a shared borrow.
#![feature(rustc_attrs)]
#[rustc_error]
-fn main() { //[nll]~ ERROR compilation successful
+fn main() { //~ ERROR compilation successful
let mut v = vec![0, 1, 2];
let shared = &v;
v.push(shared.len());
- //[lxl]~^ ERROR cannot borrow `v` as mutable because it is also borrowed as immutable [E0502]
assert_eq!(v, [0, 1, 2, 3]);
}
// ignore-tidy-linelength
-// revisions: lxl_beyond nll_beyond nll_target
+// revisions: nll_beyond nll_target
// The following revisions are disabled due to missing support from two-phase beyond autorefs
-//[lxl_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
-//[lxl_beyond] should-fail
-//[nll_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref -Z nll
+//[nll_beyond]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z two-phase-beyond-autoref
//[nll_beyond] should-fail
-//[nll_target]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+//[nll_target]compile-flags: -Z borrowck=mir -Z two-phase-borrows
// This is a corner case that the current implementation is (probably)
// treating more conservatively than is necessary. But it also does
// with the shared borrow. But in the current implementation,
// its an error.
delay = &mut vec;
- //[lxl_beyond]~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
- //[nll_beyond]~^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
- //[nll_target]~^^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
+ //[nll_beyond]~^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
+ //[nll_target]~^^ ERROR cannot borrow `vec` as mutable because it is also borrowed as immutable
shared[0];
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lxl nll
-//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+// cmpile-flags: -Z borrowck=mir -Z two-phase-borrows
// This is the first counter-example from Niko's blog post
// smallcultfollowing.com/babysteps/blog/2017/03/01/nested-method-calls-via-two-phase-borrowing/
v[0].push_str({
v.push(format!("foo"));
- //[lxl]~^ ERROR cannot borrow `v` as mutable more than once at a time [E0499]
- //[nll]~^^ ERROR cannot borrow `v` as mutable more than once at a time [E0499]
+ //~^ ERROR cannot borrow `v` as mutable more than once at a time [E0499]
"World!"
});
// Test that we can't pass other types for !
+#![feature(never_type)]
+
fn foo(x: !) -> ! {
x
}
let z = borrow_mut(x);
//[ast]~^ ERROR cannot borrow `*x` as mutable more than once at a time
//[mir]~^^ ERROR cannot borrow `*x` as mutable more than once at a time
+ drop((y, z));
}
fn double_imm_borrow(x: &mut Box<i32>) {
**x += 1;
//[ast]~^ ERROR cannot assign to `**x` because it is borrowed
//[mir]~^^ ERROR cannot assign to `**x` because it is borrowed
+ drop((y, z));
}
fn double_mut_borrow2<T>(x: &mut Box<T>) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
fn foo(x: usize, y: !, z: usize) { }
fn cast_a() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
fn foo(x: usize, y: !, z: usize) { }
fn call_foo_a() {
#![feature(specialization)]
trait Trait<T> { type Assoc; }
-//~^ cyclic dependency detected [E0391]
+//~^ cycle detected
impl<T> Trait<T> for Vec<T> {
type Assoc = ();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: cyclic dependency detected
+// error-pattern: cycle detected
#![feature(const_fn)]
struct A<T>
where T : Trait,
T : Add<T::Item>
- //~^ ERROR cyclic dependency detected
+ //~^ ERROR cycle detected
//~| ERROR associated type `Item` not found for `T`
{
data: T
// again references the trait.
trait Foo<X = Box<Foo>> {
- //~^ ERROR cyclic dependency detected
+ //~^ ERROR cycle detected
}
fn main() { }
// Test a supertrait cycle where a trait extends itself.
trait Chromosome: Chromosome {
- //~^ ERROR cyclic dependency detected
+ //~^ ERROR cycle detected
}
fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// We need to opt inot the `!` feature in order to trigger the
+// requirement that this is testing.
+#![feature(never_type)]
+
#![allow(unused)]
trait Deserialize: Sized {
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Zedition=2015 -Zunstable-options
+// compile-flags: --edition=2015 -Zunstable-options
// tests that editions work with the tyvar warning-turned-error
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: -Zedition=2018 -Zunstable-options
+// compile-flags: --edition=2018 -Zunstable-options
// tests that editions work with the tyvar warning-turned-error
// #41719
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
fn main() {
enum Foo {}
f.call(&x);
f.call(&x);
x = 5;
+ drop(y);
}
fn main() {
// except according to those terms.
type x = Vec<x>;
-//~^ ERROR cyclic dependency detected
+//~^ ERROR cycle detected
fn main() { let b: x = Vec::new(); }
// error-pattern:reached recursion limit
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
struct Foo<'a, T: 'a> {
// except according to those terms.
trait T : Iterator<Item=Self::Item>
-//~^ ERROR cyclic dependency detected
+//~^ ERROR cycle detected
//~| ERROR associated type `Item` not found for `Self`
{}
}
pub trait Processor: Subscriber<Input = Self::Input> {
- //~^ ERROR cyclic dependency detected [E0391]
+ //~^ ERROR cycle detected
type Input;
}
}
fn foo<T: Trait<A = T::B>>() { }
-//~^ ERROR cyclic dependency detected
+//~^ ERROR cycle detected
//~| ERROR associated type `B` not found for `T`
fn main() { }
// except according to those terms.
trait Expr : PartialEq<Self::Item> {
- //~^ ERROR: cyclic dependency detected
+ //~^ ERROR: cycle detected
type Item;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: cyclic dependency detected
-// note-pattern: the cycle begins when computing layout of
-// note-pattern: ...which then requires computing layout of
-// note-pattern: ...which then again requires computing layout of
-
+// error-pattern: cycle detected when computing layout of
+// note-pattern: ...which requires computing layout of
+// note-pattern: ...which again requires computing layout of
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
fn foo(_: T) {}
}
-pub struct Foo<T = Box<Trait<DefaultFoo>>>;
-type DefaultFoo = Foo; //~ ERROR cyclic dependency detected
+pub struct Foo<T = Box<Trait<DefaultFoo>>>; //~ ERROR cycle detected
+type DefaultFoo = Foo;
fn main() {
}
// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir
+// FIXME(#49821) -- No tip about using a let binding
+
use std::cell::RefCell;
fn main() {
//[ast]~| NOTE temporary value does not live long enough
//[ast]~| NOTE consider using a `let` binding to increase its lifetime
//[mir]~^^^^^ ERROR borrowed value does not live long enough [E0597]
- //[mir]~| NOTE temporary value dropped here while still borrowed
//[mir]~| NOTE temporary value does not live long enough
- //[mir]~| NOTE consider using a `let` binding to increase its lifetime
+ //[mir]~| NOTE temporary value only lives until here
println!("{}", val);
+ //[mir]~^ borrow later used here
}
//[ast]~^ NOTE temporary value needs to live until here
-//[mir]~^^ NOTE temporary value needs to live until here
fn xyz() -> u8 { 42 }
const NUM: u8 = xyz();
-//~^ ERROR calls in constants are limited to constant functions, struct and enum constructors
+//~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants
//~| ERROR constant evaluation error
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// error-pattern: cycle detected when computing layout of
+
#![feature(const_fn)]
#![feature(core_intrinsics)]
struct Foo {
bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
- //~^ ERROR cyclic dependency detected
x: usize,
}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-trait Foo {
- const AMT: usize;
-}
-
-enum Bar<A, B> {
- First(A),
- Second(B),
-}
-
-impl<A: Foo, B: Foo> Foo for Bar<A, B> {
- const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
-}
-
-impl Foo for u8 {
- const AMT: usize = 1;
-}
-
-impl Foo for u16 {
- const AMT: usize = 2;
-}
-
-fn main() {
- println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ E0080
-}
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+
+// ignore-tidy-linelength
+
#![feature(const_fn)]
const bad : u32 = {
{
invalid();
//~^ ERROR: blocks in constants are limited to items and tail expressions
- //~^^ ERROR: calls in constants are limited to constant functions, struct and enum
+ //~^^ ERROR: calls in constants are limited to constant functions, tuple structs and tuple variants
0
}
};
{
invalid();
//~^ ERROR: blocks in statics are limited to items and tail expressions
- //~^^ ERROR: calls in statics are limited to constant functions, struct and enum
+ //~^^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
0
}
};
{
invalid();
//~^ ERROR: blocks in statics are limited to items and tail expressions
- //~^^ ERROR: calls in statics are limited to constant functions, struct and enum
+ //~^^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
0
}
};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
fn main() {
let val: ! = loop { break break; };
//~^ ERROR mismatched types
// gate-test-use_extern_macros
+#![feature(proc_macro_path_invoc)]
+
fn main() {
globnar::brotz!(); //~ ERROR non-ident macro paths are experimental
#[derive(foo::Bar)] struct T; //~ ERROR non-ident macro paths are experimental
#![feature(asm)]
#![feature(trace_macros, concat_idents)]
+#![feature(proc_macro_path_invoc)]
#[derive(Default)] //~ ERROR
enum OrDeriveThis {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
mod private {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z borrowck=mir -Z nll
+// compile-flags: -Z borrowck=mir
#![allow(dead_code)]
let g: fn(_, _) -> _ = |_x, y| y;
//~^ ERROR free region `'b` does not outlive free region `'a`
g
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z borrowck=mir -Z nll
+// compile-flags: -Zborrowck=mir
#![allow(dead_code)]
// The MIR type checker must therefore relate `'?0` to `'?1` and `'?2`
// as part of checking the `ReifyFnPointer`.
let f: fn(_) -> _ = foo;
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR free region `'a` does not outlive free region `'static`
f(x)
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z borrowck=mir -Z nll
+// compile-flags: -Zborrowck=mir
#![allow(dead_code)]
// Here the NLL checker must relate the types in `f` to the types
// in `g`. These are related via the `UnsafeFnPointer` cast.
let g: unsafe fn(_) -> _ = f;
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR free region `'a` does not outlive free region `'static`
unsafe { g(input) }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z borrowck=mir -Z nll
+// compile-flags: -Z borrowck=mir
#![allow(dead_code)]
#![feature(dyn_trait)]
fn bar<'a>(x: &'a u32) -> &'static dyn Debug {
//~^ ERROR free region `'a` does not outlive free region `'static`
x
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
}
fn main() {}
// check borrowing is detected successfully
let &mut ref x = foo;
*foo += 1; //[ast]~ ERROR cannot assign to `*foo` because it is borrowed
- //[mir]~^ ERROR cannot assign to `*foo` because it is borrowed
+ //[mir]~^ ERROR cannot assign to `*foo` because it is borrowed
+ drop(x);
}
// Test that an assignment of type ! makes the rest of the block dead code.
+#![feature(never_type)]
#![feature(rustc_attrs)]
#![warn(unused)]
// Test that we can't use another type in place of !
+#![feature(never_type)]
#![deny(warnings)]
fn main() {
// except according to those terms.
-// compile-flags:-Zborrowck=compare -Znll
+// compile-flags:-Zborrowck=compare
#![allow(warnings)]
#![feature(rustc_attrs)]
// except according to those terms.
-// compile-flags:-Zborrowck=compare -Znll
+// compile-flags:-Zborrowck=compare
#![allow(warnings)]
#![feature(rustc_attrs)]
// except according to those terms.
//revisions: ast mir
-//[mir] compile-flags: -Z borrowck=mir -Z nll
+//[mir] compile-flags: -Z borrowck=mir
#![allow(unused_assignments)]
// in the type of `p` includes the points after `&v[0]` up to (but not
// including) the call to `use_x`. The `else` branch is not included.
-// compile-flags:-Zborrowck=compare -Znll
+// compile-flags:-Zborrowck=compare
#![allow(warnings)]
#![feature(rustc_attrs)]
// in the type of `p` includes the points after `&v[0]` up to (but not
// including) the call to `use_x`. The `else` branch is not included.
-// compile-flags:-Zborrowck=compare -Znll
+// compile-flags:-Zborrowck=compare
#![allow(warnings)]
#![feature(rustc_attrs)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z borrowck=mir -Z nll
+// compile-flags: -Zborrowck=mir
#![allow(dead_code)]
fn bar<'a, 'b>(x: &'a u32, y: &'b u32) -> (&'a u32, &'b u32) {
foo(x, y)
//~^ ERROR lifetime mismatch [E0623]
- //~| WARNING not reporting region error due to -Znll
+ //~| WARNING not reporting region error due to nll
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags: -Z borrowck=mir -Z nll
+// compile-flags: -Z borrowck=mir
#![allow(dead_code)]
fn bar<'a, 'b>(x: Cell<&'a u32>, y: Cell<&'b u32>) {
Foo { x, y };
//~^ ERROR lifetime mismatch [E0623]
- //~| WARNING not reporting region error due to -Znll
+ //~| WARNING not reporting region error due to nll
}
fn main() {}
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
+#![feature(proc_macro_path_invoc)]
mod priv_nominal {
pub struct Pub;
// ignore-tidy-linelength
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro, associated_type_defaults)]
#![allow(unused, private_in_public)]
// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct::{{constructor}}}` is priv
// error-pattern:type `for<'r> fn(&'r ext::Pub<u8>) {<ext::Pub<u8>>::priv_method}` is private
+#![feature(proc_macro_path_invoc)]
#![feature(decl_macro)]
extern crate private_inferred_type as ext;
#![feature(associated_consts)]
#![feature(decl_macro)]
#![allow(private_in_public)]
+#![feature(proc_macro_path_invoc)]
mod m {
fn priv_fn() {}
match (&a1,) {
(&ref b0,) => {
a1 = &f; //[ast]~ ERROR cannot assign
- //[mir]~^ ERROR cannot assign to `a1` because it is borrowed
+ //[mir]~^ ERROR cannot assign to `a1` because it is borrowed
+ drop(b0);
}
}
}
// except according to those terms.
// revisions: ll nll
-//[nll] compile-flags: -Znll -Zborrowck=mir
+//[nll] compile-flags:-Zborrowck=mir
fn static_id<'a,'b>(t: &'a ()) -> &'static ()
where 'a: 'static { t }
where 'a: 'b, 'b: 'static { t }
fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a {
t //[ll]~ ERROR E0312
- //[nll]~^ WARNING not reporting region error due to -Znll
+ //[nll]~^ WARNING not reporting region error due to nll
//[nll]~| ERROR free region `'a` does not outlive free region `'static`
}
fn error(u: &(), v: &()) {
static_id(&u); //[ll]~ ERROR explicit lifetime required in the type of `u` [E0621]
- //[nll]~^ WARNING not reporting region error due to -Znll
+ //[nll]~^ WARNING not reporting region error due to nll
//[nll]~| ERROR explicit lifetime required in the type of `u` [E0621]
static_id_indirect(&v); //[ll]~ ERROR explicit lifetime required in the type of `v` [E0621]
- //[nll]~^ WARNING not reporting region error due to -Znll
+ //[nll]~^ WARNING not reporting region error due to nll
//[nll]~| ERROR explicit lifetime required in the type of `v` [E0621]
}
impl Tr for S where S<Self>: Copy {} // OK
impl Tr for S where Self::A: Copy {} // OK
-impl Tr for Self {} //~ ERROR cyclic dependency detected
-impl Tr for S<Self> {} //~ ERROR cyclic dependency detected
-impl Self {} //~ ERROR cyclic dependency detected
-impl S<Self> {} //~ ERROR cyclic dependency detected
-impl Tr<Self::A> for S {} //~ ERROR cyclic dependency detected
+impl Tr for Self {} //~ ERROR cycle detected
+impl Tr for S<Self> {} //~ ERROR cycle detected
+impl Self {} //~ ERROR cycle detected
+impl S<Self> {} //~ ERROR cycle detected
+impl Tr<Self::A> for S {} //~ ERROR cycle detected
fn main() {}
#![no_std]
// OK
-#[lang = "str"]
+#[lang = "str_alloc"]
impl str {}
impl str {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
mod foo {
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(slice_patterns)]
#![deny(unreachable_patterns)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![deny(unreachable_patterns)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns, rustc_attrs)]
#![warn(unreachable_code)]
#![warn(unreachable_patterns)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll
+// compile-flags:-Zborrowck=mir
fn can_panic() -> Box<usize> {
Box::new(44)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll
+// compile-flags:-Zborrowck=mir
#![allow(warnings)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll
+// compile-flags:-Zborrowck=mir
fn cond() -> bool { false }
// suitable variables and that we setup the outlives relationship
// between R0 and R1 properly.
-// compile-flags:-Znll -Zverbose
-// ^^^^^^^^^ force compiler to dump more region information
+// compile-flags:-Zborrowck=mir -Zverbose
+// ^^^^^^^^^ force compiler to dump more region information
// ignore-tidy-linelength
#![allow(warnings)]
// in the type of `r_a` must outlive the region (`R7`) that appears in
// the type of `r_b`
-// compile-flags:-Znll -Zverbose
-// ^^^^^^^^^ force compiler to dump more region information
+// compile-flags:-Zborrowck=mir -Zverbose
+// ^^^^^^^^^ force compiler to dump more region information
#![allow(warnings)]
// in the type of `p` includes the points after `&v[0]` up to (but not
// including) the call to `use_x`. The `else` branch is not included.
-// compile-flags:-Znll -Zverbose
-// ^^^^^^^^^ force compiler to dump more region information
+// compile-flags:-Zborrowck=mir -Zverbose
+// ^^^^^^^^^ force compiler to dump more region information
#![allow(warnings)]
// but only at a particular point, and hence they wind up including
// distinct regions.
-// compile-flags:-Znll -Zverbose
-// ^^^^^^^^^ force compiler to dump more region information
+// compile-flags:-Zborrowck=mir -Zverbose
+// ^^^^^^^^^ force compiler to dump more region information
#![allow(warnings)]
// in the type of `p` includes the points after `&v[0]` up to (but not
// including) the call to `use_x`. The `else` branch is not included.
-// compile-flags:-Znll -Zverbose
-// ^^^^^^^^^ force compiler to dump more region information
+// compile-flags:-Zborrowck=mir -Zverbose
+// ^^^^^^^^^ force compiler to dump more region information
#![allow(warnings)]
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// Test that we generate obsolete syntax errors around usages of `proc`.
-
-fn foo(p: proc()) { } //~ ERROR expected type, found reserved keyword `proc`
-
-fn bar() { proc() 1; } //~ ERROR expected expression, found reserved keyword `proc`
-
-fn main() { }
// Test that a variable of type ! can coerce to another type.
// error-pattern:explicit
+
+#![feature(never_type)]
+
fn main() {
let x: ! = panic!();
let y: u32 = x;
// error-pattern:wowzers!
+#![feature(never_type)]
#![allow(unreachable_code)]
fn foo(x: !) -> ! {
// Test that we can explicitly cast ! to another type
// error-pattern:explicit
+
+#![feature(never_type)]
+
fn main() {
let x: ! = panic!();
let y: u32 = x as u32;
// error-pattern:kapow!
+#![feature(never_type)]
+
trait Foo {
type Wow;
// error-pattern:oh no!
+#![feature(never_type)]
+
struct Wub;
impl PartialEq<!> for Wub {
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+ifeq ($(TARGET),wasm32-unknown-unknown)
+all:
+ $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg a
+ wc -c < $(TMPDIR)/foo.wasm
+ [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "1024" ]
+ $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg b
+ wc -c < $(TMPDIR)/foo.wasm
+ [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ]
+ $(RUSTC) foo.rs -C lto -O --target wasm32-unknown-unknown --cfg c
+ wc -c < $(TMPDIR)/foo.wasm
+ [ "`wc -c < $(TMPDIR)/foo.wasm`" -lt "5120" ]
+else
+all:
+endif
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "cdylib"]
+
+#[no_mangle]
+#[cfg(a)]
+pub fn foo() {
+ panic!("test");
+}
+
+#[no_mangle]
+#[cfg(b)]
+pub fn foo() {
+ panic!("{}", 1);
+}
+
+#[no_mangle]
+#[cfg(c)]
+pub fn foo() {
+ panic!("{}", "a");
+}
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
+#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
+#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
extern crate proc_macro;
// aux-build:cond_plugin.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate cond_plugin;
// aux-build:hello_macro.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc, proc_macro_non_items)]
extern crate hello_macro;
// ignore-stage1
#![allow(warnings)]
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate attr_args;
use attr_args::attr_with_args;
#[attr_with_args(text = "Hello, world!")]
fn foo() {}
-#[::attr_args::identity
- fn main() { assert_eq!(foo(), "Hello, world!"); }]
+#[::attr_args::identity(
+ fn main() { assert_eq!(foo(), "Hello, world!"); })]
struct Dummy;
// aux-build:attr-on-trait.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate attr_on_trait;
// aux-build:attr-stmt-expr.rs
// ignore-stage1
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(proc_macro, stmt_expr_attributes, proc_macro_stmt, proc_macro_expr)]
extern crate attr_stmt_expr;
use attr_stmt_expr::{expect_let, expect_print_stmt, expect_expr, expect_print_expr,
pub fn attr_with_args(args: TokenStream, input: TokenStream) -> TokenStream {
let args = args.to_string();
- assert_eq!(args, r#"( text = "Hello, world!" )"#);
+ assert_eq!(args, r#"text = "Hello, world!""#);
let input = input.to_string();
// no-prefer-dynamic
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![crate_type = "proc-macro"]
extern crate proc_macro;
// no-prefer-dynamic
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
#![crate_type = "proc-macro"]
extern crate proc_macro as proc_macro_renamed; // This does not break `quote!`
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro)]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn check(_a: TokenStream, b: TokenStream) -> TokenStream {
+ b.into_iter().collect()
+}
// aux-build:bang-macro.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate bang_macro;
use bang_macro::rewrite;
// aux-build:count_compound_ops.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate count_compound_ops;
use count_compound_ops::count_compound_ops;
// aux-build:derive-b.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_path_invoc)]
extern crate derive_b;
// aux-build:hygiene_example.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate hygiene_example;
use hygiene_example::hello;
// aux-build:issue-42708.rs
// ignore-stage1
-#![feature(decl_macro, proc_macro)]
+#![feature(decl_macro, proc_macro, proc_macro_path_invoc)]
#![allow(unused)]
extern crate issue_42708;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-50061.rs
+// ignore-stage1
+
+#![feature(proc_macro, proc_macro_path_invoc, decl_macro)]
+
+extern crate issue_50061;
+
+macro inner(any_token $v: tt) {
+ $v
+}
+
+macro outer($v: tt) {
+ inner!(any_token $v)
+}
+
+#[issue_50061::check]
+fn main() {
+ //! this doc comment forces roundtrip through a string
+ let checkit = 0;
+ outer!(checkit);
+}
// aux-build:negative-token.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate negative_token;
// ignore-stage1
// ignore-cross-compile
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro_def;
#![feature(allocator_api, nonnull)]
-use std::alloc::{Alloc, Global};
+use std::alloc::{Alloc, Global, oom};
fn main() {
unsafe {
- let ptr = Global.alloc_one::<i32>().unwrap_or_else(|_| {
- Global.oom()
- });
+ let ptr = Global.alloc_one::<i32>().unwrap_or_else(|_| oom());
*ptr.as_ptr() = 4;
assert_eq!(*ptr.as_ptr(), 4);
Global.dealloc_one(ptr);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lxl nll
-//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+// compile-flags: -Z borrowck=mir -Z two-phase-borrows
// This is the "goto example" for why we want two phase borrows.
// These represent current behavior, but are pretty dubious. I would
// like to revisit these and potentially change them. --nmatsakis
+#![feature(never_type)]
+
trait BadDefault {
fn default() -> Self;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
#![feature(slice_patterns)]
#![allow(unreachable_patterns)]
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
macro m($S:ident, $x:ident) {
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
mod foo {
// aux-build:legacy_interaction.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#[allow(unused)]
extern crate legacy_interaction;
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod bar {
mod baz {
// aux-build:my_crate.rs
// aux-build:unhygienic_example.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate unhygienic_example;
extern crate my_crate; // (b)
// aux-build:xcrate.rs
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate xcrate;
// Test that we can call static methods on ! both directly and when it appears in a generic
+#![feature(never_type)]
+
trait StringifyType {
fn stringify_type() -> &'static str;
}
// except according to those terms.
// revisions: normal nll
-//[nll] compile-flags: -Znll -Zborrowck=mir
+//[nll] compile-flags:-Zborrowck=mir
#![feature(fn_traits,
step_trait,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//`#[cfg]` on struct field permits empty unusable struct
+// `#[cfg]` on struct field permits empty unusable struct
struct S {
#[cfg(untrue)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
#![feature(exhaustive_patterns)]
// Regression test for inhabitedness check. The old
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Debug)]
+#[repr(i32)]
+enum E {
+ Min = -2147483648i32,
+ _Max = 2147483647i32,
+}
+
+fn main() {
+ assert_eq!(Some(E::Min).unwrap() as i32, -2147483648i32);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
+
#[allow(unused)]
fn never_returns() {
loop {
// ignore-wasm32-bare compiled with panic=abort by default
#![feature(fn_traits)]
+#![feature(never_type)]
use std::panic;
// Test that we can extract a ! through pattern matching then use it as several different types.
+#![feature(never_type)]
+
fn main() {
let x: Result<u32, !> = Ok(123);
match x {
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
extern crate two_macros;
// Ideally this would be revised to use no_std, but for now it serves
// well enough to reproduce (and illustrate) the bug from #16687.
-#![feature(heap_api, allocator_api, nonnull_cast)]
+#![feature(heap_api, allocator_api)]
-use std::alloc::{Global, Alloc, Layout};
+use std::alloc::{Global, Alloc, Layout, oom};
use std::ptr::{self, NonNull};
fn main() {
println!("allocate({:?})", layout);
}
- let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| Global.oom());
+ let ret = Global.alloc(layout.clone()).unwrap_or_else(|_| oom());
if PRINT {
println!("allocate({:?}) = {:?}", layout, ret);
}
let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old.clone(), new.size())
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
if PRINT {
println!("reallocate({:?}, old={:?}, new={:?}) = {:?}",
#![feature(allocator_api)]
-use std::alloc::{Alloc, Global, Layout};
+use std::alloc::{Alloc, Global, Layout, oom};
use std::ptr::NonNull;
struct arena(());
fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
unsafe {
let ptr = Global.alloc(Layout::new::<Bcx>())
- .unwrap_or_else(|_| Global.oom());
+ .unwrap_or_else(|_| oom());
&*(ptr.as_ptr() as *const _)
}
}
// ignore-emscripten
#![feature(repr_simd, target_feature, cfg_target_feature)]
+#![feature(avx512_target_feature)]
use std::process::{Command, ExitStatus};
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(never_type)]
use std::mem::size_of;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const QUERY = '&';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'reference' },
+ ],
+};
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const QUERY = '+';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::ops::AddAssign', 'name': 'AddAssign' },
+ { 'path': 'std::ops::Add', 'name': 'Add' },
+ ],
+};
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const QUERY = '!';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'never' },
+ ],
+};
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const QUERY = '[';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'slice' },
+ { 'path': 'std::ops::IndexMut', 'name': 'IndexMut' },
+ { 'path': 'std::ops::Index', 'name': 'Index' },
+ ],
+};
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const QUERY = 'str,u8';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'str' },
+ { 'path': 'std', 'name': 'u8' },
+ { 'path': 'std::ffi', 'name': 'CStr' },
+ { 'path': 'std::simd', 'name': 'u8x2' },
+ ],
+};
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const QUERY = '!';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std', 'name': 'never' },
+ ],
+};
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+//! Test with [Foo::baz], [Bar::foo], [Uniooon::X]
+
+pub struct Foo {
+ pub bar: usize,
+}
--- /dev/null
+warning: [Foo::baz] cannot be resolved, ignoring it...
+
+warning: [Bar::foo] cannot be resolved, ignoring it...
+
+warning: [Uniooon::X] cannot be resolved, ignoring it...
+
pub const CONST: u32 = 0;
pub static STATIC: &str = "baguette";
pub fn function() {}
+
+mod private_module {
+ pub struct ReexportedStruct;
+}
+
+// @has foo/all.html '//a[@href="struct.ReexportedStruct.html"]' 'ReexportedStruct'
+// @!has foo/all.html 'private_module'
+pub use private_module::ReexportedStruct;
pub mod str {
#![doc(primitive = "str")]
- #[lang = "str"]
+ #[lang = "str_alloc"]
impl str {
// @has search-index.js foo
pub fn foo(&self) {}
// aux-build:parent-source-spans.rs
// ignore-stage1
-#![feature(proc_macro, decl_macro)]
+#![feature(proc_macro, decl_macro, proc_macro_non_items)]
extern crate parent_source_spans;
// aux-build:three-equals.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate three_equals;
fn ice<A>(a: A) {
let r = loop {};
r = r + a;
- //~^ ERROR the trait bound `!: Add<A>` is not satisfied
+ //~^ ERROR the trait bound `(): Add<A>` is not satisfied
}
-error[E0277]: the trait bound `!: Add<A>` is not satisfied
+error[E0277]: the trait bound `(): Add<A>` is not satisfied
--> $DIR/associated-types-ICE-when-projecting-out-of-err.rs:33:11
|
LL | r = r + a;
- | ^ the trait `Add<A>` is not implemented for `!`
+ | ^ the trait `Add<A>` is not implemented for `()`
error: aborting due to previous error
+++ /dev/null
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:24:24
- |
-LL | let c1 = to_fn_mut(|| x = 4);
- | -- - previous borrow occurs due to use of `x` in closure
- | |
- | first mutable borrow occurs here
-LL | let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
- | ^^ - borrow occurs due to use of `x` in closure
- | |
- | second mutable borrow occurs here
-LL | //~| ERROR cannot borrow `x` as mutable more than once
-LL | }
- | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:35:24
- |
-LL | let c1 = to_fn_mut(|| set(&mut x));
- | -- - previous borrow occurs due to use of `x` in closure
- | |
- | first mutable borrow occurs here
-LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
- | ^^ - borrow occurs due to use of `x` in closure
- | |
- | second mutable borrow occurs here
-LL | //~| ERROR cannot borrow `x` as mutable more than once
-LL | }
- | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:42:24
- |
-LL | let c1 = to_fn_mut(|| x = 5);
- | -- - previous borrow occurs due to use of `x` in closure
- | |
- | first mutable borrow occurs here
-LL | let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
- | ^^ - borrow occurs due to use of `x` in closure
- | |
- | second mutable borrow occurs here
-LL | //~| ERROR cannot borrow `x` as mutable more than once
-LL | }
- | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:49:24
- |
-LL | let c1 = to_fn_mut(|| x = 5);
- | -- - previous borrow occurs due to use of `x` in closure
- | |
- | first mutable borrow occurs here
-LL | let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
- | ^^ - borrow occurs due to use of `x` in closure
- | |
- | second mutable borrow occurs here
-...
-LL | }
- | - first borrow ends here
-
-error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:61:24
- |
-LL | let c1 = to_fn_mut(|| set(&mut *x.f));
- | -- - previous borrow occurs due to use of `x` in closure
- | |
- | first mutable borrow occurs here
-LL | let c2 = to_fn_mut(|| set(&mut *x.f));
- | ^^ - borrow occurs due to use of `x` in closure
- | |
- | second mutable borrow occurs here
-...
-LL | }
- | - first borrow ends here
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0499`.
let c1 = to_fn_mut(|| x = 4);
let c2 = to_fn_mut(|| x = 5); //~ ERROR cannot borrow `x` as mutable more than once
//~| ERROR cannot borrow `x` as mutable more than once
+ drop((c1, c2));
}
fn set(x: &mut isize) {
let c1 = to_fn_mut(|| set(&mut x));
let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
//~| ERROR cannot borrow `x` as mutable more than once
+ drop((c1, c2));
}
fn c() {
let c1 = to_fn_mut(|| x = 5);
let c2 = to_fn_mut(|| set(&mut x)); //~ ERROR cannot borrow `x` as mutable more than once
//~| ERROR cannot borrow `x` as mutable more than once
+ drop((c1, c2));
}
fn d() {
let c2 = to_fn_mut(|| { let _y = to_fn_mut(|| set(&mut x)); }); // (nested closure)
//~^ ERROR cannot borrow `x` as mutable more than once
//~| ERROR cannot borrow `x` as mutable more than once
+ drop((c1, c2));
}
fn g() {
let c2 = to_fn_mut(|| set(&mut *x.f));
//~^ ERROR cannot borrow `x` as mutable more than once
//~| ERROR cannot borrow `x` as mutable more than once
+ drop((c1, c2));
}
fn main() {
| ^^ - borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
-LL | //~| ERROR cannot borrow `x` as mutable more than once
+...
LL | }
| - first borrow ends here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:35:24
+ --> $DIR/borrowck-closures-two-mut.rs:36:24
|
LL | let c1 = to_fn_mut(|| set(&mut x));
| -- - previous borrow occurs due to use of `x` in closure
| ^^ - borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
-LL | //~| ERROR cannot borrow `x` as mutable more than once
+...
LL | }
| - first borrow ends here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:42:24
+ --> $DIR/borrowck-closures-two-mut.rs:44:24
|
LL | let c1 = to_fn_mut(|| x = 5);
| -- - previous borrow occurs due to use of `x` in closure
| ^^ - borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
-LL | //~| ERROR cannot borrow `x` as mutable more than once
+...
LL | }
| - first borrow ends here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:49:24
+ --> $DIR/borrowck-closures-two-mut.rs:52:24
|
LL | let c1 = to_fn_mut(|| x = 5);
| -- - previous borrow occurs due to use of `x` in closure
| - first borrow ends here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Ast)
- --> $DIR/borrowck-closures-two-mut.rs:61:24
+ --> $DIR/borrowck-closures-two-mut.rs:65:24
|
LL | let c1 = to_fn_mut(|| set(&mut *x.f));
| -- - previous borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
-LL | }
- | - first borrow ends here
+LL | drop((c1, c2));
+ | -- borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
- --> $DIR/borrowck-closures-two-mut.rs:35:24
+ --> $DIR/borrowck-closures-two-mut.rs:36:24
|
LL | let c1 = to_fn_mut(|| set(&mut x));
| -- - previous borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
-LL | }
- | - first borrow ends here
+LL | drop((c1, c2));
+ | -- borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
- --> $DIR/borrowck-closures-two-mut.rs:42:24
+ --> $DIR/borrowck-closures-two-mut.rs:44:24
|
LL | let c1 = to_fn_mut(|| x = 5);
| -- - previous borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
LL | //~| ERROR cannot borrow `x` as mutable more than once
-LL | }
- | - first borrow ends here
+LL | drop((c1, c2));
+ | -- borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
- --> $DIR/borrowck-closures-two-mut.rs:49:24
+ --> $DIR/borrowck-closures-two-mut.rs:52:24
|
LL | let c1 = to_fn_mut(|| x = 5);
| -- - previous borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
...
-LL | }
- | - first borrow ends here
+LL | drop((c1, c2));
+ | -- borrow later used here
error[E0499]: cannot borrow `x` as mutable more than once at a time (Mir)
- --> $DIR/borrowck-closures-two-mut.rs:61:24
+ --> $DIR/borrowck-closures-two-mut.rs:65:24
|
LL | let c1 = to_fn_mut(|| set(&mut *x.f));
| -- - previous borrow occurs due to use of `x` in closure
| |
| second mutable borrow occurs here
...
-LL | }
- | - first borrow ends here
+LL | drop((c1, c2));
+ | -- borrow later used here
error: aborting due to 10 previous errors
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/issue-45983.rs:17:27
|
LL | give_any(|y| x = Some(y));
LL | give_any(|y| x = Some(y));
| ^^^^^^^^^^^ cannot mutate
|
- = note: Value not mutable causing this error: `x`
+ = note: the value which is causing this path not to be mutable is...: `x`
error[E0596]: cannot borrow immutable item `x` as mutable
--> $DIR/issue-45983.rs:17:14
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/issue-7573.rs:27:31
|
LL | let mut lines_to_use: Vec<&CrateId> = Vec::new();
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/regions-escape-bound-fn-2.rs:18:27
|
LL | with_int(|y| x = Some(y));
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/regions-escape-bound-fn.rs:18:22
|
LL | with_int(|y| x = Some(y));
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/regions-escape-unboxed-closure.rs:16:27
|
LL | with_int(&mut |y| x = Some(y));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lxl nll
-//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+// compile-flags: -Z borrowck=mir -Z two-phase-borrows
// run-pass
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// revisions: lxl nll
-//[lxl]compile-flags: -Z borrowck=mir -Z two-phase-borrows
-//[nll]compile-flags: -Z borrowck=mir -Z two-phase-borrows -Z nll
+// compile-flags: -Z borrowck=mir -Z two-phase-borrows
// run-pass
#[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
impl<T: 'static> Foo for T where T: Iterator<Item = i32> { }
+trait Bar {
+ type Assoc;
+}
+
+impl<T> Bar for T where T: Iterator<Item = i32> {
+ #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
+ type Assoc = Vec<T>;
+}
+
fn main() {
println!("hello");
}
LL | #[rustc_dump_program_clauses] //~ ERROR Implemented(T: Foo) :-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :- Implemented(T: Bar).
+ --> $DIR/lower_impl.rs:23:5
+ |
+LL | #[rustc_dump_program_clauses] //~ ERROR Normalize(<T as Bar>::Assoc == std::vec::Vec<T>) :-
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/expect-region-supply-region.rs:28:13
|
LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/expect-region-supply-region.rs:38:13
|
LL | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/expect-region-supply-region.rs:47:33
|
LL | closure_expecting_bound(|x: &'x u32| {
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/expect-region-supply-region.rs:52:13
|
LL | f = Some(x);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-pass
+
const X: u32 = 5;
const Y: u32 = 6;
const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
//~^ WARN attempt to subtract with overflow
fn main() {
- println!("{}", FOO); //~ E0080
+ println!("{}", FOO);
+ //~^ WARN constant evaluation error
}
warning: attempt to subtract with overflow
- --> $DIR/conditional_array_execution.rs:13:19
+ --> $DIR/conditional_array_execution.rs:15:19
|
LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize];
| ^^^^^
|
= note: #[warn(const_err)] on by default
-error[E0080]: constant evaluation error
- --> $DIR/conditional_array_execution.rs:17:20
+warning: constant evaluation error
+ --> $DIR/conditional_array_execution.rs:19:20
|
-LL | println!("{}", FOO); //~ E0080
+LL | println!("{}", FOO);
| ^^^ referenced constant has errors
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+fn main() {
+ const MIN: i8 = -5;
+ match 5i8 {
+ MIN...-1 => {},
+ _ => {},
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-pass
+
#![feature(const_fn)]
const fn foo(x: u32) -> u32 {
const Y: u32 = foo(0-1);
//~^ WARN attempt to subtract with overflow
println!("{} {}", X, Y);
- //~^ ERROR constant evaluation error
- //~| ERROR constant evaluation error
+ //~^ WARN constant evaluation error
+ //~| WARN constant evaluation error
}
warning: attempt to subtract with overflow
- --> $DIR/issue-43197.rs:18:20
+ --> $DIR/issue-43197.rs:20:20
|
LL | const X: u32 = 0-1;
| ^^^
|
= note: #[warn(const_err)] on by default
-error[E0080]: constant evaluation error
- --> $DIR/issue-43197.rs:22:23
+warning: constant evaluation error
+ --> $DIR/issue-43197.rs:24:23
|
LL | println!("{} {}", X, Y);
| ^ referenced constant has errors
warning: attempt to subtract with overflow
- --> $DIR/issue-43197.rs:20:24
+ --> $DIR/issue-43197.rs:22:24
|
LL | const Y: u32 = foo(0-1);
| ^^^
-error[E0080]: constant evaluation error
- --> $DIR/issue-43197.rs:22:26
+warning: constant evaluation error
+ --> $DIR/issue-43197.rs:24:26
|
LL | println!("{} {}", X, Y);
| ^ referenced constant has errors
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+trait Foo {
+ const AMT: usize;
+}
+
+enum Bar<A, B> {
+ First(A),
+ Second(B),
+}
+
+impl<A: Foo, B: Foo> Foo for Bar<A, B> {
+ const AMT: usize = [A::AMT][(A::AMT > B::AMT) as usize];
+}
+
+impl Foo for u8 {
+ const AMT: usize = 1;
+}
+
+impl Foo for u16 {
+ const AMT: usize = 2;
+}
+
+fn main() {
+ println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
+ //~^ WARN const_err
+}
--- /dev/null
+warning: constant evaluation error
+ --> $DIR/issue-44578.rs:35:20
+ |
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+ |
+ = note: #[warn(const_err)] on by default
+
+warning: constant evaluation error
+ --> $DIR/issue-44578.rs:35:20
+ |
+LL | println!("{}", <Bar<u16, u8> as Foo>::AMT); //~ WARN const_err
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+// compile-flags: -O
+fn main() {
+ println!("{}", 0u32 - 1);
+ //~^ WARN const_err
+ //~| WARN const_err
+ let _x = 0u32 - 1;
+ //~^ WARN const_err
+ println!("{}", 1/(1-1));
+ //~^ WARN const_err
+ //~| WARN const_err
+ let _x = 1/(1-1);
+ //~^ WARN const_err
+ //~| WARN const_err
+ println!("{}", 1/(false as u32));
+ //~^ WARN const_err
+ let _x = 1/(false as u32);
+}
--- /dev/null
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:14:20
+ |
+LL | println!("{}", 0u32 - 1);
+ | ^^^^^^^^ attempted to do overflowing math
+ |
+ = note: #[warn(const_err)] on by default
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:14:20
+ |
+LL | println!("{}", 0u32 - 1);
+ | ^^^^^^^^ attempted to do overflowing math
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:17:14
+ |
+LL | let _x = 0u32 - 1;
+ | ^^^^^^^^ attempted to do overflowing math
+
+warning: attempt to divide by zero
+ --> $DIR/promoted_errors.rs:19:20
+ |
+LL | println!("{}", 1/(1-1));
+ | ^^^^^^^
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:19:20
+ |
+LL | println!("{}", 1/(1-1));
+ | ^^^^^^^ attempted to do overflowing math
+
+warning: attempt to divide by zero
+ --> $DIR/promoted_errors.rs:22:14
+ |
+LL | let _x = 1/(1-1);
+ | ^^^^^^^
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:22:14
+ |
+LL | let _x = 1/(1-1);
+ | ^^^^^^^ attempted to do overflowing math
+
+warning: constant evaluation error
+ --> $DIR/promoted_errors.rs:25:20
+ |
+LL | println!("{}", 1/(false as u32));
+ | ^^^^^^^^^^^^^^^^ attempted to do overflowing math
+
LL | let mut sum = 0;
| ^
-error[E0015]: calls in constant functions are limited to constant functions, struct and enum constructors
+error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
--> $DIR/const-fn-error.rs:18:14
|
LL | for i in 0..x {
}
trait B: C {
+ //~^ ERROR cycle detected
}
trait C: B { }
- //~^ ERROR cyclic dependency detected
- //~| cyclic reference
fn main() { }
-error[E0391]: cyclic dependency detected
- --> $DIR/cycle-trait-supertrait-indirect.rs:20:1
+error[E0391]: cycle detected when computing the supertraits of `B`
+ --> $DIR/cycle-trait-supertrait-indirect.rs:17:1
|
-LL | trait C: B { }
- | ^^^^^^^^^^ cyclic reference
+LL | trait B: C {
+ | ^^^^^^^^^^
|
-note: the cycle begins when computing the supertraits of `B`...
- --> $DIR/cycle-trait-supertrait-indirect.rs:14:1
+note: ...which requires computing the supertraits of `C`...
+ --> $DIR/cycle-trait-supertrait-indirect.rs:21:1
|
-LL | trait A: B {
+LL | trait C: B { }
| ^^^^^^^^^^
-note: ...which then requires computing the supertraits of `C`...
- --> $DIR/cycle-trait-supertrait-indirect.rs:17:1
+ = note: ...which again requires computing the supertraits of `B`, completing the cycle
+note: cycle used when computing the supertraits of `A`
+ --> $DIR/cycle-trait-supertrait-indirect.rs:14:1
|
-LL | trait B: C {
+LL | trait A: B {
| ^^^^^^^^^^
- = note: ...which then again requires computing the supertraits of `B`, completing the cycle.
error: aborting due to previous error
+error[E0596]: cannot borrow immutable item `self` as mutable
+ --> $DIR/issue-34126.rs:16:18
+ |
+LL | self.run(&mut self); //~ ERROR cannot borrow
+ | ^^^^^^^^^ cannot borrow as mutable
+
error[E0502]: cannot borrow `self` as mutable because it is also borrowed as immutable
--> $DIR/issue-34126.rs:16:18
|
| immutable borrow occurs here
| borrow later used here
-error: aborting due to previous error
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0502`.
+Some errors occurred: E0502, E0596.
+For more information about an error, try `rustc --explain E0502`.
LL | f.v.push("cat".to_string()); //~ ERROR cannot borrow
| ^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `f`
+ = note: the value which is causing this path not to be mutable is...: `f`
error[E0384]: cannot assign twice to immutable variable `s.x`
--> $DIR/issue-35937.rs:26:5
LL | self.s.push('x'); //~ ERROR cannot borrow data mutably
| ^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*self`
+ = note: the value which is causing this path not to be mutable is...: `*self`
error: aborting due to previous error
LL | f.s.push('x'); //~ ERROR cannot borrow data mutably
| ^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*f`
+ = note: the value which is causing this path not to be mutable is...: `*f`
error: aborting due to previous error
LL | let _ = &mut z.x; //~ ERROR cannot borrow
| ^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `z`
+ = note: the value which is causing this path not to be mutable is...: `z`
error[E0596]: cannot borrow immutable item `self.x` as mutable
--> $DIR/issue-39544.rs:26:17
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*self`
+ = note: the value which is causing this path not to be mutable is...: `*self`
error[E0596]: cannot borrow immutable item `self.x` as mutable
--> $DIR/issue-39544.rs:30:17
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*self`
+ = note: the value which is causing this path not to be mutable is...: `*self`
error[E0596]: cannot borrow immutable item `other.x` as mutable
--> $DIR/issue-39544.rs:31:17
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*other`
+ = note: the value which is causing this path not to be mutable is...: `*other`
error[E0596]: cannot borrow immutable item `self.x` as mutable
--> $DIR/issue-39544.rs:35:17
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*self`
+ = note: the value which is causing this path not to be mutable is...: `*self`
error[E0596]: cannot borrow immutable item `other.x` as mutable
--> $DIR/issue-39544.rs:36:17
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*other`
+ = note: the value which is causing this path not to be mutable is...: `*other`
error[E0596]: cannot borrow immutable item `self.x` as mutable
--> $DIR/issue-39544.rs:40:17
LL | let _ = &mut self.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*self`
+ = note: the value which is causing this path not to be mutable is...: `*self`
error[E0596]: cannot borrow immutable item `other.x` as mutable
--> $DIR/issue-39544.rs:41:17
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*other`
+ = note: the value which is causing this path not to be mutable is...: `*other`
error[E0596]: cannot borrow immutable item `other.x` as mutable
--> $DIR/issue-39544.rs:45:17
LL | let _ = &mut other.x; //~ ERROR cannot borrow
| ^^^^^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*other`
+ = note: the value which is causing this path not to be mutable is...: `*other`
error[E0596]: cannot borrow immutable item `z.x` as mutable
--> $DIR/issue-39544.rs:51:13
LL | let _ = &mut z.x; //~ ERROR cannot borrow
| ^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `z`
+ = note: the value which is causing this path not to be mutable is...: `z`
error[E0596]: cannot borrow immutable item `w.x` as mutable
--> $DIR/issue-39544.rs:52:13
LL | let _ = &mut w.x; //~ ERROR cannot borrow
| ^^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*w`
+ = note: the value which is causing this path not to be mutable is...: `*w`
error[E0594]: cannot assign to immutable item `*x.0`
--> $DIR/issue-39544.rs:58:5
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(try_from)]
+
use std::marker::PhantomData;
use std::convert::{TryFrom, AsRef};
error[E0119]: conflicting implementations of trait `std::convert::AsRef<Q>` for type `std::boxed::Box<Q>`:
- --> $DIR/conflict-with-std.rs:15:1
+ --> $DIR/conflict-with-std.rs:17:1
|
LL | impl AsRef<Q> for Box<Q> { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^^^^^^^
where T: ?Sized;
error[E0119]: conflicting implementations of trait `std::convert::From<S>` for type `S`:
- --> $DIR/conflict-with-std.rs:22:1
+ --> $DIR/conflict-with-std.rs:24:1
|
LL | impl From<S> for S { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^
- impl<T> std::convert::From<T> for T;
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<X>` for type `X`:
- --> $DIR/conflict-with-std.rs:29:1
+ --> $DIR/conflict-with-std.rs:31:1
|
LL | impl TryFrom<X> for X { //~ ERROR conflicting implementations
| ^^^^^^^^^^^^^^^^^^^^^
-error[E0594]: cannot assign to immutable item `fancy_ref.num`
+error[E0594]: cannot assign to data in a `&` reference
--> $DIR/E0389.rs:18:5
|
+LL | let fancy_ref = &(&mut fancy);
+ | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)`
LL | fancy_ref.num = 6; //~ ERROR E0389
- | ^^^^^^^^^^^^^^^^^ cannot mutate
- |
- = note: Value not mutable causing this error: `*fancy_ref`
+ | ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
error: aborting due to previous error
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/E0621-does-not-trigger-for-closures.rs:25:5
|
LL | invoke(&x, |a, b| if a > b { a } else { b }); //~ ERROR E0495
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental
-#[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental
-struct Foo(u64, u64);
-
-#[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental
-fn foo() {}
-
-fn main() {
- cfg!(target_feature = "x");
- //~^ ERROR `cfg(target_feature)` is experimental and subject to change
-}
+++ /dev/null
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
- --> $DIR/feature-gate-cfg-target-feature.rs:12:12
- |
-LL | #[cfg_attr(target_feature = "x", x)] //~ ERROR `cfg(target_feature)` is experimental
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
- --> $DIR/feature-gate-cfg-target-feature.rs:11:7
- |
-LL | #[cfg(target_feature = "x")] //~ ERROR `cfg(target_feature)` is experimental
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
- --> $DIR/feature-gate-cfg-target-feature.rs:15:19
- |
-LL | #[cfg(not(any(all(target_feature = "x"))))] //~ ERROR `cfg(target_feature)` is experimental
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error[E0658]: `cfg(target_feature)` is experimental and subject to change (see issue #29717)
- --> $DIR/feature-gate-cfg-target-feature.rs:19:10
- |
-LL | cfg!(target_feature = "x");
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(cfg_target_feature)] to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[doc(alias = "foo")] //~ ERROR: #[doc(alias = "...")] is experimental
+pub struct Foo;
+
+fn main() {}
--- /dev/null
+error[E0658]: #[doc(alias = "...")] is experimental (see issue #50146)
+ --> $DIR/feature-gate-doc_alias.rs:11:1
+ |
+LL | #[doc(alias = "foo")] //~ ERROR: #[doc(alias = "...")] is experimental
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(doc_alias)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![feature(never_type)]
fn foo() -> Result<u32, !> {
Ok(123)
}
//~^ ERROR generic associated types are unstable
type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
//~^ ERROR generic associated types are unstable
+ //~| ERROR where clauses on associated types are unstable
}
struct Foo;
//~^ ERROR generic associated types are unstable
}
+trait Bar {
+ type Assoc where Self: Sized;
+ //~^ ERROR where clauses on associated types are unstable
+}
+
+
fn main() {}
|
= help: add #![feature(generic_associated_types)] to the crate attributes to enable
+error[E0658]: where clauses on associated types are unstable (see issue #44265)
+ --> $DIR/feature-gate-generic_associated_types.rs:16:5
+ |
+LL | type Pointer2<T>: Deref<Target = T> where T: Clone, U: Clone;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(generic_associated_types)] to the crate attributes to enable
+
error[E0658]: generic associated types are unstable (see issue #44265)
- --> $DIR/feature-gate-generic_associated_types.rs:22:5
+ --> $DIR/feature-gate-generic_associated_types.rs:23:5
|
LL | type Pointer<usize> = Box<usize>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: add #![feature(generic_associated_types)] to the crate attributes to enable
error[E0658]: generic associated types are unstable (see issue #44265)
- --> $DIR/feature-gate-generic_associated_types.rs:24:5
+ --> $DIR/feature-gate-generic_associated_types.rs:25:5
|
LL | type Pointer2<u32> = Box<u32>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(generic_associated_types)] to the crate attributes to enable
-error: aborting due to 4 previous errors
+error[E0658]: where clauses on associated types are unstable (see issue #44265)
+ --> $DIR/feature-gate-generic_associated_types.rs:30:5
+ |
+LL | type Assoc where Self: Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(generic_associated_types)] to the crate attributes to enable
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that ! errors when used in illegal positions with feature(never_type) disabled
+
+trait Foo {
+ type Wub;
+}
+
+type Ma = (u32, !, i32); //~ ERROR type is experimental
+type Meeshka = Vec<!>; //~ ERROR type is experimental
+type Mow = &fn(!) -> !; //~ ERROR type is experimental
+type Skwoz = &mut !; //~ ERROR type is experimental
+
+impl Foo for Meeshka {
+ type Wub = !; //~ ERROR type is experimental
+}
+
+fn main() {
+}
--- /dev/null
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:17:17
+ |
+LL | type Ma = (u32, !, i32); //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:18:20
+ |
+LL | type Meeshka = Vec<!>; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:19:16
+ |
+LL | type Mow = &fn(!) -> !; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:20:19
+ |
+LL | type Skwoz = &mut !; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error[E0658]: The `!` type is experimental (see issue #35121)
+ --> $DIR/feature-gate-never_type.rs:23:16
+ |
+LL | type Wub = !; //~ ERROR type is experimental
+ | ^
+ |
+ = help: add #![feature(never_type)] to the crate attributes to enable
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[target_feature = "+sse2"]
-//~^ the `#[target_feature]` attribute is an experimental feature
-fn foo() {}
+++ /dev/null
-error[E0658]: the `#[target_feature]` attribute is an experimental feature
- --> $DIR/feature-gate-target_feature.rs:11:1
- |
-LL | #[target_feature = "+sse2"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add #![feature(target_feature)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+error[E0382]: use of moved value: `foo.x`
+ --> $DIR/fields-move.rs:38:42
+ |
+LL | $foo.x
+ | ------ value moved here
+...
+LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
+ | ^^^^^ value used here after move
+ |
+ = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `foo.x`
+ --> $DIR/fields-move.rs:28:9
+ |
+LL | $foo.x
+ | ------ value moved here
+...
+LL | $foo.x //~ ERROR use of moved value: `foo.x`
+ | ^^^^^^ value used here after move
+...
+LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
+ | ----- value moved here
+LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
+ | ----------------- in this macro invocation
+ |
+ = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `foo.x`
+ --> $DIR/fields-move.rs:39:42
+ |
+LL | $foo.x
+ | ------ value moved here
+...
+LL | $foo.x //~ ERROR use of moved value: `foo.x`
+ | ------ value moved here
+...
+LL | assert_two_copies(copy_modern!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
+ | ----- value moved here
+LL | assert_two_copies(copy_legacy!(foo), foo.x); //~ ERROR use of moved value: `foo.x`
+ | ^^^^^ value used here after move
+ |
+ = note: move occurs because `foo.x` has type `NonCopy`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+error: compilation successful
+ --> $DIR/fields-numeric-borrowck.rs:13:1
+ |
+LL | / fn main() { #![rustc_error] // rust-lang/rust#49855
+LL | | let mut s = S(0);
+LL | | let borrow1 = &mut s.0;
+LL | | let S { 0: ref mut borrow2 } = s;
+LL | | //~^ ERROR cannot borrow `s.0` as mutable more than once at a time
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![feature(rustc_attrs)]
struct S(u8);
-fn main() {
+fn main() { #![rustc_error] // rust-lang/rust#49855
let mut s = S(0);
let borrow1 = &mut s.0;
let S { 0: ref mut borrow2 } = s;
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
struct S { x: u32 }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub fn f() {}
// ignore-pretty pretty-printing is unhygienic
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
struct S;
// error-pattern:type `fn() -> u32 {intercrate::foo::bar::f}` is private
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
extern crate intercrate;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub macro m() { Vec::new(); ().clone() }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
fn f() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(decl_macro)]
+#![feature(decl_macro, proc_macro_path_invoc)]
mod foo {
pub trait T {
// independently resolved and only require the concrete
// return type, which can't depend on the obligation.
fn cycle1() -> impl Clone {
- //~^ ERROR cyclic dependency detected
- //~| cyclic reference
+ //~^ ERROR cycle detected
send(cycle2().clone());
Rc::new(Cell::new(5))
LL | fn send<T: Send>(_: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^
-error[E0391]: cyclic dependency detected
- --> $DIR/auto-trait-leak.rs:42:1
- |
-LL | fn cycle1() -> impl Clone {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ cyclic reference
- |
-note: the cycle begins when processing `cycle1`...
+error[E0391]: cycle detected when processing `cycle1`
--> $DIR/auto-trait-leak.rs:42:1
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which then requires processing `cycle2::{{impl-Trait}}`...
- --> $DIR/auto-trait-leak.rs:50:16
+ |
+note: ...which requires processing `cycle2::{{impl-Trait}}`...
+ --> $DIR/auto-trait-leak.rs:49:16
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^
-note: ...which then requires processing `cycle2`...
- --> $DIR/auto-trait-leak.rs:50:1
+note: ...which requires processing `cycle2`...
+ --> $DIR/auto-trait-leak.rs:49:1
|
LL | fn cycle2() -> impl Clone {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which then requires processing `cycle1::{{impl-Trait}}`...
+note: ...which requires processing `cycle1::{{impl-Trait}}`...
--> $DIR/auto-trait-leak.rs:42:16
|
LL | fn cycle1() -> impl Clone {
| ^^^^^^^^^^
- = note: ...which then again requires processing `cycle1`, completing the cycle.
+ = note: ...which again requires processing `cycle1`, completing the cycle
+note: cycle used when type-checking all item bodies
error: aborting due to 3 previous errors
| ^^^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
- = note: the following traits define an item `is_empty`, perhaps you need to implement one of them:
+ = note: the following trait defines an item `is_empty`, perhaps you need to implement it:
candidate #1: `std::iter::ExactSizeIterator`
- candidate #2: `core::slice::SliceExt`
- candidate #3: `core::str::StrExt`
error: aborting due to previous error
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
extern crate two_macros;
// aux-build:two_macros.rs
-#![feature(use_extern_macros)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
mod foo {
extern crate two_macros;
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/dyn-trait.rs:33:16
|
LL | static_val(x); //~ ERROR cannot infer
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/mismatched.rs:14:42
|
LL | fn foo(x: &'a u32, y: &u32) -> &'a u32 { y } //~ ERROR explicit lifetime required
| ^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/mismatched.rs:16:46
|
LL | fn foo2(x: &'a u32, y: &'b u32) -> &'a u32 { y } //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/mismatched_trait.rs:16:9
|
LL | y //~ ERROR explicit lifetime required
// except according to those terms.
trait t1 : t2 {
+//~^ ERROR cycle detected
}
trait t2 : t1 {
-//~^ ERROR cyclic dependency detected
-//~| cyclic reference
}
fn main() { }
-error[E0391]: cyclic dependency detected
- --> $DIR/issue-12511.rs:14:1
- |
-LL | trait t2 : t1 {
- | ^^^^^^^^^^^^^ cyclic reference
- |
-note: the cycle begins when computing the supertraits of `t1`...
+error[E0391]: cycle detected when computing the supertraits of `t1`
--> $DIR/issue-12511.rs:11:1
|
LL | trait t1 : t2 {
| ^^^^^^^^^^^^^
-note: ...which then requires computing the supertraits of `t2`...
- --> $DIR/issue-12511.rs:11:1
|
-LL | trait t1 : t2 {
+note: ...which requires computing the supertraits of `t2`...
+ --> $DIR/issue-12511.rs:15:1
+ |
+LL | trait t2 : t1 {
| ^^^^^^^^^^^^^
- = note: ...which then again requires computing the supertraits of `t1`, completing the cycle.
+ = note: ...which again requires computing the supertraits of `t1`, completing the cycle
error: aborting due to previous error
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/issue-13058.rs:24:21
|
LL | let cont_iter = cont.iter();
| ^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/issue-13058.rs:24:26
|
LL | let cont_iter = cont.iter();
-error[E0391]: cyclic dependency detected
- --> $DIR/issue-23302-1.rs:14:9
- |
-LL | A = X::A as isize, //~ ERROR E0391
- | ^^^^^^^^^^^^^ cyclic reference
- |
-note: the cycle begins when const-evaluating `X::A::{{initializer}}`...
- --> $DIR/issue-23302-1.rs:14:9
- |
-LL | A = X::A as isize, //~ ERROR E0391
- | ^^^^^^^^^^^^^
-note: ...which then requires computing layout of `X`...
+error[E0391]: cycle detected when const-evaluating `X::A::{{initializer}}`
--> $DIR/issue-23302-1.rs:14:9
|
LL | A = X::A as isize, //~ ERROR E0391
| ^^^^
- = note: ...which then again requires const-evaluating `X::A::{{initializer}}`, completing the cycle.
+ |
+note: ...which requires computing layout of `X`...
+ = note: ...which again requires const-evaluating `X::A::{{initializer}}`, completing the cycle
error: aborting due to previous error
-error[E0391]: cyclic dependency detected
- --> $DIR/issue-23302-2.rs:14:9
- |
-LL | A = Y::B as isize, //~ ERROR E0391
- | ^^^^^^^^^^^^^ cyclic reference
- |
-note: the cycle begins when const-evaluating `Y::A::{{initializer}}`...
- --> $DIR/issue-23302-2.rs:14:9
- |
-LL | A = Y::B as isize, //~ ERROR E0391
- | ^^^^^^^^^^^^^
-note: ...which then requires computing layout of `Y`...
+error[E0391]: cycle detected when const-evaluating `Y::A::{{initializer}}`
--> $DIR/issue-23302-2.rs:14:9
|
LL | A = Y::B as isize, //~ ERROR E0391
| ^^^^
- = note: ...which then again requires const-evaluating `Y::A::{{initializer}}`, completing the cycle.
+ |
+note: ...which requires computing layout of `Y`...
+ = note: ...which again requires const-evaluating `Y::A::{{initializer}}`, completing the cycle
error: aborting due to previous error
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const A: i32 = B;
+const A: i32 = B; //~ ERROR cycle detected
-const B: i32 = A; //~ ERROR cyclic dependency detected
+const B: i32 = A;
fn main() { }
-error[E0391]: cyclic dependency detected
- --> $DIR/issue-23302-3.rs:13:16
- |
-LL | const B: i32 = A; //~ ERROR cyclic dependency detected
- | ^ cyclic reference
- |
-note: the cycle begins when const checking if rvalue is promotable to static `A`...
+error[E0391]: cycle detected when const checking if rvalue is promotable to static `A`
--> $DIR/issue-23302-3.rs:11:1
|
-LL | const A: i32 = B;
+LL | const A: i32 = B; //~ ERROR cycle detected
| ^^^^^^^^^^^^^^^^^
-note: ...which then requires checking which parts of `A` are promotable to static...
- --> $DIR/issue-23302-3.rs:11:1
|
-LL | const A: i32 = B;
- | ^^^^^^^^^^^^^^^^^
-note: ...which then requires const checking if rvalue is promotable to static `B`...
+note: ...which requires checking which parts of `A` are promotable to static...
--> $DIR/issue-23302-3.rs:11:16
|
-LL | const A: i32 = B;
+LL | const A: i32 = B; //~ ERROR cycle detected
| ^
-note: ...which then requires checking which parts of `B` are promotable to static...
+note: ...which requires const checking if rvalue is promotable to static `B`...
--> $DIR/issue-23302-3.rs:13:1
|
-LL | const B: i32 = A; //~ ERROR cyclic dependency detected
+LL | const B: i32 = A;
| ^^^^^^^^^^^^^^^^^
- = note: ...which then again requires const checking if rvalue is promotable to static `A`, completing the cycle.
+note: ...which requires checking which parts of `B` are promotable to static...
+ --> $DIR/issue-23302-3.rs:13:16
+ |
+LL | const B: i32 = A;
+ | ^
+ = note: ...which again requires const checking if rvalue is promotable to static `A`, completing the cycle
error: aborting due to previous error
-error[E0391]: cyclic dependency detected
- --> $DIR/issue-36163.rs:14:9
- |
-LL | B = A, //~ ERROR E0391
- | ^ cyclic reference
- |
-note: the cycle begins when const-evaluating `Foo::B::{{initializer}}`...
+error[E0391]: cycle detected when const-evaluating `Foo::B::{{initializer}}`
--> $DIR/issue-36163.rs:14:9
|
LL | B = A, //~ ERROR E0391
| ^
-note: ...which then requires processing `Foo::B::{{initializer}}`...
+ |
+note: ...which requires processing `Foo::B::{{initializer}}`...
--> $DIR/issue-36163.rs:14:9
|
LL | B = A, //~ ERROR E0391
| ^
-note: ...which then requires const-evaluating `A`...
- --> $DIR/issue-36163.rs:11:1
- |
-LL | const A: isize = Foo::B as isize;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-note: ...which then requires computing layout of `Foo`...
+note: ...which requires const-evaluating `A`...
--> $DIR/issue-36163.rs:11:18
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^
- = note: ...which then again requires const-evaluating `Foo::B::{{initializer}}`, completing the cycle.
+note: ...which requires computing layout of `Foo`...
+ = note: ...which again requires const-evaluating `Foo::B::{{initializer}}`, completing the cycle
error: aborting due to previous error
LL | f(&mut *x); //~ ERROR cannot borrow immutable
| ^^^^^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `x`
+ = note: the value which is causing this path not to be mutable is...: `x`
error: aborting due to previous error
+++ /dev/null
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
- --> $DIR/issue-45697-1.rs:30:9
- |
-LL | let z = copy_borrowed_ptr(&mut y);
- | - borrow of `*y.pointer` occurs here
-LL | *y.pointer += 1;
- | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
-
-error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
- --> $DIR/issue-45697-1.rs:30:9
- |
-LL | let z = copy_borrowed_ptr(&mut y);
- | ------ borrow of `y` occurs here
-LL | *y.pointer += 1;
- | ^^^^^^^^^^^^^^^ use of borrowed `y`
-...
-LL | *z.pointer += 1;
- | --------------- borrow later used here
-
-error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
- --> $DIR/issue-45697-1.rs:30:9
- |
-LL | let z = copy_borrowed_ptr(&mut y);
- | ------ borrow of `*y.pointer` occurs here
-LL | *y.pointer += 1;
- | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
-...
-LL | *z.pointer += 1;
- | --------------- borrow later used here
-
-error: aborting due to 3 previous errors
-
-Some errors occurred: E0503, E0506.
-For more information about an error, try `rustc --explain E0503`.
*y.pointer += 1;
//~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506]
//~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503]
+ //~| ERROR cannot assign to `*y.pointer` because it is borrowed (Mir) [E0506]
*z.pointer += 1;
}
}
| ------ borrow of `y` occurs here
LL | *y.pointer += 1;
| ^^^^^^^^^^^^^^^ use of borrowed `y`
+...
+LL | *z.pointer += 1;
+ | --------------- borrow later used here
-error: aborting due to 2 previous errors
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
+ --> $DIR/issue-45697-1.rs:30:9
+ |
+LL | let z = copy_borrowed_ptr(&mut y);
+ | ------ borrow of `*y.pointer` occurs here
+LL | *y.pointer += 1;
+ | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+...
+LL | *z.pointer += 1;
+ | --------------- borrow later used here
+
+error: aborting due to 3 previous errors
Some errors occurred: E0503, E0506.
For more information about an error, try `rustc --explain E0503`.
*y.pointer += 1;
//~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506]
//~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503]
+ //~| ERROR cannot assign to `*y.pointer` because it is borrowed (Mir) [E0506]
*z.pointer += 1;
}
}
| ------ borrow of `y` occurs here
LL | *y.pointer += 1;
| ^^^^^^^^^^^^^^^ use of borrowed `y`
+...
+LL | *z.pointer += 1;
+ | --------------- borrow later used here
-error: aborting due to 2 previous errors
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Mir)
+ --> $DIR/issue-45697.rs:30:9
+ |
+LL | let z = copy_borrowed_ptr(&mut y);
+ | ------ borrow of `*y.pointer` occurs here
+LL | *y.pointer += 1;
+ | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+...
+LL | *z.pointer += 1;
+ | --------------- borrow later used here
+
+error: aborting due to 3 previous errors
Some errors occurred: E0503, E0506.
For more information about an error, try `rustc --explain E0503`.
+++ /dev/null
-error[E0597]: `z` does not live long enough (Ast)
- --> $DIR/issue-46471-1.rs:16:14
- |
-LL | &mut z
- | ^ borrowed value does not live long enough
-LL | };
- | - `z` dropped here while still borrowed
-...
-LL | }
- | - borrowed value needs to live until here
-
-error[E0597]: `z` does not live long enough (Mir)
- --> $DIR/issue-46471-1.rs:16:9
- |
-LL | let y = {
- | _____________-
-LL | | let mut z = 0;
-LL | | &mut z
- | | ^^^^^^ borrowed value does not live long enough
-LL | | };
- | | -
- | | |
- | |_____borrowed value only lives until here
- | borrow later used here
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0597`.
error[E0597]: `z` does not live long enough (Mir)
--> $DIR/issue-46471-1.rs:16:9
|
-LL | &mut z
- | ^^^^^^ borrowed value does not live long enough
-LL | };
- | - `z` dropped here while still borrowed
-...
-LL | }
- | - borrowed value needs to live until here
+LL | let y = {
+ | _____________-
+LL | | let mut z = 0;
+LL | | &mut z
+ | | ^^^^^^ borrowed value does not live long enough
+LL | | };
+ | | -
+ | | |
+ | |_____borrowed value only lives until here
+ | borrow later used here
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S {
+ x: u8
+ /// The id of the parent core
+ y: u8,
+}
+//~^^^ ERROR found a documentation comment that doesn't document anything
+fn main() {}
--- /dev/null
+error[E0585]: found a documentation comment that doesn't document anything
+ --> $DIR/issue-48636.rs:13:5
+ |
+LL | x: u8
+ | - help: missing comma here: `,`
+LL | /// The id of the parent core
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: doc comments must come before what they document, maybe a comment was intended with `//`?
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0585`.
--- /dev/null
+//~ ERROR 1:1: 1:1: can't find crate for `core` [E0463]
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --target thumbv7em-none-eabihf
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![no_std]
+
+extern crate cortex_m;
+
--- /dev/null
+error[E0463]: can't find crate for `core`
+ |
+ = note: the `thumbv7em-none-eabihf` target may not be installed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0463`.
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/42701_one_named_and_one_anonymous.rs:20:9
|
LL | &*x //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:21:21
|
LL | other //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-if-else-2.rs:12:16
|
LL | if x > y { x } else { y } //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-if-else-3.rs:12:27
|
LL | if x > y { x } else { y } //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:14:15
|
LL | if x > y { x } else { y } //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:18:36
|
LL | if true { &self.field } else { x } //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-if-else-using-impl.rs:21:20
|
LL | if x > y { x } else { y } //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-if-else.rs:12:27
|
LL | if x > y { x } else { y } //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:18:5
|
LL | x //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex1-return-one-existing-name-self-is-anon.rs:18:30
|
LL | if true { x } else { self } //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex2a-push-one-existing-name-2.rs:16:12
|
LL | y.push(x); //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex2a-push-one-existing-name-early-bound.rs:17:12
|
LL | x.push(y); //~ ERROR explicit lifetime required
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex2a-push-one-existing-name.rs:16:12
|
LL | x.push(y); //~ ERROR explicit lifetime
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex2b-push-no-existing-names.rs:16:12
|
LL | x.push(y); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex2c-push-inference-variable.rs:16:13
|
LL | let z = Ref { data: y.data };
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex2d-push-inference-variable-2.rs:17:13
|
LL | let b = Ref { data: y.data };
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex2e-push-inference-variable-3.rs:17:13
|
LL | let b = Ref { data: y.data };
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-2.rs:12:9
|
LL | v = x; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-3.rs:12:13
|
LL | z.push((x,y)); //~ ERROR lifetime mismatch
| ^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-3.rs:12:15
|
LL | z.push((x,y)); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-both-are-structs-2.rs:16:11
|
LL | x.b = y.b; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-both-are-structs-3.rs:16:11
|
LL | x.a = x.b; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-both-are-structs-4.rs:16:11
|
LL | x.a = x.b; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-both-are-structs-earlybound-regions.rs:18:12
|
LL | x.push(y); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-both-are-structs-latebound-regions.rs:15:12
|
LL | x.push(y); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-both-are-structs.rs:15:12
|
LL | x.push(y); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-latebound-regions.rs:12:12
|
LL | x.push(y); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:14:9
|
LL | y = x.b; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-one-is-struct-3.rs:14:11
|
LL | y.b = x; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-one-is-struct-4.rs:14:11
|
LL | y.b = x; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-one-is-struct.rs:17:11
|
LL | x.b = y; //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:17:5
|
LL | x //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-self-is-anon.rs:17:19
|
LL | if true { x } else { self } //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-using-fn-items.rs:11:10
|
LL | y.push(z); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-using-impl-items.rs:15:16
|
LL | x.push(y); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions-using-trait-objects.rs:11:10
|
LL | y.push(z); //~ ERROR lifetime mismatch
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ex3-both-anon-regions.rs:12:12
|
LL | x.push(y); //~ ERROR lifetime mismatch
macro_rules! real_method_stmt {
() => {
- 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
}
}
macro_rules! real_method_expr {
() => {
- 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
}
}
LL | fake_anon_field_stmt!();
| ------------------------ in this macro invocation
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/macro-backtrace-invalid-internals.rs:51:15
|
-LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
- | ^^^^
+LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
+ | ^^^^^
...
LL | real_method_stmt!();
| -------------------- in this macro invocation
help: you must specify a concrete type for this numeric value, like `f32`
|
-LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
| ^^^^^^^
error[E0599]: no method named `fake` found for type `{integer}` in the current scope
LL | let _ = fake_anon_field_expr!();
| ----------------------- in this macro invocation
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/macro-backtrace-invalid-internals.rs:57:15
|
-LL | 2.0.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
- | ^^^^
+LL | 2.0.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
+ | ^^^^^
...
LL | let _ = real_method_expr!();
| ------------------- in this macro invocation
help: you must specify a concrete type for this numeric value, like `f32`
|
-LL | 2.0_f32.powi(2) //~ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+LL | 2.0_f32.recip() //~ ERROR can't call method `recip` on ambiguous numeric type `{float}`
| ^^^^^^^
error: aborting due to 8 previous errors
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+struct Foo { a: u8 }
+fn bar() -> Foo {
+ Foo { a: 5 }
+}
+
+static foo: Foo = bar();
+//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
+
+fn main() {}
--- /dev/null
+error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+ --> $DIR/mir_check_nonconst.rs:18:19
+ |
+LL | static foo: Foo = bar();
+ | ^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
// that appear free in its type (hence, we see it before the closure's
// "external requirements" report).
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
let y = 22;
let mut closure = expect_sig(|p, y| *p = y);
//~^ ERROR does not outlive free region
- //~| WARNING not reporting region error due to -Znll
+ //~| WARNING not reporting region error due to nll
closure(&mut p, &y);
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/escape-argument-callee.rs:36:50
|
LL | let mut closure = expect_sig(|p, y| *p = y);
// basically checking that the MIR type checker correctly enforces the
// closure signature.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
//
// except that the closure does so via a second closure.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
// `'b`. This relationship is propagated to the closure creator,
// which reports an error.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
// Test where we fail to approximate due to demanding a postdom
// relationship between our upper bounds.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
|_outlives1, _outlives2, _outlives3, x, y| {
// Only works if 'x: 'y:
let p = x.get();
- //~^ WARN not reporting region error due to -Znll
+ //~^ WARN not reporting region error due to nll
//~| ERROR does not outlive free region
demand_y(x, y, p)
},
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-approximated-fail-no-postdom.rs:55:21
|
LL | let p = x.get();
LL | / |_outlives1, _outlives2, _outlives3, x, y| {
LL | | // Only works if 'x: 'y:
LL | | let p = x.get();
-LL | | //~^ WARN not reporting region error due to -Znll
+LL | | //~^ WARN not reporting region error due to nll
LL | | //~| ERROR does not outlive free region
LL | | demand_y(x, y, p)
LL | | },
// Note: the use of `Cell` here is to introduce invariance. One less
// variable.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
//~^ ERROR lifetime mismatch
// Only works if 'x: 'y:
- demand_y(x, y, x.get()) //~ WARNING not reporting region error due to -Znll
+ demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
});
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-approximated-ref.rs:57:9
|
-LL | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to -Znll
+LL | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
| ^^^^^^^^^^^^^^^^^^^^^^^
note: External requirements
LL | | //~^ ERROR lifetime mismatch
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to -Znll
+LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
LL | | });
| |_____^
|
// where `'x` is bound in closure type but `'a` is free. This forces
// us to approximate `'x` one way or the other.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
let a = 0;
let cell = Cell::new(&a);
foo(cell, |cell_a, cell_x| {
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
//~^ ERROR does not outlive free region
})
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:31:5
|
LL | foo(cell, |cell_a, cell_x| {
|
LL | foo(cell, |cell_a, cell_x| {
| _______________^
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | cell_a.set(cell_x.get()); // forces 'x: 'a, error in closure
LL | | //~^ ERROR does not outlive free region
LL | | })
// FIXME(#45827) Because of shortcomings in the MIR type checker,
// these errors are not (yet) reported.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
//~^ ERROR does not outlive free region
// Only works if 'x: 'y:
- demand_y(x, y, x.get()) //~ WARNING not reporting region error due to -Znll
+ demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
});
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:49:9
|
-LL | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to -Znll
+LL | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
| ^^^^^^^^^^^^^^^^^^^^^^^
note: External requirements
LL | | //~^ ERROR does not outlive free region
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to -Znll
+LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
LL | | });
| |_____^
|
LL | | //~^ ERROR does not outlive free region
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to -Znll
+LL | | demand_y(x, y, x.get()) //~ WARNING not reporting region error due to nll
LL | | });
| |_____^
// FIXME(#45827) Because of shortcomings in the MIR type checker,
// these errors are not (yet) reported.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
//~^ ERROR does not outlive free region
// Only works if 'x: 'y:
demand_y(x, y, x.get())
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
});
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:51:9
|
LL | demand_y(x, y, x.get())
LL | | //~^ ERROR does not outlive free region
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | });
| |_____^
|
LL | | //~^ ERROR does not outlive free region
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | });
| |_____^
// relationships. In the 'main' variant, there are a number of
// anonymous regions as well.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
//~^ ERROR lifetime mismatch
// Only works if 'x: 'y:
- demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to -Znll
+ demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to nll
});
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-approximated-val.rs:50:9
|
-LL | demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to -Znll
+LL | demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to nll
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: External requirements
LL | | //~^ ERROR lifetime mismatch
LL | |
LL | | // Only works if 'x: 'y:
-LL | | demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to -Znll
+LL | | demand_y(outlives1, outlives2, x.get()) //~ WARNING not reporting region error due to nll
LL | | });
| |_____^
|
// need to propagate; but in fact we do because identity of free
// regions is erased.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass
#![feature(rustc_attrs)]
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-despite-same-free-region.rs:54:21
|
LL | let p = x.get();
// as it knows of no relationships between `'x` and any
// non-higher-ranked regions.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
- //~^ WARN not reporting region error due to -Znll
+ //~^ WARN not reporting region error due to nll
//~| ERROR does not outlive free region
});
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:47:9
|
LL | demand_y(x, y, x.get())
| _______________________________________________^
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARN not reporting region error due to -Znll
+LL | | //~^ WARN not reporting region error due to nll
LL | | //~| ERROR does not outlive free region
LL | | });
| |_____^
// as it only knows of regions that `'x` is outlived by, and none that
// `'x` outlives.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
// Only works if 'x: 'y:
demand_y(x, y, x.get())
- //~^ WARN not reporting region error due to -Znll
+ //~^ WARN not reporting region error due to nll
//~| ERROR does not outlive free region
});
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:51:9
|
LL | demand_y(x, y, x.get())
| _______________________________________________^
LL | | // Only works if 'x: 'y:
LL | | demand_y(x, y, x.get())
-LL | | //~^ WARN not reporting region error due to -Znll
+LL | | //~^ WARN not reporting region error due to nll
LL | | //~| ERROR does not outlive free region
LL | | });
| |_____^
// the same `'a` for which it implements `Trait`, which can only be the `'a`
// from the function definition.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#![allow(dead_code)]
// The latter does not hold.
require(value);
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
});
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/propagate-from-trait-match.rs:55:9
|
LL | require(value);
LL | |
LL | | // This function call requires that
... |
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | });
| |_____^
|
LL | |
LL | | // This function call requires that
... |
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | });
| |_____^
|
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
fn foo(x: &u32) -> &'static u32 {
&*x
- //~^ WARN not reporting region error due to -Znll
+ //~^ WARN not reporting region error due to nll
//~| ERROR explicit lifetime required in the type of `x`
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/region-lbr-anon-does-not-outlive-static.rs:19:5
|
LL | &*x
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
fn foo<'a>(x: &'a u32) -> &'static u32 {
&*x
- //~^ WARN not reporting region error due to -Znll
+ //~^ WARN not reporting region error due to nll
//~| ERROR does not outlive free region
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/region-lbr-named-does-not-outlive-static.rs:19:5
|
LL | &*x
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> &'b u32 {
&*x
- //~^ WARN not reporting region error due to -Znll
+ //~^ WARN not reporting region error due to nll
//~| ERROR lifetime mismatch
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/region-lbr1-does-not-outlive-ebr2.rs:19:5
|
LL | &*x
// Basic test for free regions in the NLL code. This test does not
// report an error because of the (implied) bound that `'b: 'a`.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass
#![allow(warnings)]
// the first, but actually returns the second. This should fail within
// the closure.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![feature(rustc_attrs)]
#[rustc_regions]
fn test() {
expect_sig(|a, b| b); // ought to return `a`
- //~^ WARN not reporting region error due to -Znll
+ //~^ WARN not reporting region error due to nll
//~| ERROR does not outlive free region
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/return-wrong-bound-region.rs:21:23
|
LL | expect_sig(|a, b| b); // ought to return `a`
|
LL | / fn test() {
LL | | expect_sig(|a, b| b); // ought to return `a`
-LL | | //~^ WARN not reporting region error due to -Znll
+LL | | //~^ WARN not reporting region error due to nll
LL | | //~| ERROR does not outlive free region
LL | | }
| |_^
// Test that MIR borrowck and NLL analysis can handle constants of
// arbitrary types without ICEs.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass
const HI: &str = "hi";
// in the type of `p` includes the points after `&v[0]` up to (but not
// including) the call to `use_x`. The `else` branch is not included.
-// compile-flags:-Znll -Zborrowck=mir
+// compile-flags:-Zborrowck=mir
// compile-pass
#![allow(warnings)]
// because of destructor. (Note that the stderr also identifies this
// destructor in the error message.)
-// compile-flags:-Znll -Zborrowck=mir
+// compile-flags:-Zborrowck=mir
#![allow(warnings)]
#![feature(dropck_eyepatch)]
// a variety of errors from the older, AST-based machinery (notably
// borrowck), and then we get the NLL error at the end.
-// compile-flags:-Znll -Zborrowck=compare
+// compile-flags:-Zborrowck=compare
struct Map {
}
--> $DIR/issue-47388.rs:18:5
|
LL | let fancy_ref = &(&mut fancy);
- | ------------- help: consider changing this to be a mutable reference: `&mut`
+ | ------------- help: consider changing this to be a mutable reference: `&mut (&mut fancy)`
LL | fancy_ref.num = 6; //~ ERROR E0594
| ^^^^^^^^^^^^^^^^^ `fancy_ref` is a `&` reference, so the data it refers to cannot be written
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
+//compile-flags: -Z emit-end-regions -Zborrowck=mir
#![allow(warnings)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//compile-flags: -Z emit-end-regions -Zborrowck=mir -Z nll
+// compile-flags: -Z emit-end-regions -Zborrowck=mir
// compile-pass
#![allow(warnings)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
+//compile-flags: -Z emit-end-regions -Zborrowck=mir
#![allow(warnings)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
+//compile-flags: -Z emit-end-regions -Zborrowck=mir
#![allow(warnings)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//compile-flags: -Z emit-end-regions -Zborrowck=mir -Znll
+//compile-flags: -Z emit-end-regions -Zborrowck=mir
#![allow(warnings)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir
+// compile-flags:-Zborrowck=mir
// compile-pass
#![feature(rustc_attrs)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
fn foo<'a, T>(x: &T) -> impl Foo<'a> {
x
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR explicit lifetime required in the type of `x` [E0621]
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/impl-trait-captures.rs:21:5
|
LL | x
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
use std::fmt::Debug;
fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
where
T: Debug,
{
}
fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
where
T: 'b + Debug,
{
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/impl-trait-outlives.rs:17:35
|
LL | fn no_region<'a, T>(x: Box<T>) -> impl Debug + 'a
| ^^^^^^^^^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/impl-trait-outlives.rs:33:42
|
LL | fn wrong_region<'a, 'b, T>(x: Box<T>) -> impl Debug + 'a
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
// Test that we can deduce when projections like `T::Item` outlive the
// function body. Test that this does not imply that `T: 'a` holds.
#[rustc_errors]
fn generic2<T: Iterator>(value: T) {
twice(value, |value_ref, item| invoke2(value_ref, item));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the parameter type `T` may not live long enough
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-implied-bounds.rs:45:36
|
LL | twice(value, |value_ref, item| invoke2(value_ref, item));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
// Tests closures that propagate an outlives relationship to their
// creator where the subject is a projection with no regions (`<T as
T: Iterator,
{
with_signature(x, |mut y| Box::new(y.next()))
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
T: 'b + Iterator,
{
with_signature(x, |mut y| Box::new(y.next()))
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-no-regions-closure.rs:36:31
|
LL | with_signature(x, |mut y| Box::new(y.next()))
| ^^^^^^^^^^^^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-no-regions-closure.rs:54:31
|
LL | with_signature(x, |mut y| Box::new(y.next()))
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
T: Iterator,
{
Box::new(x.next())
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
T: 'b + Iterator,
{
Box::new(x.next())
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| the associated type `<T as std::iter::Iterator>::Item` may not live long enough
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-no-regions-fn.rs:24:5
|
LL | Box::new(x.next())
| ^^^^^^^^^^^^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-no-regions-fn.rs:40:5
|
LL | Box::new(x.next())
//
// Ensuring that both `T: 'a` and `'b: 'a` holds does work (`elements_outlive`).
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
T: Anything<'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR does not outlive free region
}
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR does not outlive free region
}
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the parameter type `T` may not live long enough
//~| ERROR free region `ReEarlyBound(1, 'b)` does not outlive free region `ReEarlyBound(0, 'a)`
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-one-region-closure.rs:56:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-one-region-closure.rs:68:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-one-region-closure.rs:90:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
// case, the best way to satisfy the trait bound is to show that `'b:
// 'a`, which can be done in various ways.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
T: Anything<'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR does not outlive free region
}
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR does not outlive free region
}
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR does not outlive free region
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-one-region-trait-bound-closure.rs:48:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-one-region-trait-bound-closure.rs:59:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-one-region-trait-bound-closure.rs:80:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
// outlive `'static`. In this case, we don't get any errors, and in fact
// we don't even propagate constraints from the closures to the callers.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass
#![allow(warnings)]
// the trait bound, and hence we propagate it to the caller as a type
// test.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
T: Anything<'b, 'c>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR associated type `<T as Anything<'_#5r, '_#6r>>::AssocType` may not live long enough
}
'a: 'a,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
}
// can do better here with a more involved verification step.
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR associated type `<T as Anything<'_#6r, '_#7r>>::AssocType` may not live long enough
}
T: Anything<'b, 'b>,
{
with_signature(cell, t, |cell, t| require(cell, t));
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR does not outlive free region
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-two-region-trait-bound-closure.rs:49:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-two-region-trait-bound-closure.rs:60:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-two-region-trait-bound-closure.rs:81:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/projection-two-region-trait-bound-closure.rs:109:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-closure-approximate-lower-bound.rs:35:31
|
LL | twice(cell, value, |a, b| invoke(a, b));
| ^^^^^^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31
|
LL | twice(cell, value, |a, b| invoke(a, b));
| ^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31
|
LL | twice(cell, value, |a, b| invoke(a, b));
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
// `'a` (and subsequently reports an error).
with_signature(x, |y| y)
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the parameter type `T` may not live long enough
}
T: 'b + Debug,
{
x
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the parameter type `T` may not live long enough
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-closure-outlives-from-return-type.rs:37:27
|
LL | with_signature(x, |y| y)
| ^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-closure-outlives-from-return-type.rs:53:5
|
LL | x
// `correct_region` for an explanation of how this test is setup; it's
// somewhat intricate.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
#![allow(warnings)]
#![feature(dyn_trait)]
// function, there is no where clause *anywhere*, and hence we
// get an error (but reported by the closure creator).
require(&x, &y)
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
})
}
//~^ ERROR the parameter type `T` may not live long enough
// See `correct_region`
require(&x, &y)
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
})
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:45:9
|
LL | require(&x, &y)
| ^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-closure-outlives-from-where-clause.rs:79:9
|
LL | require(&x, &y)
LL | | //
LL | | // See `correct_region`, which explains the point of this
... |
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | })
| |_____^
|
LL | | //
LL | | // See `correct_region`, which explains the point of this
... |
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | })
| |_____^
|
LL | | //~^ ERROR the parameter type `T` may not live long enough
LL | | // See `correct_region`
LL | | require(&x, &y)
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | })
| |_____^
|
LL | | //~^ ERROR the parameter type `T` may not live long enough
LL | | // See `correct_region`
LL | | require(&x, &y)
-LL | | //~^ WARNING not reporting region error due to -Znll
+LL | | //~^ WARNING not reporting region error due to nll
LL | | })
| |_____^
|
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir
+// compile-flags:-Zborrowck=mir
// Test that we assume that universal types like `T` outlive the
// function body.
// Error here, because T: 'a is not satisfied.
fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) {
outlives(cell, t)
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| ERROR the parameter type `T` may not live long enough
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-fn-body.rs:30:5
|
LL | outlives(cell, t)
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir
+// compile-flags:-Zborrowck=mir
#![allow(warnings)]
#![feature(dyn_trait)]
T: Debug,
{
x
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| the parameter type `T` may not live long enough
}
T: 'b + Debug,
{
x
- //~^ WARNING not reporting region error due to -Znll
+ //~^ WARNING not reporting region error due to nll
//~| the parameter type `T` may not live long enough
}
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-fn.rs:22:5
|
LL | x
| ^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/ty-param-fn.rs:38:5
|
LL | x
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:-Znll -Zborrowck=mir -Zverbose
+// compile-flags:-Zborrowck=mir -Zverbose
// compile-pass
// Test that we assume that universal types like `T` outlive the
// compile-flags: -Z print-type-sizes
// compile-pass
+#![feature(never_type)]
#![feature(start)]
#[start]
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![deny(unreachable_code)]
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![deny(unreachable_code)]
-#![feature(type_ascription)]
+#![feature(never_type, type_ascription)]
fn a() {
// the cast is unreachable:
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![allow(unused_assignments)]
#![allow(dead_code)]
#![deny(unreachable_code)]
-#![feature(type_ascription)]
+#![feature(never_type, type_ascription)]
fn a() {
// the cast is unreachable:
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-
+#![feature(never_type)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(dead_code)]
}
impl ToNbt<Self> {}
-//~^ ERROR cyclic dependency detected
+//~^ ERROR cycle detected
fn main() {}
-error[E0391]: cyclic dependency detected
+error[E0391]: cycle detected when processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`
--> $DIR/issue-23305.rs:15:12
|
LL | impl ToNbt<Self> {}
- | ^^^^ cyclic reference
+ | ^^^^
|
-note: the cycle begins when processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`...
- --> $DIR/issue-23305.rs:15:1
- |
-LL | impl ToNbt<Self> {}
- | ^^^^^^^^^^^^^^^^
- = note: ...which then again requires processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`, completing the cycle.
+ = note: ...which again requires processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`, completing the cycle
error: aborting due to previous error
-error[E0594]: cannot assign to immutable item `*x`
+error[E0594]: cannot assign to data in a `&` reference
--> $DIR/enum.rs:19:5
|
+LL | let Wrap(x) = &Wrap(3);
+ | - help: consider changing this to be a mutable reference: `&mut`
LL | *x += 1; //~ ERROR cannot assign to immutable
- | ^^^^^^^ cannot mutate
+ | ^^^^^^^
-error[E0594]: cannot assign to immutable item `*x`
+error[E0594]: cannot assign to data in a `&` reference
--> $DIR/enum.rs:23:9
|
+LL | if let Some(x) = &Some(3) {
+ | - help: consider changing this to be a mutable reference: `&mut`
LL | *x += 1; //~ ERROR cannot assign to immutable
- | ^^^^^^^ cannot mutate
+ | ^^^^^^^
-error[E0594]: cannot assign to immutable item `*x`
+error[E0594]: cannot assign to data in a `&` reference
--> $DIR/enum.rs:29:9
|
+LL | while let Some(x) = &Some(3) {
+ | - help: consider changing this to be a mutable reference: `&mut`
LL | *x += 1; //~ ERROR cannot assign to immutable
- | ^^^^^^^ cannot mutate
+ | ^^^^^^^
error: aborting due to 3 previous errors
-error[E0594]: cannot assign to immutable item `*n`
+error[E0594]: cannot assign to data in a `&` reference
--> $DIR/explicit-mut.rs:17:13
|
+LL | Some(n) => {
+ | - help: consider changing this to be a mutable reference: `&mut`
LL | *n += 1; //~ ERROR cannot assign to immutable
- | ^^^^^^^ cannot mutate
+ | ^^^^^^^
-error[E0594]: cannot assign to immutable item `*n`
+error[E0594]: cannot assign to data in a `&` reference
--> $DIR/explicit-mut.rs:25:13
|
+LL | Some(n) => {
+ | - help: consider changing this to be a mutable reference: `&mut`
LL | *n += 1; //~ ERROR cannot assign to immutable
- | ^^^^^^^ cannot mutate
+ | ^^^^^^^
-error[E0594]: cannot assign to immutable item `*n`
+error[E0594]: cannot assign to data in a `&` reference
--> $DIR/explicit-mut.rs:33:13
|
+LL | Some(n) => {
+ | - help: consider changing this to be a mutable reference: `&mut`
LL | *n += 1; //~ ERROR cannot assign to immutable
- | ^^^^^^^ cannot mutate
+ | ^^^^^^^
error: aborting due to 3 previous errors
LL | f.f.call_mut(())
| ^^^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `*f`
+ = note: the value which is causing this path not to be mutable is...: `*f`
error[E0507]: cannot move out of borrowed content
--> $DIR/borrowck-call-is-borrow-issue-12224.rs:66:13
LL | x.borrowed_mut(); //~ ERROR cannot borrow
| ^ cannot borrow as mutable
|
- = note: Value not mutable causing this error: `x`
+ = note: the value which is causing this path not to be mutable is...: `x`
error: aborting due to 2 previous errors
+error[E0597]: `*a` does not live long enough
+ --> $DIR/destructor-restrictions.rs:18:10
+ |
+LL | *a.borrow() + 1
+ | ^---------
+ | |
+ | borrowed value does not live long enough
+ | borrow may end up in a temporary, created here
+LL | }; //~^ ERROR `*a` does not live long enough
+ | -- temporary later dropped here, potentially using the reference
+ | |
+ | borrowed value only lives until here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
error[E0597]: `c1` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:118:24
+ --> $DIR/dropck_vec_cycle_checked.rs:121:24
|
LL | c3.v[0].v.set(Some(&c1));
| ^^^ borrowed value does not live long enough
| borrow later used here, when `c1` is dropped
error[E0597]: `c2` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:110:24
+ --> $DIR/dropck_vec_cycle_checked.rs:113:24
|
LL | c1.v[0].v.set(Some(&c2));
| ^^^ borrowed value does not live long enough
| borrow later used here, when `c1` is dropped
error[E0597]: `c3` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:112:24
+ --> $DIR/dropck_vec_cycle_checked.rs:115:24
|
LL | c1.v[1].v.set(Some(&c3));
| ^^^ borrowed value does not live long enough
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: -Z nll-subminimal-causes
+// (Work around rust-lang/rust#49998 by opting into nll-subminimal-causes.)
+
// Reject mixing cyclic structure and Drop when using Vec.
//
// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
error[E0597]: `c2` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:110:25
+ --> $DIR/dropck_vec_cycle_checked.rs:113:25
|
LL | c1.v[0].v.set(Some(&c2));
| ^^ borrowed value does not live long enough
= note: values in a scope are dropped in the opposite order they are created
error[E0597]: `c3` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:112:25
+ --> $DIR/dropck_vec_cycle_checked.rs:115:25
|
LL | c1.v[1].v.set(Some(&c3));
| ^^ borrowed value does not live long enough
= note: values in a scope are dropped in the opposite order they are created
error[E0597]: `c2` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:114:25
+ --> $DIR/dropck_vec_cycle_checked.rs:117:25
|
LL | c2.v[0].v.set(Some(&c2));
| ^^ borrowed value does not live long enough
= note: values in a scope are dropped in the opposite order they are created
error[E0597]: `c3` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:116:25
+ --> $DIR/dropck_vec_cycle_checked.rs:119:25
|
LL | c2.v[1].v.set(Some(&c3));
| ^^ borrowed value does not live long enough
= note: values in a scope are dropped in the opposite order they are created
error[E0597]: `c1` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:118:25
+ --> $DIR/dropck_vec_cycle_checked.rs:121:25
|
LL | c3.v[0].v.set(Some(&c1));
| ^^ borrowed value does not live long enough
= note: values in a scope are dropped in the opposite order they are created
error[E0597]: `c2` does not live long enough
- --> $DIR/dropck_vec_cycle_checked.rs:120:25
+ --> $DIR/dropck_vec_cycle_checked.rs:123:25
|
LL | c3.v[1].v.set(Some(&c2));
| ^^ borrowed value does not live long enough
+error[E0597]: `y` does not live long enough
+ --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:20:5
+ |
+LL | y.borrow().clone()
+ | ^---------
+ | |
+ | borrowed value does not live long enough
+ | borrow may end up in a temporary, created here
+LL | }
+ | -
+ | |
+ | borrowed value only lives until here
+ | temporary later dropped here, potentially using the reference
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/issue-23338-locals-die-before-temps-of-body.rs:27:9
+ |
+LL | y.borrow().clone()
+ | ^---------
+ | |
+ | borrowed value does not live long enough
+ | borrow may end up in a temporary, created here
+LL | };
+ | -- temporary later dropped here, potentially using the reference
+ | |
+ | borrowed value only lives until here
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
-error: compilation successful
- --> $DIR/wf-method-late-bound-regions.rs:25:1
+error[E0597]: `pointer` does not live long enough
+ --> $DIR/wf-method-late-bound-regions.rs:30:18
|
-LL | / fn main() { #![rustc_error] // rust-lang/rust#49855
-LL | | let f = Foo(None);
-LL | | let f2 = f;
-LL | | let dangling = {
-... |
-LL | | println!("{}", dangling);
-LL | | }
- | |_^
+LL | f2.xmute(&pointer)
+ | ^^^^^^^^ borrowed value does not live long enough
+LL | };
+ | - borrowed value only lives until here
+LL | //~^^ ERROR `pointer` does not live long enough
+LL | println!("{}", dangling);
+ | -------- borrow later used here
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0597`.
// A method's receiver must be well-formed, even if it has late-bound regions.
// Because of this, a method's substs being well-formed does not imply that
// the method's implied bounds are met.
-#![feature(rustc_attrs)]
+
struct Foo<'b>(Option<&'b ()>);
trait Bar<'b> {
fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32 { u }
}
-fn main() { #![rustc_error] // rust-lang/rust#49855
+fn main() {
let f = Foo(None);
let f2 = f;
let dangling = {
// except according to those terms.
fn main() {
- let x = 2.0.powi(2);
- //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ let x = 2.0.recip();
+ //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}`
let y = 2.0;
- let x = y.powi(2);
- //~^ ERROR can't call method `powi` on ambiguous numeric type `{float}`
+ let x = y.recip();
+ //~^ ERROR can't call method `recip` on ambiguous numeric type `{float}`
println!("{:?}", x);
}
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/method-on-ambiguous-numeric-type.rs:12:17
|
-LL | let x = 2.0.powi(2);
- | ^^^^
+LL | let x = 2.0.recip();
+ | ^^^^^
help: you must specify a concrete type for this numeric value, like `f32`
|
-LL | let x = 2.0_f32.powi(2);
+LL | let x = 2.0_f32.recip();
| ^^^^^^^
-error[E0689]: can't call method `powi` on ambiguous numeric type `{float}`
+error[E0689]: can't call method `recip` on ambiguous numeric type `{float}`
--> $DIR/method-on-ambiguous-numeric-type.rs:15:15
|
-LL | let x = y.powi(2);
- | ^^^^
+LL | let x = y.recip();
+ | ^^^^^
help: you must specify a type for this binding, like `f32`
|
LL | let y: f32 = 2.0;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-arm
+// ignore-aarch64
+// ignore-wasm
+// ignore-emscripten
+// gate-test-sse4a_target_feature
+// gate-test-powerpc_target_feature
+// gate-test-avx512_target_feature
+// gate-test-tbm_target_feature
+// gate-test-arm_target_feature
+// gate-test-aarch64_target_feature
+// gate-test-hexagon_target_feature
+// gate-test-mips_target_feature
+// gate-test-mmx_target_feature
+// min-llvm-version 6.0
+
+#[target_feature(enable = "avx512bw")]
+//~^ ERROR: currently unstable
+unsafe fn foo() {
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: the target feature `avx512bw` is currently unstable
+ --> $DIR/target-feature-gate.rs:26:18
+ |
+LL | #[target_feature(enable = "avx512bw")]
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(avx512_target_feature)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
#![feature(target_feature)]
#[target_feature = "+sse2"]
-//~^ WARN: deprecated
+//~^ ERROR: must be of the form
#[target_feature(enable = "foo")]
//~^ ERROR: not valid for this target
#[target_feature(bar)]
-warning: #[target_feature = ".."] is deprecated and will eventually be removed, use #[target_feature(enable = "..")] instead
+error: #[target_feature] attribute must be of the form #[target_feature(..)]
--> $DIR/target-feature-wrong.rs:21:1
|
LL | #[target_feature = "+sse2"]
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/dyn-trait-underscore.rs:20:14
|
LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
| ^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/dyn-trait-underscore.rs:20:20
|
LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
| ^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/dyn-trait-underscore.rs:20:5
|
LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
| ^^^^^^^^
-warning: not reporting region error due to -Znll
+warning: not reporting region error due to nll
--> $DIR/dyn-trait-underscore.rs:20:5
|
LL | Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
BUILD_DIR="$1"
shift
+shopt -s nullglob
+
while [[ "$1" != "" ]]; do
- STDERR_NAME="${1/%.rs/.stderr}"
- STDOUT_NAME="${1/%.rs/.stdout}"
+ for EXT in "stderr" "stdout"; do
+ for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do
+ OUT_BASE=`basename "$OUT_NAME"`
+ if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then
+ echo updating $MYDIR/$OUT_BASE
+ cp $OUT_NAME $MYDIR
+ fi
+ done
+ done
shift
- if [ -f $BUILD_DIR/$STDOUT_NAME ] && \
- ! (diff $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME >& /dev/null); then
- echo updating $MYDIR/$STDOUT_NAME
- cp $BUILD_DIR/$STDOUT_NAME $MYDIR/$STDOUT_NAME
- fi
- if [ -f $BUILD_DIR/$STDERR_NAME ] && \
- ! (diff $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME >& /dev/null); then
- echo updating $MYDIR/$STDERR_NAME
- cp $BUILD_DIR/$STDERR_NAME $MYDIR/$STDERR_NAME
- fi
done
-Subproject commit 008c3690846798d678f4a0a45ee46cc9ff6dc90f
+Subproject commit 0a1add2d8689ad12a86f6c32d0a5cd0393dc5d80
-Subproject commit 8ec61a613ad1278b18a4770332b6da128704fdd6
+Subproject commit c5b39a5917ffc0f1349b6e414fa3b874fdcf8429
}
impl CompareMode {
- fn to_str(&self) -> &'static str {
+ pub(crate) fn to_str(&self) -> &'static str {
match *self {
CompareMode::Nll => "nll"
}
),
};
+ let src_base = opt_path(matches, "src-base");
+ let run_ignored = matches.opt_present("ignored");
Config {
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
valgrind_path: matches.opt_str("valgrind-path"),
force_valgrind: matches.opt_present("force-valgrind"),
llvm_filecheck: matches.opt_str("llvm-filecheck").map(|s| PathBuf::from(&s)),
- src_base: opt_path(matches, "src-base"),
+ src_base,
build_base: opt_path(matches, "build-base"),
stage_id: matches.opt_str("stage-id").unwrap(),
mode: matches
.unwrap()
.parse()
.expect("invalid mode"),
- run_ignored: matches.opt_present("ignored"),
+ run_ignored,
filter: matches.free.first().cloned(),
filter_exact: matches.opt_present("exact"),
logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
// Debugging emscripten code doesn't make sense today
let ignore = early_props.ignore
- || (!up_to_date(config, testpaths, &early_props) && config.compare_mode.is_none())
+ || !up_to_date(config, testpaths, &early_props)
|| (config.mode == DebugInfoGdb || config.mode == DebugInfoLldb)
&& config.target.contains("emscripten");
}
fn stamp(config: &Config, testpaths: &TestPaths) -> PathBuf {
+ let mode_suffix = match config.compare_mode {
+ Some(ref mode) => format!("-{}", mode.to_str()),
+ None => format!(""),
+ };
let stamp_name = format!(
- "{}-{}.stamp",
+ "{}-{}{}.stamp",
testpaths.file.file_name().unwrap().to_str().unwrap(),
- config.stage_id
+ config.stage_id,
+ mode_suffix
);
config
.build_base
let path = PathBuf::from(config.src_base.file_name().unwrap())
.join(&testpaths.relative_dir)
.join(&testpaths.file.file_name().unwrap());
- test::DynTestName(format!("[{}] {}", config.mode, path.display()))
+ let mode_suffix = match config.compare_mode {
+ Some(ref mode) => format!(" ({})", mode.to_str()),
+ None => format!(""),
+ };
+ test::DynTestName(format!("[{}{}] {}", config.mode, mode_suffix, path.display()))
}
pub fn make_test_closure(config: &Config, testpaths: &TestPaths) -> test::TestFn {
use std::collections::HashMap;
use std::collections::HashSet;
use std::env;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
use std::fs::{self, create_dir_all, File};
use std::fmt;
use std::io::prelude::*;
}
}
+trait PathBufExt {
+ /// Append an extension to the path, even if it already has one.
+ fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
+}
+
+impl PathBufExt for PathBuf {
+ fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
+ if extension.as_ref().len() == 0 {
+ self.clone()
+ } else {
+ let mut fname = self.file_name().unwrap().to_os_string();
+ if !extension.as_ref().to_str().unwrap().starts_with(".") {
+ fname.push(".");
+ }
+ fname.push(extension);
+ self.with_file_name(fname)
+ }
+ }
+}
+
// Produces a diff between the expected output and actual output.
pub fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
let mut line_number = 1;
// want to actually assert warnings about all this code. Instead
// let's just ignore unused code warnings by defaults and tests
// can turn it back on if needed.
- rustc.args(&["-A", "unused"]);
+ if !self.config.src_base.ends_with("rustdoc-ui") {
+ rustc.args(&["-A", "unused"]);
+ }
}
_ => {}
}
}
fn make_compile_args(&self, input_file: &Path, output_file: TargetLocation) -> Command {
- let mut rustc = Command::new(&self.config.rustc_path);
+ let is_rustdoc = self.config.src_base.ends_with("rustdoc-ui");
+ let mut rustc = if !is_rustdoc {
+ Command::new(&self.config.rustc_path)
+ } else {
+ Command::new(&self.config.rustdoc_path.clone().expect("no rustdoc built yet"))
+ };
rustc.arg(input_file).arg("-L").arg(&self.config.build_base);
// Optionally prevent default --target if specified in test compile-flags.
rustc.args(&["--cfg", revision]);
}
- if let Some(ref incremental_dir) = self.props.incremental_dir {
- rustc.args(&[
- "-C",
- &format!("incremental={}", incremental_dir.display()),
- ]);
- rustc.args(&["-Z", "incremental-verify-ich"]);
- rustc.args(&["-Z", "incremental-queries"]);
- }
+ if !is_rustdoc {
+ if let Some(ref incremental_dir) = self.props.incremental_dir {
+ rustc.args(&[
+ "-C",
+ &format!("incremental={}", incremental_dir.display()),
+ ]);
+ rustc.args(&["-Z", "incremental-verify-ich"]);
+ rustc.args(&["-Z", "incremental-queries"]);
+ }
- if self.config.mode == CodegenUnits {
- rustc.args(&["-Z", "human_readable_cgu_names"]);
+ if self.config.mode == CodegenUnits {
+ rustc.args(&["-Z", "human_readable_cgu_names"]);
+ }
}
match self.config.mode {
}
}
-
- if self.config.target == "wasm32-unknown-unknown" {
- // rustc.arg("-g"); // get any backtrace at all on errors
- } else if !self.props.no_prefer_dynamic {
- rustc.args(&["-C", "prefer-dynamic"]);
+ if !is_rustdoc {
+ if self.config.target == "wasm32-unknown-unknown" {
+ // rustc.arg("-g"); // get any backtrace at all on errors
+ } else if !self.props.no_prefer_dynamic {
+ rustc.args(&["-C", "prefer-dynamic"]);
+ }
}
match output_file {
match self.config.compare_mode {
Some(CompareMode::Nll) => {
- rustc.args(&["-Znll", "-Zborrowck=mir", "-Ztwo-phase-borrows"]);
+ rustc.args(&["-Zborrowck=mir", "-Ztwo-phase-borrows"]);
},
None => {},
}
} else {
rustc.args(self.split_maybe_args(&self.config.target_rustcflags));
}
- if let Some(ref linker) = self.config.linker {
- rustc.arg(format!("-Clinker={}", linker));
+ if !is_rustdoc {
+ if let Some(ref linker) = self.config.linker {
+ rustc.arg(format!("-Clinker={}", linker));
+ }
}
rustc.args(&self.props.compile_flags);
}
fn make_exe_name(&self) -> PathBuf {
- let mut f = self.output_base_name();
+ let mut f = self.output_base_name_stage();
// FIXME: This is using the host architecture exe suffix, not target!
if self.config.target.contains("emscripten") {
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(".js");
- f.set_file_name(&fname);
+ f = f.with_extra_extension("js");
} else if self.config.target.contains("wasm32") {
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(".wasm");
- f.set_file_name(&fname);
+ f = f.with_extra_extension("wasm");
} else if !env::consts::EXE_SUFFIX.is_empty() {
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(env::consts::EXE_SUFFIX);
- f.set_file_name(&fname);
+ f = f.with_extra_extension(env::consts::EXE_SUFFIX);
}
f
}
}
fn aux_output_dir_name(&self) -> PathBuf {
- let f = self.output_base_name();
- let mut fname = f.file_name().unwrap().to_os_string();
- fname.push(&format!("{}.aux", self.config.mode.disambiguator()));
- f.with_file_name(&fname)
+ self.output_base_name_stage()
+ .with_extra_extension(self.config.mode.disambiguator())
+ .with_extra_extension(".aux")
}
fn output_testname(&self, filepath: &Path) -> PathBuf {
PathBuf::from(filepath.file_stem().unwrap())
}
- /// Given a test path like `compile-fail/foo/bar.rs` Returns a name like
- ///
- /// <output>/foo/bar-stage1
+ /// Given a test path like `compile-fail/foo/bar.rs` returns a name like
+ /// `/path/to/build/<triple>/test/compile-fail/foo/bar`.
fn output_base_name(&self) -> PathBuf {
let dir = self.config.build_base.join(&self.testpaths.relative_dir);
// Note: The directory `dir` is created during `collect_tests_from_dir`
dir.join(&self.output_testname(&self.testpaths.file))
- .with_extension(&self.config.stage_id)
+ }
+
+ /// Same as `output_base_name`, but includes the stage ID as an extension,
+ /// such as: `.../compile-fail/foo/bar.stage1-<triple>`
+ fn output_base_name_stage(&self) -> PathBuf {
+ self.output_base_name().with_extension(&self.config.stage_id)
}
fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
fn run_rustdoc_test(&self) {
assert!(self.revision.is_none(), "revisions not relevant here");
- let out_dir = self.output_base_name();
+ let out_dir = self.output_base_name_stage();
let _ = fs::remove_dir_all(&out_dir);
create_dir_all(&out_dir).unwrap();
.unwrap();
let src_root = cwd.join(&src_root);
- let tmpdir = cwd.join(self.output_base_name());
+ let tmpdir = cwd.join(self.output_base_name_stage());
if tmpdir.exists() {
self.aggressive_rm_rf(&tmpdir).unwrap();
}
.compile_flags
.iter()
.any(|s| s.contains("--error-format"));
-
let proc_res = self.compile_test();
self.check_if_test_should_compile(&proc_res);
normalized
}
- fn load_expected_output(&self, kind: &str) -> String {
+ fn expected_output_path(&self, kind: &str) -> PathBuf {
let mut path = expected_output_path(&self.testpaths,
self.revision,
&self.config.compare_mode,
kind);
-
if !path.exists() && self.config.compare_mode.is_some() {
// fallback!
path = expected_output_path(&self.testpaths, self.revision, &None, kind);
}
+ path
+ }
+
+ fn load_expected_output(&self, kind: &str) -> String {
+ let path = self.expected_output_path(kind);
if path.exists() {
match self.load_expected_output_from_path(&path) {
Ok(x) => x,
}
}
- let output_file = self.output_base_name().with_extension(kind);
+ let mode = self.config.compare_mode.as_ref().map_or("", |m| m.to_str());
+ let output_file = self.output_base_name()
+ .with_extra_extension(self.revision.unwrap_or(""))
+ .with_extra_extension(mode)
+ .with_extra_extension(kind);
+
match File::create(&output_file).and_then(|mut f| f.write_all(actual.as_bytes())) {
Ok(()) => {}
Err(e) => self.fatal(&format!(
clap = "2.25.0"
[dependencies.mdbook]
-version = "0.1.5"
+version = "0.1.7"
default-features = false
features = ["search"]
var toolchain = argv[2];
var mainJs = readFile("build/" + toolchain + "/doc/main.js");
+ var ALIASES = readFile("build/" + toolchain + "/doc/aliases.js");
var searchIndex = readFile("build/" + toolchain + "/doc/search-index.js").split("\n");
if (searchIndex[searchIndex.length - 1].length === 0) {
searchIndex.pop();
// execQuery first parameter is built in getQuery (which takes in the search input).
// execQuery last parameter is built in buildIndex.
// buildIndex requires the hashmap from search-index.
- var functionsToLoad = ["levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery"];
+ var functionsToLoad = ["levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery",
+ "execSearch"];
finalJS += 'window = { "currentCrate": "std" };\n';
+ finalJS += ALIASES;
finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs);
'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;');
const expected = loadedFile.EXPECTED;
const query = loadedFile.QUERY;
- var results = loaded.execQuery(loaded.getQuery(query), index);
+ var results = loaded.execSearch(loaded.getQuery(query), index);
process.stdout.write('Checking "' + file + '" ... ');
var error_text = [];
for (var key in expected) {
-Subproject commit 1415a4dc23f28644cb197b6bb69c311245c216e2
+Subproject commit dd807e24656c91b4ad22d3cac146edd86315e633
use std::path::Path;
-// See rust-lang/rust#48879: In addition to the mapping from `foo.rs`
-// to `foo.stderr`/`foo.stdout`, we also can optionally have
-// `foo.$mode.stderr`, where $mode is one of the strings on this list,
-// as an alternative to use when running under that mode.
-static COMPARE_MODE_NAMES: [&'static str; 1] = ["nll"];
-
pub fn check(path: &Path, bad: &mut bool) {
super::walk_many(&[&path.join("test/ui"), &path.join("test/ui-fulldeps")],
&mut |_| false,
&mut |file_path| {
if let Some(ext) = file_path.extension() {
- if (ext == "stderr" || ext == "stdout") && !file_path.with_extension("rs").exists() {
-
- // rust-lang/rust#48879: this fn used to be beautful
- // because Path API special-cases replacing
- // extensions. That works great for ".stderr" but not
- // so well for ".nll.stderr". To support the latter,
- // we explicitly search backwards for mode's starting
- // point and build corresponding source name.
- let filename = file_path.file_name().expect("need filename")
- .to_str().expect("need UTF-8 filename");
- let found_matching_prefix = COMPARE_MODE_NAMES.iter().any(|mode| {
- if let Some(r_idx) = filename.rfind(&format!(".{}", mode)) {
- let source_name = format!("{}.rs", &filename[0..r_idx]);
- let source_path = file_path.with_file_name(source_name);
- source_path.exists()
- } else {
- false
- }
- });
-
- if !found_matching_prefix {
+ if ext == "stderr" || ext == "stdout" {
+ // Test output filenames have the format:
+ // $testname.stderr
+ // $testname.$mode.stderr
+ // $testname.$revision.stderr
+ // $testname.$revision.$mode.stderr
+ //
+ // For now, just make sure that there is a corresponding
+ // $testname.rs file.
+ let testname = file_path.file_name().unwrap()
+ .to_str().unwrap()
+ .splitn(2, '.').next().unwrap();
+ if !file_path.with_file_name(testname)
+ .with_extension("rs")
+ .exists() {
println!("Stray file with UI testing output: {:?}", file_path);
*bad = true;
}