Compiler
--------
-- [Added the `armv5te-unknown-linux-musl` target.][50423]
+- [Added the `armv5te-unknown-linux-musleabi` target.][50423]
Libraries
---------
# the same format as above, but since these targets are experimental, they are
# not built by default and the experimental Rust compilation targets that depend
# on them will not work unless the user opts in to building them. By default the
-# `WebAssembly` target is enabled when compiling LLVM from scratch.
-#experimental-targets = "WebAssembly"
+# `WebAssembly` and `RISCV` targets are enabled when compiling LLVM from scratch.
+#experimental-targets = "WebAssembly;RISCV"
# Cap the number of parallel linker invocations when compiling LLVM.
# This can be useful when building LLVM with debug info, which significantly
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (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.13 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (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)",
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crates-io 0.18.0",
- "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.5.0 (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.13 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.1 (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)",
"libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-workspace-hack 1.0.0",
+ "rustfix 0.4.2 (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.70 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.0.212"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy-mini-macro-test 0.2.0",
"clippy_lints 0.0.212",
"compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-workspace-hack 1.0.0",
"rustc_version 0.2.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.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"log 0.4.3 (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.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustfix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.18.0"
dependencies = [
"curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "crossbeam-utils"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "crypto-hash"
version = "0.3.1"
[[package]]
name = "failure"
-version = "0.1.1"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
-version = "0.1.1"
+version = "0.1.2"
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)",
- "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"clippy_lints 0.0.212",
"crossbeam-channel 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 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)",
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"languageserver-types 0.45.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.4.0 (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.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-workspace-hack 1.0.0",
"rustfmt-nightly 0.9.0",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "racer 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
"rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-arena"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
version = "209.0.0"
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_cratesio_shim"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_data_structures"
version = "209.0.0"
"stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_data_structures"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_errors"
version = "209.0.0"
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_errors"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 211.0.0 (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.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-rustc_target"
version = "209.0.0"
"rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-rustc_target"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-serialize"
version = "209.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "rustc-ap-serialize"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "rustc-ap-syntax"
version = "209.0.0"
"scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-syntax"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-ap-syntax_pos"
version = "209.0.0"
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "rustc-ap-syntax_pos"
+version = "211.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-arena 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.8"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "rustc-workspace-hack"
+version = "1.0.0"
+dependencies = [
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc_allocator"
version = "0.0.0"
[[package]]
name = "rustfix"
-version = "0.4.1"
+version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.4 (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.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"isatty 0.1.8 (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.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "synstructure"
-version = "0.6.1"
+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)",
+ "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"checksum crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285987a59c4d91388e749850e3cb7b3a92299668528caaacd08005b8f238c0ea"
"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a"
+"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
"checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4"
"checksum curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "893713db705eab9847e050268507b0e2a2aad64e90a831874bd4e8e0d67f9523"
"checksum curl-sys 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "de9cf174efdf90b5887c4e2e900769373c89c5e18152e8f3ed75b501a6f1c0fb"
"checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02"
-"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 failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9"
+"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426"
"checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f"
"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 rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ecbc8541b4c341d6271eae10f869dd9d36db871afe184f5b6f9bffbd6ed0373f"
"checksum rustc-ap-arena 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b098827864368459cbc7a79fbc54eafb92df7e00a46c0cda352b5a21583ee436"
+"checksum rustc-ap-arena 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eec75ed880706dd9a05bc770c327ed142fa7d4b648d9757fbc71d821d68448a5"
"checksum rustc-ap-rustc_cratesio_shim 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4d923dea14fb085bca743fb982f6a3bc11c0d5d30b822bcf6fa16e9464a56c"
+"checksum rustc-ap-rustc_cratesio_shim 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f5d54615bedbae65a976e0835edf0de90dd962ec818c0149fe181d5cd81da9e"
"checksum rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c6a5c9edc6b4ae035cdc03af7d8662d39fad7879c5501d103e7087dfaebc80"
+"checksum rustc-ap-rustc_data_structures 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7c51cc6e79eab25c7ea84a7e104e81e6f44cca32709df54c2cdb4e7059d7843"
"checksum rustc-ap-rustc_errors 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1e9bdc597abd95cebce0c14c1da58943a9e5b8255530a0fec30659d144eb0b"
+"checksum rustc-ap-rustc_errors 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff050095b7afb254506591ee7d3a5d0fb9c03c16f8c2741b588178085e563d49"
"checksum rustc-ap-rustc_target 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142ddef3dc12dda2bcd3412f0d96d3745413a8fbc2f224f0cc97afa04c071d89"
+"checksum rustc-ap-rustc_target 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53c7a8c21c3b05f24998fa6ab9ded6269810a2f3ae12ff301c432c1e9fa8e111"
"checksum rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b08f8f175b038a82caa7e51fc52b72ff96cfe8c1429755da30380dbd4199c7f"
+"checksum rustc-ap-serialize 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4713c2c0c26a45ead8fb16fee88e16fecf999588ae6920847cbaeb19565b7f"
"checksum rustc-ap-syntax 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c802e0e1fbc64eddc21e0798527eb1f5fdbd5781d119bd2c44b6130afdc81cc"
+"checksum rustc-ap-syntax 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "768e2698f912913be2ccd355b2dea62c978efc356f75db1400605f3642905d53"
"checksum rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "008d47cc54ed12a2784217b9e6630a7fa1c8dc3591a283f65ad4b7fa307d49d5"
+"checksum rustc-ap-syntax_pos 211.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a280dc8919aa7f684832ba3eeab2f6c96dbe2e2e4f6a922f7f0bdb3a9dd9e641"
"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649"
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
"checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306"
"checksum rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40f06724db71e18d68b3b946fdf890ca8c921d9edccc1404fdfdb537b0d12649"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a"
-"checksum rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f77b09d42bae4adfbcd105a8914e2d9fb46b63612c1a765b824a2b4a4bb814"
+"checksum rustfix 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "756567f00f7d89c9f89a5c401b8b1caaa122e27240b9eaadd0bb52ee0b680b1b"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f"
"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28"
"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b"
"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
-"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
+"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7"
"checksum tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f41ca4a5689f06998f0247fcb60da6c760f1950cc9df2a10d71575ad0b062a"
"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b"
"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
[patch."https://github.com/rust-lang/cargo"]
cargo = { path = "tools/cargo" }
-[patch."https://github.com/rust-lang-nursery/rustfmt"]
+[patch.crates-io]
# Similar to Cargo above we want the RLS to use a vendored version of `rustfmt`
# that we're shipping as well (to ensure that the rustfmt in RLS and the
# `rustfmt` executable are the same exact version).
rustfmt-nightly = { path = "tools/rustfmt" }
+# See comments in `tools/rustc-workspace-hack/README.md` for what's going on
+# here
+rustc-workspace-hack = { path = 'tools/rustc-workspace-hack' }
+
[patch."https://github.com/rust-lang-nursery/rust-clippy"]
clippy_lints = { path = "tools/clippy/clippy_lints" }
use config::Config;
// The version number
-pub const CFG_RELEASE_NUM: &str = "1.29.0";
+pub const CFG_RELEASE_NUM: &str = "1.30.0";
pub struct GitInfo {
inner: Option<Info>,
set(&mut config.llvm_link_shared, llvm.link_shared);
config.llvm_targets = llvm.targets.clone();
config.llvm_experimental_targets = llvm.experimental_targets.clone()
- .unwrap_or("WebAssembly".to_string());
+ .unwrap_or("WebAssembly;RISCV".to_string());
config.llvm_link_jobs = llvm.link_jobs;
config.llvm_clang_cl = llvm.clang_cl.clone();
}
cargo.env("RLS_TEST_WORKSPACE_DIR", test_workspace_path);
builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.arg("--")
+ .args(builder.config.cmd.test_args());
if try_run(builder, &mut cargo) {
builder.save_toolstate("rls", ToolState::TestPass);
prev.0, &prev_features - &cur_features, prev.1);
}
println!("");
+ println!("to fix this you will probably want to edit the local \
+ src/tools/rustc-workspace-hack/Cargo.toml crate, as \
+ that will update the dependency graph to ensure that \
+ these crates all share the same feature set");
panic!("tools should not compile multiple copies of the same crate");
}
ENV TARGETS=$TARGETS,thumbv7m-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabi
ENV TARGETS=$TARGETS,thumbv7em-none-eabihf
+ENV TARGETS=$TARGETS,riscv32imac-unknown-none-elf
ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \
CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \
#[cfg(test)]
mod boxed_test;
pub mod collections;
-#[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
-))]
+#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
pub mod sync;
pub mod rc;
pub mod raw_vec;
pub use core::task::*;
-#[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
-))]
+#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
pub use self::if_arc::*;
-#[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
-))]
+#[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
mod if_arc {
use super::*;
use core::marker::PhantomData;
}
}
- #[cfg(any(
- all(stage0, target_has_atomic = "ptr"),
- all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
- ))]
+ #[cfg(all(target_has_atomic = "ptr", target_has_atomic = "cas"))]
struct ArcWrapped<T>(PhantomData<T>);
unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
/// [`drain`]: #method.drain
#[stable(feature = "rust1", since = "1.0.0")]
pub fn truncate(&mut self, len: usize) {
+ let current_len = self.len;
unsafe {
+ let mut ptr = self.as_mut_ptr().offset(self.len as isize);
+ // Set the final length at the end, keeping in mind that
+ // dropping an element might panic. Works around a missed
+ // optimization, as seen in the following issue:
+ // https://github.com/rust-lang/rust/issues/51802
+ let mut local_len = SetLenOnDrop::new(&mut self.len);
+
// drop any extra elements
- while len < self.len {
- // decrement len before the drop_in_place(), so a panic on Drop
- // doesn't re-drop the just-failed value.
- self.len -= 1;
- let len = self.len;
- ptr::drop_in_place(self.get_unchecked_mut(len));
+ for _ in len..current_len {
+ local_len.decrement_len(1);
+ ptr = ptr.offset(-1);
+ ptr::drop_in_place(ptr);
}
}
}
fn increment_len(&mut self, increment: usize) {
self.local_len += increment;
}
+
+ #[inline]
+ fn decrement_len(&mut self, decrement: usize) {
+ self.local_len -= decrement;
+ }
}
impl<'a> Drop for SetLenOnDrop<'a> {
cmd.arg("--with-jemalloc-prefix=je_");
}
- // FIXME: building with jemalloc assertions is currently broken.
- // See <https://github.com/rust-lang/rust/issues/44152>.
- //if cfg!(feature = "debug") {
- // cmd.arg("--enable-debug");
- //}
+ if cfg!(feature = "debug") {
+ // Enable jemalloc assertions.
+ cmd.arg("--enable-debug");
+ }
cmd.arg(format!("--host={}", build_helper::gnu_target(&target)));
cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));
use ptr::{self, NonNull};
use num::NonZeroUsize;
-#[unstable(feature = "alloc_internals", issue = "0")]
-#[cfg(stage0)]
-pub type Opaque = u8;
-
/// Represents the combination of a starting address and
/// a total capacity of the returned block.
#[unstable(feature = "allocator_api", issue = "32838")]
/// use specific allocators with looser requirements.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[cfg_attr(not(stage0), lang = "alloc_layout")]
+#[lang = "alloc_layout"]
pub struct Layout {
// size of the requested block of memory, measured in bytes.
size_: usize,
/// assert!('٣'.is_alphanumeric());
/// assert!('7'.is_alphanumeric());
/// assert!('৬'.is_alphanumeric());
+ /// assert!('¾'.is_alphanumeric());
+ /// assert!('①'.is_alphanumeric());
/// assert!('K'.is_alphanumeric());
/// assert!('و'.is_alphanumeric());
/// assert!('藏'.is_alphanumeric());
- /// assert!(!'¾'.is_alphanumeric());
- /// assert!(!'①'.is_alphanumeric());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// assert!('٣'.is_numeric());
/// assert!('7'.is_numeric());
/// assert!('৬'.is_numeric());
+ /// assert!('¾'.is_numeric());
+ /// assert!('①'.is_numeric());
/// assert!(!'K'.is_numeric());
/// assert!(!'و'.is_numeric());
/// assert!(!'藏'.is_numeric());
- /// assert!(!'¾'.is_numeric());
- /// assert!(!'①'.is_numeric());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// Perform a volatile load from the `src` pointer
/// The pointer is not required to be aligned.
- #[cfg(not(stage0))]
pub fn unaligned_volatile_load<T>(src: *const T) -> T;
/// Perform a volatile store to the `dst` pointer.
/// The pointer is not required to be aligned.
- #[cfg(not(stage0))]
pub fn unaligned_volatile_store<T>(dst: *mut T, val: T);
/// Returns the square root of an `f32`
+++ /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.
-
-/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
-///
-/// This wrapper is 0-cost.
-///
-/// # Examples
-///
-/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
-/// the type:
-///
-/// ```rust
-/// use std::mem::ManuallyDrop;
-/// struct Peach;
-/// struct Banana;
-/// struct Melon;
-/// struct FruitBox {
-/// // Immediately clear there’s something non-trivial going on with these fields.
-/// peach: ManuallyDrop<Peach>,
-/// melon: Melon, // Field that’s independent of the other two.
-/// banana: ManuallyDrop<Banana>,
-/// }
-///
-/// impl Drop for FruitBox {
-/// fn drop(&mut self) {
-/// unsafe {
-/// // Explicit ordering in which field destructors are run specified in the intuitive
-/// // location – the destructor of the structure containing the fields.
-/// // Moreover, one can now reorder fields within the struct however much they want.
-/// ManuallyDrop::drop(&mut self.peach);
-/// ManuallyDrop::drop(&mut self.banana);
-/// }
-/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets
-/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`.
-/// }
-/// }
-/// ```
-#[stable(feature = "manually_drop", since = "1.20.0")]
-#[allow(unions_with_drop_fields)]
-#[derive(Copy)]
-pub union ManuallyDrop<T>{ value: T }
-
-impl<T> ManuallyDrop<T> {
- /// Wrap a value to be manually dropped.
- ///
- /// # Examples
- ///
- /// ```rust
- /// use std::mem::ManuallyDrop;
- /// ManuallyDrop::new(Box::new(()));
- /// ```
- #[stable(feature = "manually_drop", since = "1.20.0")]
- #[rustc_const_unstable(feature = "const_manually_drop_new")]
- #[inline]
- pub const fn new(value: T) -> ManuallyDrop<T> {
- ManuallyDrop { value: value }
- }
-
- /// Extract the value from the ManuallyDrop container.
- ///
- /// # Examples
- ///
- /// ```rust
- /// use std::mem::ManuallyDrop;
- /// let x = ManuallyDrop::new(Box::new(()));
- /// let _: Box<()> = ManuallyDrop::into_inner(x);
- /// ```
- #[stable(feature = "manually_drop", since = "1.20.0")]
- #[inline]
- pub fn into_inner(slot: ManuallyDrop<T>) -> T {
- unsafe {
- slot.value
- }
- }
-
- /// Manually drops the contained value.
- ///
- /// # Safety
- ///
- /// This function runs the destructor of the contained value and thus the wrapped value
- /// now represents uninitialized data. It is up to the user of this method to ensure the
- /// uninitialized data is not actually used.
- #[stable(feature = "manually_drop", since = "1.20.0")]
- #[inline]
- pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
- ptr::drop_in_place(&mut slot.value)
- }
-}
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T> Deref for ManuallyDrop<T> {
- type Target = T;
- #[inline]
- fn deref(&self) -> &Self::Target {
- unsafe {
- &self.value
- }
- }
-}
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T> DerefMut for ManuallyDrop<T> {
- #[inline]
- fn deref_mut(&mut self) -> &mut Self::Target {
- unsafe {
- &mut self.value
- }
- }
-}
-
-#[stable(feature = "manually_drop", since = "1.20.0")]
-impl<T: ::fmt::Debug> ::fmt::Debug for ManuallyDrop<T> {
- fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result {
- unsafe {
- fmt.debug_tuple("ManuallyDrop").field(&self.value).finish()
- }
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Clone> Clone for ManuallyDrop<T> {
- fn clone(&self) -> Self {
- ManuallyDrop::new(self.deref().clone())
- }
-
- fn clone_from(&mut self, source: &Self) {
- self.deref_mut().clone_from(source);
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Default> Default for ManuallyDrop<T> {
- fn default() -> Self {
- ManuallyDrop::new(Default::default())
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: PartialEq> PartialEq for ManuallyDrop<T> {
- fn eq(&self, other: &Self) -> bool {
- self.deref().eq(other)
- }
-
- fn ne(&self, other: &Self) -> bool {
- self.deref().ne(other)
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Eq> Eq for ManuallyDrop<T> {}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: PartialOrd> PartialOrd for ManuallyDrop<T> {
- fn partial_cmp(&self, other: &Self) -> Option<::cmp::Ordering> {
- self.deref().partial_cmp(other)
- }
-
- fn lt(&self, other: &Self) -> bool {
- self.deref().lt(other)
- }
-
- fn le(&self, other: &Self) -> bool {
- self.deref().le(other)
- }
-
- fn gt(&self, other: &Self) -> bool {
- self.deref().gt(other)
- }
-
- fn ge(&self, other: &Self) -> bool {
- self.deref().ge(other)
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: Ord> Ord for ManuallyDrop<T> {
- fn cmp(&self, other: &Self) -> ::cmp::Ordering {
- self.deref().cmp(other)
- }
-}
-
-#[stable(feature = "manually_drop_impls", since = "1.22.0")]
-impl<T: ::hash::Hash> ::hash::Hash for ManuallyDrop<T> {
- fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
- self.deref().hash(state);
- }
-}
/// }
/// }
/// ```
-#[cfg(not(stage0))]
#[stable(feature = "manually_drop", since = "1.20.0")]
#[lang = "manually_drop"]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
value: T,
}
-#[cfg(stage0)]
-include!("manually_drop_stage0.rs");
-
-#[cfg(not(stage0))]
impl<T> ManuallyDrop<T> {
/// Wrap a value to be manually dropped.
///
}
}
-#[cfg(not(stage0))]
#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T> Deref for ManuallyDrop<T> {
type Target = T;
}
}
-#[cfg(not(stage0))]
#[stable(feature = "manually_drop", since = "1.20.0")]
impl<T> DerefMut for ManuallyDrop<T> {
#[inline]
// - the first remaining bytes, < 2 word size
let len = text.len();
let ptr = text.as_ptr();
- let usize_bytes = mem::size_of::<usize>();
+ type Chunk = usize;
- let mut offset = {
- // We call this just to obtain the length of the suffix
- let (_, _, suffix) = unsafe { text.align_to::<usize>() };
- len - suffix.len()
+ let (min_aligned_offset, max_aligned_offset) = {
+ // We call this just to obtain the length of the prefix and suffix.
+ // In the middle we always process two chunks at once.
+ let (prefix, _, suffix) = unsafe { text.align_to::<(Chunk, Chunk)>() };
+ (prefix.len(), len - suffix.len())
};
+
+ let mut offset = max_aligned_offset;
if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
return Some(offset + index);
}
- // search the body of the text
+ // search the body of the text, make sure we don't cross min_aligned_offset.
+ // offset is always aligned, so just testing `>` is sufficient and avoids possible
+ // overflow.
let repeated_x = repeat_byte(x);
+ let chunk_bytes = mem::size_of::<Chunk>();
- while offset >= 2 * usize_bytes {
+ while offset > min_aligned_offset {
unsafe {
- let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize);
- let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize);
+ let u = *(ptr.offset(offset as isize - 2 * chunk_bytes as isize) as *const Chunk);
+ let v = *(ptr.offset(offset as isize - chunk_bytes as isize) as *const Chunk);
// break if there is a matching byte
let zu = contains_zero_byte(u ^ repeated_x);
break;
}
}
- offset -= 2 * usize_bytes;
+ offset -= 2 * chunk_bytes;
}
// find the byte before the point the body loop stopped
// Extension traits
//
-// Use macros to be generic over const/mut
-macro_rules! slice_offset {
- ($ptr:expr, $by:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- (ptr as *mut i8).wrapping_offset($by) as _
- } else {
- ptr.offset($by)
- }
- }};
-}
-
-// make a &T from a *const T
-macro_rules! make_ref {
- ($ptr:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- // Use a non-null pointer value
- &*(1 as *mut _)
- } else {
- &*ptr
- }
- }};
-}
-
-// make a &mut T from a *mut T
-macro_rules! make_ref_mut {
- ($ptr:expr) => {{
- let ptr = $ptr;
- if size_from_ptr(ptr) == 0 {
- // Use a non-null pointer value
- &mut *(1 as *mut _)
- } else {
- &mut *ptr
- }
- }};
-}
-
#[lang = "slice"]
#[cfg(not(test))]
impl<T> [T] {
#[inline]
pub fn iter(&self) -> Iter<T> {
unsafe {
- let p = if mem::size_of::<T>() == 0 {
- 1 as *const _
+ let ptr = self.as_ptr();
+ assume(!ptr.is_null());
+
+ let end = if mem::size_of::<T>() == 0 {
+ (ptr as *const u8).wrapping_offset(self.len() as isize) as *const T
} else {
- let p = self.as_ptr();
- assume(!p.is_null());
- p
+ ptr.offset(self.len() as isize)
};
Iter {
- ptr: p,
- end: slice_offset!(p, self.len() as isize),
+ ptr,
+ end,
_marker: marker::PhantomData
}
}
#[inline]
pub fn iter_mut(&mut self) -> IterMut<T> {
unsafe {
- let p = if mem::size_of::<T>() == 0 {
- 1 as *mut _
+ let ptr = self.as_mut_ptr();
+ assume(!ptr.is_null());
+
+ let end = if mem::size_of::<T>() == 0 {
+ (ptr as *mut u8).wrapping_offset(self.len() as isize) as *mut T
} else {
- let p = self.as_mut_ptr();
- assume(!p.is_null());
- p
+ ptr.offset(self.len() as isize)
};
IterMut {
- ptr: p,
- end: slice_offset!(p, self.len() as isize),
+ ptr,
+ end,
_marker: marker::PhantomData
}
}
}
}
-#[inline]
+// Macro helper functions
+#[inline(always)]
fn size_from_ptr<T>(_: *const T) -> usize {
mem::size_of::<T>()
}
+// Inlining is_empty and len makes a huge performance difference
+macro_rules! is_empty {
+ // The way we encode the length of a ZST iterator, this works both for ZST
+ // and non-ZST.
+ ($self: ident) => {$self.ptr == $self.end}
+}
+// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
+// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
+macro_rules! len {
+ ($self: ident) => {{
+ let start = $self.ptr;
+ let diff = ($self.end as usize).wrapping_sub(start as usize);
+ let size = size_from_ptr(start);
+ if size == 0 {
+ diff
+ } else {
+ // Using division instead of `offset_from` helps LLVM remove bounds checks
+ diff / size
+ }
+ }}
+}
+
// The shared definition of the `Iter` and `IterMut` iterators
macro_rules! iterator {
- (struct $name:ident -> $ptr:ty, $elem:ty, $mkref:ident) => {
+ (struct $name:ident -> $ptr:ty, $elem:ty, $raw_mut:tt, $( $mut_:tt )*) => {
+ impl<'a, T> $name<'a, T> {
+ // Helper function for creating a slice from the iterator.
+ #[inline(always)]
+ fn make_slice(&self) -> &'a [T] {
+ unsafe { from_raw_parts(self.ptr, len!(self)) }
+ }
+
+ // Helper function for moving the start of the iterator forwards by `offset` elements,
+ // returning the old start.
+ // Unsafe because the offset must be in-bounds or one-past-the-end.
+ #[inline(always)]
+ unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
+ if mem::size_of::<T>() == 0 {
+ // This is *reducing* the length. `ptr` never changes with ZST.
+ self.end = (self.end as * $raw_mut u8).wrapping_offset(-offset) as * $raw_mut T;
+ self.ptr
+ } else {
+ let old = self.ptr;
+ self.ptr = self.ptr.offset(offset);
+ old
+ }
+ }
+
+ // Helper function for moving the end of the iterator backwards by `offset` elements,
+ // returning the new end.
+ // Unsafe because the offset must be in-bounds or one-past-the-end.
+ #[inline(always)]
+ unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
+ if mem::size_of::<T>() == 0 {
+ self.end = (self.end as * $raw_mut u8).wrapping_offset(-offset) as * $raw_mut T;
+ self.ptr
+ } else {
+ self.end = self.end.offset(-offset);
+ self.end
+ }
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, T> ExactSizeIterator for $name<'a, T> {
+ #[inline(always)]
+ fn len(&self) -> usize {
+ len!(self)
+ }
+
+ #[inline(always)]
+ fn is_empty(&self) -> bool {
+ is_empty!(self)
+ }
+ }
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Iterator for $name<'a, T> {
type Item = $elem;
fn next(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
unsafe {
+ assume(!self.ptr.is_null());
if mem::size_of::<T>() != 0 {
- assume(!self.ptr.is_null());
assume(!self.end.is_null());
}
- if self.ptr == self.end {
+ if is_empty!(self) {
None
} else {
- Some($mkref!(self.ptr.post_inc()))
+ Some(& $( $mut_ )* *self.post_inc_start(1))
}
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let exact = unsafe { ptrdistance(self.ptr, self.end) };
+ let exact = len!(self);
(exact, Some(exact))
}
#[inline]
fn count(self) -> usize {
- self.len()
+ len!(self)
}
#[inline]
fn nth(&mut self, n: usize) -> Option<$elem> {
- // Call helper method. Can't put the definition here because mut versus const.
- self.iter_nth(n)
+ if n >= len!(self) {
+ // This iterator is now empty.
+ if mem::size_of::<T>() == 0 {
+ // We have to do it this way as `ptr` may never be 0, but `end`
+ // could be (due to wrapping).
+ self.end = self.ptr;
+ } else {
+ self.ptr = self.end;
+ }
+ return None;
+ }
+ // We are in bounds. `offset` does the right thing even for ZSTs.
+ unsafe {
+ let elem = Some(& $( $mut_ )* *self.ptr.offset(n as isize));
+ self.post_inc_start((n as isize).wrapping_add(1));
+ elem
+ }
}
#[inline]
// manual unrolling is needed when there are conditional exits from the loop
let mut accum = init;
unsafe {
- while ptrdistance(self.ptr, self.end) >= 4 {
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
+ while len!(self) >= 4 {
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
}
- while self.ptr != self.end {
- accum = f(accum, $mkref!(self.ptr.post_inc()))?;
+ while !is_empty!(self) {
+ accum = f(accum, & $( $mut_ )* *self.post_inc_start(1))?;
}
}
Try::from_ok(accum)
Self: Sized,
P: FnMut(Self::Item) -> bool,
{
- // The addition might panic on overflow
- // Use the len of the slice to hint optimizer to remove result index bounds check.
- let n = make_slice!(self.ptr, self.end).len();
+ // The addition might panic on overflow.
+ let n = len!(self);
self.try_fold(0, move |i, x| {
if predicate(x) { Err(i) }
else { Ok(i + 1) }
Self: Sized + ExactSizeIterator + DoubleEndedIterator
{
// No need for an overflow check here, because `ExactSizeIterator`
- // implies that the number of elements fits into a `usize`.
- // Use the len of the slice to hint optimizer to remove result index bounds check.
- let n = make_slice!(self.ptr, self.end).len();
+ let n = len!(self);
self.try_rfold(n, move |i, x| {
let i = i - 1;
if predicate(x) { Err(i) }
fn next_back(&mut self) -> Option<$elem> {
// could be implemented with slices, but this avoids bounds checks
unsafe {
+ assume(!self.ptr.is_null());
if mem::size_of::<T>() != 0 {
- assume(!self.ptr.is_null());
assume(!self.end.is_null());
}
- if self.end == self.ptr {
+ if is_empty!(self) {
None
} else {
- Some($mkref!(self.end.pre_dec()))
+ Some(& $( $mut_ )* *self.pre_dec_end(1))
}
}
}
// manual unrolling is needed when there are conditional exits from the loop
let mut accum = init;
unsafe {
- while ptrdistance(self.ptr, self.end) >= 4 {
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
+ while len!(self) >= 4 {
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
}
- while self.ptr != self.end {
- accum = f(accum, $mkref!(self.end.pre_dec()))?;
+ // inlining is_empty everywhere makes a huge performance difference
+ while !is_empty!(self) {
+ accum = f(accum, & $( $mut_ )* *self.pre_dec_end(1))?;
}
}
Try::from_ok(accum)
}
}
-macro_rules! make_slice {
- ($start: expr, $end: expr) => {{
- let start = $start;
- let diff = ($end as usize).wrapping_sub(start as usize);
- if size_from_ptr(start) == 0 {
- // use a non-null pointer value
- unsafe { from_raw_parts(1 as *const _, diff) }
- } else {
- let len = diff / size_from_ptr(start);
- unsafe { from_raw_parts(start, len) }
- }
- }}
-}
-
-macro_rules! make_mut_slice {
- ($start: expr, $end: expr) => {{
- let start = $start;
- let diff = ($end as usize).wrapping_sub(start as usize);
- if size_from_ptr(start) == 0 {
- // use a non-null pointer value
- unsafe { from_raw_parts_mut(1 as *mut _, diff) }
- } else {
- let len = diff / size_from_ptr(start);
- unsafe { from_raw_parts_mut(start, len) }
- }
- }}
-}
-
/// Immutable slice iterator
///
/// This struct is created by the [`iter`] method on [slices].
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
ptr: *const T,
- end: *const T,
+ end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ // ptr == end is a quick test for the Iterator being empty, that works
+ // for both ZST and non-ZST.
_marker: marker::PhantomData<&'a T>,
}
/// ```
#[stable(feature = "iter_to_slice", since = "1.4.0")]
pub fn as_slice(&self) -> &'a [T] {
- make_slice!(self.ptr, self.end)
- }
-
- // Helper function for Iter::nth
- fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
- match self.as_slice().get(n) {
- Some(elem_ref) => unsafe {
- self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
- Some(elem_ref)
- },
- None => {
- self.ptr = self.end;
- None
- }
- }
+ self.make_slice()
}
}
-iterator!{struct Iter -> *const T, &'a T, make_ref}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for Iter<'a, T> {
- fn is_empty(&self) -> bool {
- self.ptr == self.end
- }
-}
+iterator!{struct Iter -> *const T, &'a T, const, /* no mut */}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Iter<'a, T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
ptr: *mut T,
- end: *mut T,
+ end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ // ptr == end is a quick test for the Iterator being empty, that works
+ // for both ZST and non-ZST.
_marker: marker::PhantomData<&'a mut T>,
}
impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("IterMut")
- .field(&make_slice!(self.ptr, self.end))
+ .field(&self.make_slice())
.finish()
}
}
/// ```
#[stable(feature = "iter_to_slice", since = "1.4.0")]
pub fn into_slice(self) -> &'a mut [T] {
- make_mut_slice!(self.ptr, self.end)
- }
-
- // Helper function for IterMut::nth
- fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
- match make_mut_slice!(self.ptr, self.end).get_mut(n) {
- Some(elem_ref) => unsafe {
- self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
- Some(elem_ref)
- },
- None => {
- self.ptr = self.end;
- None
- }
- }
- }
-}
-
-iterator!{struct IterMut -> *mut T, &'a mut T, make_ref_mut}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
- fn is_empty(&self) -> bool {
- self.ptr == self.end
+ unsafe { from_raw_parts_mut(self.ptr, len!(self)) }
}
}
-// Return the number of elements of `T` from `start` to `end`.
-// Return the arithmetic difference if `T` is zero size.
-#[inline(always)]
-unsafe fn ptrdistance<T>(start: *const T, end: *const T) -> usize {
- if mem::size_of::<T>() == 0 {
- (end as usize).wrapping_sub(start as usize)
- } else {
- end.offset_from(start) as usize
- }
-}
-
-// Extension methods for raw pointers, used by the iterators
-trait PointerExt : Copy {
- unsafe fn slice_offset(self, i: isize) -> Self;
-
- /// Increments `self` by 1, but returns the old value.
- #[inline(always)]
- unsafe fn post_inc(&mut self) -> Self {
- let current = *self;
- *self = self.slice_offset(1);
- current
- }
-
- /// Decrements `self` by 1, and returns the new value.
- #[inline(always)]
- unsafe fn pre_dec(&mut self) -> Self {
- *self = self.slice_offset(-1);
- *self
- }
-}
-
-impl<T> PointerExt for *const T {
- #[inline(always)]
- unsafe fn slice_offset(self, i: isize) -> Self {
- slice_offset!(self, i)
- }
-}
-
-impl<T> PointerExt for *mut T {
- #[inline(always)]
- unsafe fn slice_offset(self, i: isize) -> Self {
- slice_offset!(self, i)
- }
-}
+iterator!{struct IterMut -> *mut T, &'a mut T, mut, mut}
/// An internal abstraction over the splitting iterators, so that
/// splitn, splitn_mut etc can be implemented once.
/// ```
/// use std::slice;
///
-/// // manifest a slice out of thin air!
-/// let ptr = 0x1234 as *const usize;
-/// let amt = 10;
-/// unsafe {
-/// let slice = slice::from_raw_parts(ptr, amt);
-/// }
+/// // manifest a slice for a single element
+/// let x = 42;
+/// let ptr = &x as *const _;
+/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
+/// assert_eq!(slice[0], 42);
/// ```
///
/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn swap(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
Ok(x) => x,
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_exchange(&self,
current: bool,
new: bool,
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_and(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
// We can't use atomic_nand here because it can result in a bool with
// an invalid value. This happens because the atomic operation is done
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_or(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T }
}
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
Ok(x) => x,
/// ```
#[inline]
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_exchange(&self,
current: *mut T,
new: *mut T,
```"),
#[inline]
#[$stable]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
unsafe { atomic_swap(self.v.get(), val, order) }
}
```"),
#[inline]
#[$stable]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_and_swap(&self,
current: $int_type,
new: $int_type,
```"),
#[inline]
#[$stable_cxchg]
- #[cfg(any(stage0, target_has_atomic = "cas"))]
+ #[cfg(target_has_atomic = "cas")]
pub fn compare_exchange(&self,
current: $int_type,
new: $int_type,
}
#[inline]
-#[cfg(any(stage0, target_has_atomic = "cas"))]
+#[cfg(target_has_atomic = "cas")]
fn strongest_failure_ordering(order: Ordering) -> Ordering {
match order {
Release => Relaxed,
}
#[inline]
-#[cfg(any(stage0, target_has_atomic = "cas"))]
+#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
match order {
Acquire => intrinsics::atomic_xchg_acq(dst, val),
}
#[inline]
-#[cfg(any(stage0, target_has_atomic = "cas"))]
+#[cfg(target_has_atomic = "cas")]
unsafe fn atomic_compare_exchange<T>(dst: *mut T,
old: T,
new: T,
}
#[test]
-fn test_is_digit() {
+fn test_is_numeric() {
assert!('2'.is_numeric());
assert!('7'.is_numeric());
+ assert!('¾'.is_numeric());
assert!(!'c'.is_numeric());
assert!(!'i'.is_numeric());
assert!(!'z'.is_numeric());
assert_eq!(res, [14, 18, 22, 26]);
}
+#[test]
+#[allow(const_err)]
+fn test_iter_ref_consistency() {
+ use std::fmt::Debug;
+
+ fn test<T : Copy + Debug + PartialEq>(x : T) {
+ let v : &[T] = &[x, x, x];
+ let v_ptrs : [*const T; 3] = match v {
+ [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _],
+ _ => unreachable!()
+ };
+ let len = v.len();
+
+ // nth(i)
+ for i in 0..len {
+ assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure
+ let nth = v.iter().nth(i).unwrap();
+ assert_eq!(nth as *const _, v_ptrs[i]);
+ }
+ assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
+
+ // stepping through with nth(0)
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let next = it.nth(0).unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.nth(0), None);
+ }
+
+ // next()
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let next = it.next().unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None, "The final call to next() should return None");
+ }
+
+ // next_back()
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let prev = it.next_back().unwrap();
+ assert_eq!(prev as *const _, v_ptrs[remaining-1]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
+ }
+ }
+
+ fn test_mut<T : Copy + Debug + PartialEq>(x : T) {
+ let v : &mut [T] = &mut [x, x, x];
+ let v_ptrs : [*mut T; 3] = match v {
+ [ref v1, ref v2, ref v3] =>
+ [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _],
+ _ => unreachable!()
+ };
+ let len = v.len();
+
+ // nth(i)
+ for i in 0..len {
+ assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure
+ let nth = v.iter_mut().nth(i).unwrap();
+ assert_eq!(nth as *mut _, v_ptrs[i]);
+ }
+ assert_eq!(v.iter().nth(len), None, "nth(len) should return None");
+
+ // stepping through with nth(0)
+ {
+ let mut it = v.iter();
+ for i in 0..len {
+ let next = it.nth(0).unwrap();
+ assert_eq!(next as *const _, v_ptrs[i]);
+ }
+ assert_eq!(it.nth(0), None);
+ }
+
+ // next()
+ {
+ let mut it = v.iter_mut();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let next = it.next().unwrap();
+ assert_eq!(next as *mut _, v_ptrs[i]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next(), None, "The final call to next() should return None");
+ }
+
+ // next_back()
+ {
+ let mut it = v.iter_mut();
+ for i in 0..len {
+ let remaining = len - i;
+ assert_eq!(it.size_hint(), (remaining, Some(remaining)));
+
+ let prev = it.next_back().unwrap();
+ assert_eq!(prev as *mut _, v_ptrs[remaining-1]);
+ }
+ assert_eq!(it.size_hint(), (0, Some(0)));
+ assert_eq!(it.next_back(), None, "The final call to next_back() should return None");
+ }
+ }
+
+ // Make sure iterators and slice patterns yield consistent addresses for various types,
+ // including ZSTs.
+ test(0u32);
+ test(());
+ test([0u32; 0]); // ZST with alignment > 0
+ test_mut(0u32);
+ test_mut(());
+ test_mut([0u32; 0]); // ZST with alignment > 0
+}
+
// The current implementation of SliceIndex fails to handle methods
// orthogonally from range types; therefore, it is worth testing
// all of the indexing operations on each input.
pub const N_table: &super::BoolTrie = &super::BoolTrie {
r1: [
- 0x03ff000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
+ 0x03ff000000000000, 0x0000000000000000, 0x720c000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000,
0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00000000000003ff
],
r2: [
- 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 3,
- 0, 0, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 5, 0, 0, 0, 3, 2, 0, 0, 0, 0, 6, 0, 2, 0, 0, 7, 0, 0, 2, 8, 0, 0, 7, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 1, 0, 2, 0, 1, 0, 1, 0, 3, 0, 4, 0, 5, 0, 1, 0, 6, 0, 1, 0, 7, 0, 7, 8,
+ 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 11, 0, 0, 0, 12, 7, 0, 0, 0, 0, 13, 0, 14, 0, 0, 15, 0, 0, 7, 16, 0, 0, 15, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 9, 0, 0, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 27, 0, 28,
+ 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28,
+ 0, 0, 1, 0, 0, 0, 0, 31, 0, 0, 7, 9, 0, 0, 32, 0, 7, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 1, 0, 0,
- 0, 0, 0, 0, 0, 2, 4, 0, 0, 12, 0, 2, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 2, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0
],
r3: &[
- 0x0000000000000000, 0x0000ffc000000000, 0x0000000003ff0000, 0x000003ff00000000,
- 0x00000000000003ff, 0x0001c00000000000, 0x000000000000ffc0, 0x0000000003ff03ff,
- 0x03ff000000000000, 0xffffffff00000000, 0x00000000000001e7, 0x070003fe00000080,
+ 0x0000000000000000, 0x0000ffc000000000, 0x03f0ffc000000000, 0x00fcffc000000000,
+ 0x0007ffc000000000, 0x7f00ffc000000000, 0x01ffffc07f000000, 0x0000000003ff0000,
+ 0x000fffff00000000, 0x00000000000003ff, 0x1ffffe0000000000, 0x0001c00000000000,
+ 0x03ff03ff00000000, 0x000000000000ffc0, 0x0000000007ff0000, 0x0000000003ff03ff,
+ 0x03ff000000000000, 0x03f1000000000000, 0xffffffffffff0000, 0x00000000000003e7,
+ 0xffffffff00000000, 0x000000000fffffff, 0xfffffc0000000000, 0xffc0000000000000,
+ 0x00000000000fffff, 0x2000000000000000, 0x070003fe00000080, 0x00000000003c0000,
+ 0x000003ff00000000, 0x00000000fffeff00, 0xfffe0000000003ff, 0x003f000000000000,
0x03ff000003ff0000
],
r4: [
- 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0, 1, 2, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 5, 6, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
],
r5: &[
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 6, 0, 5, 7, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0,
- 0, 0, 8, 0, 9, 5, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0,
- 0, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
- 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 0, 7, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 9, 10, 11, 12, 0, 13, 14, 0, 15, 16, 17, 0, 18, 19, 0, 0, 0, 0, 20, 21, 0,
+ 0, 0, 0, 22, 0, 0, 23, 24, 0, 0, 0, 25, 0, 21, 26, 0, 0, 27, 0, 0, 0, 21, 0, 0, 0, 0, 0,
+ 28, 0, 28, 0, 0, 0, 0, 0, 28, 0, 29, 30, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 32, 0, 0, 0, 28, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 33, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 0, 38, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 28, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
],
r6: &[
- 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000,
- 0x000003ff00000000, 0x03ff000000000000, 0x0000ffc000000000, 0xffc0000000000000,
- 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff,
- 0xffffffffffffc000
+ 0x0000000000000000, 0x000fffffffffff80, 0x01ffffffffffffff, 0x0000000000000c00,
+ 0x0ffffffe00000000, 0x0000000f00000000, 0x0000000000000402, 0x00000000003e0000,
+ 0x000003ff00000000, 0xfe000000ff000000, 0x0000ff8000000000, 0xf800000000000000,
+ 0x000000000fc00000, 0x3000000000000000, 0xfffffffffffcffff, 0x60000000000001ff,
+ 0x00000000e0000000, 0x0000f80000000000, 0xff000000ff000000, 0x0000fe0000000000,
+ 0xfc00000000000000, 0x03ff000000000000, 0x7fffffff00000000, 0x0000007fe0000000,
+ 0x00000000001e0000, 0x0000fffffffc0000, 0xffc0000000000000, 0x001ffffe03ff0000,
+ 0x0000000003ff0000, 0x00000000000003ff, 0x0fff000000000000, 0x0007ffff00000000,
+ 0x00001fffffff0000, 0xffffffffffffffff, 0x00007fffffffffff, 0x00000003fbff0000,
+ 0x00000000007fffff, 0x000fffff00000000, 0x01ffffff00000000, 0xffffffffffffc000,
+ 0x000000000000ff80, 0xfffe000000000000, 0x001eefffffffffff, 0x0000000000001fff
],
};
'Lu': ['LC', 'L'], 'Ll': ['LC', 'L'], 'Lt': ['LC', 'L'],
'Lm': ['L'], 'Lo': ['L'],
'Mn': ['M'], 'Mc': ['M'], 'Me': ['M'],
- 'Nd': ['N'], 'Nl': ['N'], 'No': ['No'],
+ 'Nd': ['N'], 'Nl': ['N'], 'No': ['N'],
'Pc': ['P'], 'Pd': ['P'], 'Ps': ['P'], 'Pe': ['P'],
'Pi': ['P'], 'Pf': ['P'], 'Po': ['P'],
'Sm': ['S'], 'Sc': ['S'], 'Sk': ['S'], 'So': ['S'],
PrimTy(hir::PrimTy),
TyParam(DefId),
SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
+ ToolMod, // e.g. `rustfmt` in `#[rustfmt::skip]`
// Value namespace
Fn(DefId),
// Macro namespace
Macro(DefId, MacroKind),
+ NonMacroAttr, // e.g. `#[inline]` or `#[rustfmt::skip]`
GlobalAsm(DefId),
Def::Label(..) |
Def::PrimTy(..) |
Def::SelfTy(..) |
+ Def::ToolMod |
+ Def::NonMacroAttr |
Def::Err => {
bug!("attempted .def_id() on invalid def: {:?}", self)
}
Def::SelfTy(..) => "self type",
Def::Macro(.., macro_kind) => macro_kind.descr(),
Def::GlobalAsm(..) => "global asm",
+ Def::ToolMod => "tool module",
+ Def::NonMacroAttr => "non-macro attribute",
Def::Err => "unresolved item",
}
}
}
// Desugar `<start>..=<end>` to `std::ops::RangeInclusive::new(<start>, <end>)`
ExprKind::Range(Some(ref e1), Some(ref e2), RangeLimits::Closed) => {
- // FIXME: Use e.span directly after RangeInclusive::new() is stabilized in stage0.
- let span = self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
let id = self.next_id();
let e1 = self.lower_expr(e1);
let e2 = self.lower_expr(e2);
- let ty_path = P(self.std_path(span, &["ops", "RangeInclusive"], None, false));
- let ty = P(self.ty_path(id, span, hir::QPath::Resolved(None, ty_path)));
+ let ty_path = P(self.std_path(e.span, &["ops", "RangeInclusive"], None, false));
+ let ty = P(self.ty_path(id, e.span, hir::QPath::Resolved(None, ty_path)));
let new_seg = P(hir::PathSegment::from_ident(Ident::from_str("new")));
let new_path = hir::QPath::TypeRelative(ty, new_seg);
- let new = P(self.expr(span, hir::ExprKind::Path(new_path), ThinVec::new()));
+ let new = P(self.expr(e.span, hir::ExprKind::Path(new_path), ThinVec::new()));
hir::ExprKind::Call(new, hir_vec![e1, e2])
}
ExprKind::Range(ref e1, ref e2, lims) => {
.chain(e2.iter().map(|e| ("end", e)))
.map(|(s, e)| {
let expr = P(self.lower_expr(&e));
- let unstable_span =
- self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
- let ident = Ident::new(Symbol::intern(s), unstable_span);
- self.field(ident, expr, unstable_span)
+ let ident = Ident::new(Symbol::intern(s), e.span);
+ self.field(ident, expr, e.span)
})
.collect::<P<[hir::Field]>>();
let is_unit = fields.is_empty();
- let unstable_span =
- self.allow_internal_unstable(CompilerDesugaringKind::DotFill, e.span);
let struct_path = iter::once("ops")
.chain(iter::once(path))
.collect::<Vec<_>>();
- let struct_path = self.std_path(unstable_span, &struct_path, None, is_unit);
+ let struct_path = self.std_path(e.span, &struct_path, None, is_unit);
let struct_path = hir::QPath::Resolved(None, P(struct_path));
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
} else {
hir::ExprKind::Struct(struct_path, fields, None)
},
- span: unstable_span,
+ span: e.span,
attrs: e.attrs.clone(),
};
}
Label(node_id),
Macro(def_id, macro_kind),
GlobalAsm(def_id),
+ ToolMod,
+ NonMacroAttr,
Err
});
impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind {
Async,
- DotFill,
QuestionMark,
ExistentialReturnType,
ForLoop,
pub mod nodemap;
pub mod fs;
pub mod time_graph;
+ pub mod profiling;
}
// A private module so that macro-expanded idents like
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use super::*;
#[derive(Clone)]
pub struct Preorder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
- visited: BitVector<BasicBlock>,
+ visited: BitArray<BasicBlock>,
worklist: Vec<BasicBlock>,
}
Preorder {
mir,
- visited: BitVector::new(mir.basic_blocks().len()),
+ visited: BitArray::new(mir.basic_blocks().len()),
worklist,
}
}
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
pub struct Postorder<'a, 'tcx: 'a> {
mir: &'a Mir<'tcx>,
- visited: BitVector<BasicBlock>,
+ visited: BitArray<BasicBlock>,
visit_stack: Vec<(BasicBlock, Successors<'a>)>
}
pub fn new(mir: &'a Mir<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
let mut po = Postorder {
mir,
- visited: BitVector::new(mir.basic_blocks().len()),
+ visited: BitArray::new(mir.basic_blocks().len()),
visit_stack: Vec::new()
};
Thread,
}
-#[derive(Clone, Copy, PartialEq, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum OptLevel {
No, // -O0
Less, // -O1
"disables the 'leak check' for subtyping; unsound, but useful for tests"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
"inject the given attribute in the crate"),
+ self_profile: bool = (false, parse_bool, [UNTRACKED],
+ "run the self profiler"),
+ profile_json: bool = (false, parse_bool, [UNTRACKED],
+ "output a json file with profiler results"),
}
pub fn default_lib_output() -> CrateType {
use syntax::{ast, codemap};
use syntax::feature_gate::AttributeType;
use syntax_pos::{MultiSpan, Span};
+use util::profiling::SelfProfiler;
use rustc_target::spec::{LinkerFlavor, PanicStrategy};
use rustc_target::spec::{Target, TargetTriple};
/// Used by -Z profile-queries in util::common
pub profile_channel: Lock<Option<mpsc::Sender<ProfileQueriesMsg>>>,
+ /// Used by -Z self-profile
+ pub self_profiling: Lock<SelfProfiler>,
+
/// Some measurements that are being gathered during compilation.
pub perf_stats: PerfStats,
}
}
+ pub fn profiler<F: FnOnce(&mut SelfProfiler) -> ()>(&self, f: F) {
+ let mut profiler = self.self_profiling.borrow_mut();
+ f(&mut profiler);
+ }
+
+ pub fn print_profiler_results(&self) {
+ let mut profiler = self.self_profiling.borrow_mut();
+ profiler.print_results(&self.opts);
+ }
+
+ pub fn save_json_results(&self) {
+ let profiler = self.self_profiling.borrow();
+ profiler.save_results(&self.opts);
+ }
+
pub fn print_perf_stats(&self) {
println!(
"Total time spent computing symbol hashes: {}",
imported_macro_spans: OneThread::new(RefCell::new(HashMap::new())),
incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
ignored_attr_names: ich::compute_ignored_attr_names(),
+ self_profiling: Lock::new(SelfProfiler::new()),
profile_channel: Lock::new(None),
perf_stats: PerfStats {
symbol_hash_time: Lock::new(Duration::from_secs(0)),
use mir::interpret::{GlobalId};
use rustc_data_structures::sync::Lock;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use std::iter;
use std::cmp;
use std::fmt;
} else {
return Err(Unimplemented);
};
- let mut ty_params = BitVector::new(substs_a.types().count());
+ let mut ty_params = BitArray::new(substs_a.types().count());
let mut found = false;
for ty in field.walk() {
if let ty::TyParam(p) = ty.sty {
}
/// If true, we should enable two-phase borrows checks. This is
- /// done with either `-Ztwo-phase-borrows` or with
- /// `#![feature(nll)]`.
+ /// done with either: `-Ztwo-phase-borrows`, `#![feature(nll)]`,
+ /// or by opting into an edition after 2015.
pub fn two_phase_borrows(self) -> bool {
- self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows
+ if self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows {
+ return true;
+ }
+
+ match self.sess.edition() {
+ Edition::Edition2015 => false,
+ Edition::Edition2018 => true,
+ _ => true,
+ }
}
/// What mode(s) of borrowck should we run? AST? MIR? both?
use ty::query::queries;
use ty::query::Query;
use ty::query::QueryCache;
+use util::profiling::ProfileCategory;
use std::hash::Hash;
use std::fmt::Debug;
pub trait QueryConfig<'tcx> {
const NAME: &'static str;
+ const CATEGORY: ProfileCategory;
type Key: Eq + Hash + Clone + Debug;
type Value: Clone + for<'a> HashStable<StableHashingContext<'a>>;
use ty::subst::Substs;
use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
use util::common::{ErrorReported};
+use util::profiling::ProfileCategory::*;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_target::spec::PanicStrategy;
let mut lock = cache.borrow_mut();
if let Some(value) = lock.results.get(key) {
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
+ tcx.sess.profiler(|p| {
+ p.record_query(Q::CATEGORY);
+ p.record_query_hit(Q::CATEGORY);
+ });
+
let result = Ok((value.value.clone(), value.index));
return TryGetJob::JobCompleted(result);
}
)
);
+ self.sess.profiler(|p| p.record_query(Q::CATEGORY));
+
let job = match JobOwner::try_get(self, span, &key) {
TryGetJob::NotYetStarted(job) => job,
TryGetJob::JobCompleted(result) => {
return result.map(|(v, index)| {
+ self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY));
self.dep_graph.read_index(index);
v
})
if dep_node.kind.is_anon() {
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
+ self.sess.profiler(|p| p.start_activity(Q::CATEGORY));
let res = job.start(self, |tcx| {
tcx.dep_graph.with_anon_task(dep_node.kind, || {
})
});
+ self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
let ((result, dep_node_index), diagnostics) = res;
if !dep_node.kind.is_input() {
if let Some(dep_node_index) = self.try_mark_green_and_read(&dep_node) {
profq_msg!(self, ProfileQueriesMsg::CacheHit);
+ self.sess.profiler(|p| p.record_query_hit(Q::CATEGORY));
+
return self.load_from_disk_and_cache_in_memory::<Q>(key,
job,
dep_node_index,
key, dep_node);
profq_msg!(self, ProfileQueriesMsg::ProviderBegin);
+ self.sess.profiler(|p| {
+ p.start_activity(Q::CATEGORY);
+ p.record_query(Q::CATEGORY);
+ });
+
let res = job.start(self, |tcx| {
if dep_node.kind.is_eval_always() {
tcx.dep_graph.with_eval_always_task(dep_node,
Q::compute)
}
});
+
+ self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
profq_msg!(self, ProfileQueriesMsg::ProviderEnd);
let ((result, dep_node_index), diagnostics) = res;
// DepNodeIndex. We must invoke the query itself. The performance cost
// this introduces should be negligible as we'll immediately hit the
// in-memory cache, or another query down the line will.
+
+ self.sess.profiler(|p| {
+ p.start_activity(Q::CATEGORY);
+ p.record_query(Q::CATEGORY);
+ });
+
let _ = self.get_query::<Q>(DUMMY_SP, key);
+
+ self.sess.profiler(|p| p.end_activity(Q::CATEGORY));
}
}
rustc_data_structures::stable_hasher::StableHasher,
ich::StableHashingContext
};
+ use util::profiling::ProfileCategory;
define_queries_struct! {
tcx: $tcx,
type Value = $V;
const NAME: &'static str = stringify!($name);
+ const CATEGORY: ProfileCategory = $category;
}
impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> {
--- /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.
+
+use session::config::Options;
+
+use std::fs;
+use std::io::{self, StdoutLock, Write};
+use std::time::Instant;
+
+macro_rules! define_categories {
+ ($($name:ident,)*) => {
+ #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+ pub enum ProfileCategory {
+ $($name),*
+ }
+
+ #[allow(bad_style)]
+ struct Categories<T> {
+ $($name: T),*
+ }
+
+ impl<T: Default> Categories<T> {
+ fn new() -> Categories<T> {
+ Categories {
+ $($name: T::default()),*
+ }
+ }
+ }
+
+ impl<T> Categories<T> {
+ fn get(&self, category: ProfileCategory) -> &T {
+ match category {
+ $(ProfileCategory::$name => &self.$name),*
+ }
+ }
+
+ fn set(&mut self, category: ProfileCategory, value: T) {
+ match category {
+ $(ProfileCategory::$name => self.$name = value),*
+ }
+ }
+ }
+
+ struct CategoryData {
+ times: Categories<u64>,
+ query_counts: Categories<(u64, u64)>,
+ }
+
+ impl CategoryData {
+ fn new() -> CategoryData {
+ CategoryData {
+ times: Categories::new(),
+ query_counts: Categories::new(),
+ }
+ }
+
+ fn print(&self, lock: &mut StdoutLock) {
+ writeln!(lock, "| Phase | Time (ms) | Queries | Hits (%) |")
+ .unwrap();
+ writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
+ .unwrap();
+
+ $(
+ let (hits, total) = self.query_counts.$name;
+ let (hits, total) = if total > 0 {
+ (format!("{:.2}",
+ (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
+ } else {
+ ("".into(), "".into())
+ };
+
+ writeln!(
+ lock,
+ "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
+ stringify!($name),
+ self.times.$name / 1_000_000,
+ total,
+ hits
+ ).unwrap();
+ )*
+ }
+
+ fn json(&self) -> String {
+ let mut json = String::from("[");
+
+ $(
+ let (hits, total) = self.query_counts.$name;
+
+ json.push_str(&format!(
+ "{{ \"category\": {}, \"time_ms\": {},
+ \"query_count\": {}, \"query_hits\": {} }}",
+ stringify!($name),
+ self.times.$name / 1_000_000,
+ total,
+ format!("{:.2}", (((hits as f32) / (total as f32)) * 100.0))
+ ));
+ )*
+
+ json.push(']');
+
+ json
+ }
+ }
+ }
+}
+
+define_categories! {
+ Parsing,
+ Expansion,
+ TypeChecking,
+ BorrowChecking,
+ Codegen,
+ Linking,
+ Other,
+}
+
+pub struct SelfProfiler {
+ timer_stack: Vec<ProfileCategory>,
+ data: CategoryData,
+ current_timer: Instant,
+}
+
+impl SelfProfiler {
+ pub fn new() -> SelfProfiler {
+ let mut profiler = SelfProfiler {
+ timer_stack: Vec::new(),
+ data: CategoryData::new(),
+ current_timer: Instant::now(),
+ };
+
+ profiler.start_activity(ProfileCategory::Other);
+
+ profiler
+ }
+
+ pub fn start_activity(&mut self, category: ProfileCategory) {
+ match self.timer_stack.last().cloned() {
+ None => {
+ self.current_timer = Instant::now();
+ },
+ Some(current_category) if current_category == category => {
+ //since the current category is the same as the new activity's category,
+ //we don't need to do anything with the timer, we just need to push it on the stack
+ }
+ Some(current_category) => {
+ let elapsed = self.stop_timer();
+
+ //record the current category's time
+ let new_time = self.data.times.get(current_category) + elapsed;
+ self.data.times.set(current_category, new_time);
+ }
+ }
+
+ //push the new category
+ self.timer_stack.push(category);
+ }
+
+ pub fn record_query(&mut self, category: ProfileCategory) {
+ let (hits, total) = *self.data.query_counts.get(category);
+ self.data.query_counts.set(category, (hits, total + 1));
+ }
+
+ pub fn record_query_hit(&mut self, category: ProfileCategory) {
+ let (hits, total) = *self.data.query_counts.get(category);
+ self.data.query_counts.set(category, (hits + 1, total));
+ }
+
+ pub fn end_activity(&mut self, category: ProfileCategory) {
+ match self.timer_stack.pop() {
+ None => bug!("end_activity() was called but there was no running activity"),
+ Some(c) =>
+ assert!(
+ c == category,
+ "end_activity() was called but a different activity was running"),
+ }
+
+ //check if the new running timer is in the same category as this one
+ //if it is, we don't need to do anything
+ if let Some(c) = self.timer_stack.last() {
+ if *c == category {
+ return;
+ }
+ }
+
+ //the new timer is different than the previous,
+ //so record the elapsed time and start a new timer
+ let elapsed = self.stop_timer();
+ let new_time = self.data.times.get(category) + elapsed;
+ self.data.times.set(category, new_time);
+ }
+
+ fn stop_timer(&mut self) -> u64 {
+ let elapsed = self.current_timer.elapsed();
+
+ self.current_timer = Instant::now();
+
+ (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
+ }
+
+ pub fn print_results(&mut self, opts: &Options) {
+ self.end_activity(ProfileCategory::Other);
+
+ assert!(
+ self.timer_stack.is_empty(),
+ "there were timers running when print_results() was called");
+
+ let out = io::stdout();
+ let mut lock = out.lock();
+
+ let crate_name =
+ opts.crate_name
+ .as_ref()
+ .map(|n| format!(" for {}", n))
+ .unwrap_or_default();
+
+ writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
+ writeln!(lock).unwrap();
+
+ self.data.print(&mut lock);
+
+ writeln!(lock).unwrap();
+ writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();
+
+ let incremental = if opts.incremental.is_some() { "on" } else { "off" };
+ writeln!(lock, "Incremental: {}", incremental).unwrap();
+ }
+
+ pub fn save_results(&self, opts: &Options) {
+ let category_data = self.data.json();
+ let compilation_options =
+ format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
+ opts.optimize,
+ if opts.incremental.is_some() { "true" } else { "false" });
+
+ let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
+ category_data,
+ compilation_options);
+
+ fs::write("self_profiler_results.json", json).unwrap();
+ }
+}
OptLevel::Size => "-O2",
OptLevel::SizeMin => "-O2"
});
+ match self.sess.opts.optimize {
+ OptLevel::No => (),
+ OptLevel::Less |
+ OptLevel::Default |
+ OptLevel::Aggressive |
+ OptLevel::Size |
+ OptLevel::SizeMin => {
+ // LLD generates incorrect debugging information when
+ // optimization is applied: strip debug sections.
+ self.cmd.arg("--strip-debug");
+ }
+ }
}
fn pgo_gen(&mut self) {
use back::bytecode::{DecodedBytecode, RLIB_BYTECODE_EXTENSION};
use back::symbol_export;
use back::write::{ModuleConfig, with_llvm_pmb, CodegenContext};
-use back::write;
+use back::write::{self, DiagnosticHandlers};
use errors::{FatalError, Handler};
use llvm::archive_ro::ArchiveRO;
use llvm::{True, False};
let module = modules.remove(costliest_module);
let mut serialized_bitcode = Vec::new();
{
- let llmod = module.llvm().expect("can't lto pre-codegened modules").llmod();
+ let (llcx, llmod) = {
+ let llvm = module.llvm().expect("can't lto pre-codegened modules");
+ (&llvm.llcx, llvm.llmod())
+ };
info!("using {:?} as a base module", module.llmod_id);
+ // The linking steps below may produce errors and diagnostics within LLVM
+ // which we'd like to handle and print, so set up our diagnostic handlers
+ // (which get unregistered when they go out of scope below).
+ let _handler = DiagnosticHandlers::new(cgcx, diag_handler, llcx);
+
// For all other modules we codegened we'll need to link them into our own
// bitcode. All modules were codegened in their own LLVM context, however,
// and we want to move everything to the same LLVM context. Currently the
}
}
-struct DiagnosticHandlers<'a> {
+pub struct DiagnosticHandlers<'a> {
data: *mut (&'a CodegenContext, &'a Handler),
llcx: &'a llvm::Context,
}
impl<'a> DiagnosticHandlers<'a> {
- fn new(cgcx: &'a CodegenContext,
- handler: &'a Handler,
- llcx: &'a llvm::Context) -> Self {
+ pub fn new(cgcx: &'a CodegenContext,
+ handler: &'a Handler,
+ llcx: &'a llvm::Context) -> Self {
let data = Box::into_raw(Box::new((cgcx, handler)));
unsafe {
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _);
opt.message));
}
}
- llvm::diagnostic::PGO(diagnostic_ref) => {
+ llvm::diagnostic::PGO(diagnostic_ref) |
+ llvm::diagnostic::Linker(diagnostic_ref) => {
let msg = llvm::build_string(|s| {
llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
- }).expect("non-UTF8 PGO diagnostic");
+ }).expect("non-UTF8 diagnostic");
diag_handler.warn(&msg);
}
llvm::diagnostic::UnknownDiagnostic(..) => {},
use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
use rustc::middle::exported_symbols;
use rustc::util::common::{time, print_time_passes_entry};
+use rustc::util::profiling::ProfileCategory;
use rustc::session::config::{self, NoDebugInfo};
use rustc::session::Session;
use rustc_incremental;
let link_meta = link::build_link_meta(crate_hash);
// Codegen the metadata.
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
let llmod_id = "metadata";
let metadata_llvm_module = ModuleLlvm::new(tcx.sess, llmod_id);
let metadata = time(tcx.sess, "write metadata", || {
write_metadata(tcx, &metadata_llvm_module, &link_meta)
});
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
let metadata_module = ModuleCodegen {
name: link::METADATA_MODULE_NAME.to_string(),
use syntax_pos::Pos;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use syntax_pos::BytePos;
};
// Find all the scopes with variables defined in them.
- let mut has_variables = BitVector::new(mir.source_scopes.len());
+ let mut has_variables = BitArray::new(mir.source_scopes.len());
for var in mir.vars_iter() {
let decl = &mir.local_decls[var];
has_variables.insert(decl.visibility_scope);
fn make_mir_scope(cx: &CodegenCx<'ll, '_>,
mir: &Mir,
- has_variables: &BitVector<SourceScope>,
+ has_variables: &BitArray<SourceScope>,
debug_context: &FunctionDebugContextData<'ll>,
scope: SourceScope,
scopes: &mut IndexVec<SourceScope, MirDebugScope<'ll>>) {
use rustc::ty::{self, TyCtxt};
use rustc::util::time_graph;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
+use rustc::util::profiling::ProfileCategory;
use rustc_mir::monomorphize;
use rustc_codegen_utils::codegen_backend::CodegenBackend;
// Run the linker on any artifacts that resulted from the LLVM run.
// This should produce either a finished executable or library.
+ sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
time(sess, "linking", || {
back::link::link_binary(sess, &ongoing_codegen,
outputs, &ongoing_codegen.crate_name.as_str());
});
+ sess.profiler(|p| p.end_activity(ProfileCategory::Linking));
// Now that we won't touch anything in the incremental compilation directory
// any more, we can finalize it (which involves renaming it)
Optimization(OptimizationDiagnostic<'ll>),
InlineAsm(InlineAsmDiagnostic<'ll>),
PGO(&'ll DiagnosticInfo),
+ Linker(&'ll DiagnosticInfo),
/// LLVM has other types that we do not wrap here.
UnknownDiagnostic(&'ll DiagnosticInfo),
Dk::PGOProfile => {
PGO(di)
}
+ Dk::Linker => {
+ Linker(di)
+ }
_ => UnknownDiagnostic(di),
}
OptimizationRemarkOther,
OptimizationFailure,
PGOProfile,
+ Linker,
}
/// LLVMRustArchiveKind
//! An analysis to determine which locals require allocas and
//! which do not.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::{self, Location, TerminatorKind};
use type_of::LayoutLlvmExt;
use super::FunctionCx;
-pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitVector<mir::Local> {
+pub fn non_ssa_locals(fx: &FunctionCx<'a, 'll, 'tcx>) -> BitArray<mir::Local> {
let mir = fx.mir;
let mut analyzer = LocalAnalyzer::new(fx);
struct LocalAnalyzer<'mir, 'a: 'mir, 'll: 'a, 'tcx: 'll> {
fx: &'mir FunctionCx<'a, 'll, 'tcx>,
dominators: Dominators<mir::BasicBlock>,
- non_ssa_locals: BitVector<mir::Local>,
+ non_ssa_locals: BitArray<mir::Local>,
// 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>
let mut analyzer = LocalAnalyzer {
fx,
dominators: fx.mir.dominators(),
- non_ssa_locals: BitVector::new(fx.mir.local_decls.len()),
+ non_ssa_locals: BitArray::new(fx.mir.local_decls.len()),
first_assignment: IndexVec::from_elem(invalid_location, &fx.mir.local_decls)
};
use std::iter;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
pub use self::constant::codegen_static_initializer;
debuginfo::start_emitting_source_locations(&fx.debug_context);
let rpo = traversal::reverse_postorder(&mir);
- let mut visited = BitVector::new(mir.basic_blocks().len());
+ let mut visited = BitArray::new(mir.basic_blocks().len());
// Codegen the body of each block using reverse postorder
for (bb, _) in rpo {
bx: &Builder<'a, 'll, 'tcx>,
fx: &FunctionCx<'a, 'll, 'tcx>,
scopes: &IndexVec<mir::SourceScope, debuginfo::MirDebugScope<'ll>>,
- memory_locals: &BitVector<mir::Local>,
+ memory_locals: &BitArray<mir::Local>,
) -> Vec<LocalRef<'ll, 'tcx>> {
let mir = fx.mir;
let tcx = bx.tcx();
// except according to those terms.
use indexed_vec::{Idx, IndexVec};
-use std::iter::FromIterator;
use std::marker::PhantomData;
type Word = u128;
const WORD_BITS: usize = 128;
-/// A very simple BitVector type.
+/// A very simple BitArray type.
+///
+/// It does not support resizing after creation; use `BitVector` for that.
#[derive(Clone, Debug, PartialEq)]
-pub struct BitVector<C: Idx> {
+pub struct BitArray<C: Idx> {
data: Vec<Word>,
marker: PhantomData<C>,
}
+#[derive(Clone, Debug, PartialEq)]
+pub struct BitVector<C: Idx> {
+ data: BitArray<C>,
+}
+
impl<C: Idx> BitVector<C> {
+ pub fn grow(&mut self, num_bits: C) {
+ self.data.grow(num_bits)
+ }
+
+ pub fn new() -> BitVector<C> {
+ BitVector {
+ data: BitArray::new(0),
+ }
+ }
+
+ pub fn with_capacity(bits: usize) -> BitVector<C> {
+ BitVector {
+ data: BitArray::new(bits),
+ }
+ }
+
+ /// Returns true if the bit has changed.
+ #[inline]
+ pub fn insert(&mut self, bit: C) -> bool {
+ self.grow(bit);
+ self.data.insert(bit)
+ }
+
#[inline]
- pub fn new(num_bits: usize) -> BitVector<C> {
+ pub fn contains(&self, bit: C) -> bool {
+ let (word, mask) = word_mask(bit);
+ if let Some(word) = self.data.data.get(word) {
+ (word & mask) != 0
+ } else {
+ false
+ }
+ }
+}
+
+impl<C: Idx> BitArray<C> {
+ // Do not make this method public, instead switch your use case to BitVector.
+ #[inline]
+ fn grow(&mut self, num_bits: C) {
let num_words = words(num_bits);
- BitVector {
+ if self.data.len() <= num_words {
+ self.data.resize(num_words + 1, 0)
+ }
+ }
+
+ #[inline]
+ pub fn new(num_bits: usize) -> BitArray<C> {
+ let num_words = words(num_bits);
+ BitArray {
data: vec![0; num_words],
marker: PhantomData,
}
///
/// The two vectors must have the same length.
#[inline]
- pub fn contains_all(&self, other: &BitVector<C>) -> bool {
+ pub fn contains_all(&self, other: &BitArray<C>) -> bool {
assert_eq!(self.data.len(), other.data.len());
self.data.iter().zip(&other.data).all(|(a, b)| (a & b) == *b)
}
}
#[inline]
- pub fn merge(&mut self, all: &BitVector<C>) -> bool {
+ pub fn merge(&mut self, all: &BitArray<C>) -> bool {
assert!(self.data.len() == all.data.len());
let mut changed = false;
for (i, j) in self.data.iter_mut().zip(&all.data) {
changed
}
- #[inline]
- pub fn grow(&mut self, num_bits: C) {
- let num_words = words(num_bits);
- if self.data.len() < num_words {
- self.data.resize(num_words, 0)
- }
- }
-
/// Iterates over indexes of set bits in a sorted order
#[inline]
- pub fn iter<'a>(&'a self) -> BitVectorIter<'a, C> {
- BitVectorIter {
+ pub fn iter<'a>(&'a self) -> BitIter<'a, C> {
+ BitIter {
iter: self.data.iter(),
current: 0,
idx: 0,
}
}
-pub struct BitVectorIter<'a, C: Idx> {
+pub struct BitIter<'a, C: Idx> {
iter: ::std::slice::Iter<'a, Word>,
current: Word,
idx: usize,
marker: PhantomData<C>
}
-impl<'a, C: Idx> Iterator for BitVectorIter<'a, C> {
+impl<'a, C: Idx> Iterator for BitIter<'a, C> {
type Item = C;
fn next(&mut self) -> Option<C> {
while self.current == 0 {
}
}
-impl<C: Idx> FromIterator<bool> for BitVector<C> {
- fn from_iter<I>(iter: I) -> BitVector<C>
- where
- I: IntoIterator<Item = bool>,
- {
- let iter = iter.into_iter();
- let (len, _) = iter.size_hint();
- // Make the minimum length for the bitvector WORD_BITS bits since that's
- // the smallest non-zero size anyway.
- let len = if len < WORD_BITS { WORD_BITS } else { len };
- let mut bv = BitVector::new(len);
- for (idx, val) in iter.enumerate() {
- if idx > len {
- bv.grow(C::new(idx));
- }
- if val {
- bv.insert(C::new(idx));
- }
- }
-
- bv
- }
-}
-
/// A "bit matrix" is basically a matrix of booleans represented as
/// one gigantic bitvector. In other words, it is as if you have
/// `rows` bitvectors, each of length `columns`.
/// Iterates through all the columns set to true in a given row of
/// the matrix.
- pub fn iter<'a>(&'a self, row: R) -> BitVectorIter<'a, C> {
+ pub fn iter<'a>(&'a self, row: R) -> BitIter<'a, C> {
let (start, end) = self.range(row);
- BitVectorIter {
+ BitIter {
iter: self.vector[start..end].iter(),
current: 0,
idx: 0,
C: Idx,
{
columns: usize,
- vector: IndexVec<R, BitVector<C>>,
+ vector: IndexVec<R, BitArray<C>>,
}
impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
fn ensure_row(&mut self, row: R) {
let columns = self.columns;
self.vector
- .ensure_contains_elem(row, || BitVector::new(columns));
+ .ensure_contains_elem(row, || BitArray::new(columns));
}
/// Sets the cell at `(row, column)` to true. Put another way, insert
}
/// Merge a row, `from`, into the `into` row.
- pub fn merge_into(&mut self, into: R, from: &BitVector<C>) -> bool {
+ pub fn merge_into(&mut self, into: R, from: &BitArray<C>) -> bool {
self.ensure_row(into);
self.vector[into].merge(from)
}
}
/// Iterates through each row and the accompanying bit set.
- pub fn iter_enumerated<'a>(&'a self) -> impl Iterator<Item = (R, &'a BitVector<C>)> + 'a {
+ pub fn iter_enumerated<'a>(&'a self) -> impl Iterator<Item = (R, &'a BitArray<C>)> + 'a {
self.vector.iter_enumerated()
}
- pub fn row(&self, row: R) -> Option<&BitVector<C>> {
+ pub fn row(&self, row: R) -> Option<&BitArray<C>> {
self.vector.get(row)
}
}
#[test]
fn bitvec_iter_works() {
- let mut bitvec: BitVector<usize> = BitVector::new(100);
+ let mut bitvec: BitArray<usize> = BitArray::new(100);
bitvec.insert(1);
bitvec.insert(10);
bitvec.insert(19);
#[test]
fn bitvec_iter_works_2() {
- let mut bitvec: BitVector<usize> = BitVector::new(319);
+ let mut bitvec: BitArray<usize> = BitArray::new(319);
bitvec.insert(0);
bitvec.insert(127);
bitvec.insert(191);
#[test]
fn union_two_vecs() {
- let mut vec1: BitVector<usize> = BitVector::new(65);
- let mut vec2: BitVector<usize> = BitVector::new(65);
+ let mut vec1: BitArray<usize> = BitArray::new(65);
+ let mut vec2: BitArray<usize> = BitArray::new(65);
assert!(vec1.insert(3));
assert!(!vec1.insert(3));
assert!(vec2.insert(5));
#[test]
fn grow() {
- let mut vec1: BitVector<usize> = BitVector::new(65);
+ let mut vec1: BitVector<usize> = BitVector::with_capacity(65);
for index in 0..65 {
assert!(vec1.insert(index));
assert!(!vec1.insert(index));
//! the field `next_edge`). Each of those fields is an array that should
//! be indexed by the direction (see the type `Direction`).
-use bitvec::BitVector;
+use bitvec::BitArray;
use std::fmt::Debug;
use std::usize;
use snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
direction: Direction,
entry_node: NodeIndex,
) -> Vec<NodeIndex> {
- let mut visited = BitVector::new(self.len_nodes());
+ let mut visited = BitArray::new(self.len_nodes());
let mut stack = vec![];
let mut result = Vec::with_capacity(self.len_nodes());
let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| {
{
graph: &'g Graph<N, E>,
stack: Vec<NodeIndex>,
- visited: BitVector<usize>,
+ visited: BitArray<usize>,
direction: Direction,
}
start_node: NodeIndex,
direction: Direction,
) -> Self {
- let mut visited = BitVector::new(graph.len_nodes());
+ let mut visited = BitArray::new(graph.len_nodes());
visited.insert(start_node.node_id());
DepthFirstTraversal {
graph,
impl<A: Array> Extend<A::Element> for SmallVec<A> {
fn extend<I: IntoIterator<Item=A::Element>>(&mut self, iter: I) {
- if self.is_array() {
- let iter = iter.into_iter();
- self.reserve(iter.size_hint().0);
-
- for el in iter {
- self.push(el);
- }
- } else {
- match self.0 {
- AccumulateVec::Heap(ref mut vec) => vec.extend(iter),
- _ => unreachable!()
- }
+ let iter = iter.into_iter();
+ self.reserve(iter.size_hint().0);
+ match self.0 {
+ AccumulateVec::Heap(ref mut vec) => vec.extend(iter),
+ _ => iter.for_each(|el| self.push(el))
}
}
}
use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
use rustc::traits;
use rustc::util::common::{install_panic_hook, time, ErrorReported};
+use rustc::util::profiling::ProfileCategory;
use rustc_allocator as allocator;
use rustc_borrowck as borrowck;
use rustc_incremental;
sess.print_perf_stats();
}
+ if sess.opts.debugging_opts.self_profile {
+ sess.print_profiler_results();
+
+ if sess.opts.debugging_opts.profile_json {
+ sess.save_json_results();
+ }
+ }
+
controller_entry_point!(
compilation_done,
sess,
profile::begin(sess);
}
+ sess.profiler(|p| p.start_activity(ProfileCategory::Parsing));
let krate = time(sess, "parsing", || match *input {
Input::File(ref file) => parse::parse_crate_from_file(file, &sess.parse_sess),
Input::Str {
ref name,
} => parse::parse_crate_from_source_str(name.clone(), input.clone(), &sess.parse_sess),
})?;
+ sess.profiler(|p| p.end_activity(ProfileCategory::Parsing));
sess.diagnostic().set_continue_after_error(true);
syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote);
// Expand all macros
+ sess.profiler(|p| p.start_activity(ProfileCategory::Expansion));
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
}
krate
});
+ sess.profiler(|p| p.end_activity(ProfileCategory::Expansion));
krate = time(sess, "maybe building test harness", || {
syntax::test::modify_for_testing(
::rustc::middle::dependency_format::calculate(tcx)
});
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::Codegen));
let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx));
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::Codegen));
if tcx.sess.profile_queries() {
profile::dump(&tcx.sess, "profile_queries".to_string())
}
fn check_const(cx: &LateContext, body_id: hir::BodyId, what: &str) {
let def_id = cx.tcx.hir.body_owner_def_id(body_id);
- let param_env = cx.tcx.param_env(def_id);
+ let is_static = cx.tcx.is_static(def_id).is_some();
+ let param_env = if is_static {
+ // Use the same param_env as `codegen_static_initializer`, to reuse the cache.
+ ty::ParamEnv::reveal_all()
+ } else {
+ cx.tcx.param_env(def_id)
+ };
let cid = ::rustc::mir::interpret::GlobalId {
instance: ty::Instance::mono(cx.tcx, def_id),
promoted: None
match cx.tcx.const_eval(param_env.and(cid)) {
Ok(val) => validate_const(cx.tcx, val, param_env, cid, what),
Err(err) => {
- // errors for statics are already reported directly in the query
- if cx.tcx.is_static(def_id).is_none() {
+ // errors for statics are already reported directly in the query, avoid duplicates
+ if !is_static {
let span = cx.tcx.def_span(def_id);
err.report_as_lint(
cx.tcx.at(span),
use rustc::lint::builtin::{
BARE_TRAIT_OBJECTS,
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
- MACRO_USE_EXTERN_CRATE,
ELIDED_LIFETIMES_IN_PATHS,
parser::QUESTION_MARK_MACRO_SEP
};
add_lint_group!(sess,
"rust_2018_idioms",
BARE_TRAIT_OBJECTS,
- UNREACHABLE_PUB,
UNUSED_EXTERN_CRATES,
- MACRO_USE_EXTERN_CRATE,
- ELIDED_LIFETIMES_IN_PATHS,
- ELLIPSIS_INCLUSIVE_RANGE_PATTERNS);
+ ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
+ ELIDED_LIFETIMES_IN_PATHS
+
+ // FIXME(#52665, #47816) not always applicable and not all
+ // macros are ready for this yet.
+ // UNREACHABLE_PUB,
+
+ // FIXME macro crates are not up for this yet, too much
+ // breakage is seen if we try to encourage this lint.
+ // MACRO_USE_EXTERN_CRATE,
+ );
// Guidelines for creating a future incompatibility lint:
//
optional_components.push("hexagon");
}
+ if major > 6 {
+ optional_components.push("riscv");
+ }
+
// FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses.
let required_components = &["ipo",
LLVMInitializeMSP430Target,
LLVMInitializeMSP430TargetMC,
LLVMInitializeMSP430AsmPrinter);
+ init_target!(llvm_component = "riscv",
+ LLVMInitializeRISCVTargetInfo,
+ LLVMInitializeRISCVTarget,
+ LLVMInitializeRISCVTargetMC,
+ LLVMInitializeRISCVAsmPrinter,
+ LLVMInitializeRISCVAsmParser);
init_target!(llvm_component = "sparc",
LLVMInitializeSparcTargetInfo,
LLVMInitializeSparcTarget,
use rustc::mir::{Field, Projection, ProjectionElem, Rvalue, Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind};
use rustc::ty::query::Providers;
-use rustc::ty::{self, ParamEnv, TyCtxt};
+use rustc::ty::{self, ParamEnv, TyCtxt, Ty};
use rustc_errors::{Diagnostic, DiagnosticBuilder, Level};
use rustc_data_structures::graph::dominators::Dominators;
// that is useful later.
let drop_place_ty = gcx.lift(&drop_place_ty).unwrap();
- self.visit_terminator_drop(loc, term, flow_state, drop_place, drop_place_ty, span);
+ debug!("visit_terminator_drop \
+ loc: {:?} term: {:?} drop_place: {:?} drop_place_ty: {:?} span: {:?}",
+ loc, term, drop_place, drop_place_ty, span);
+
+ self.visit_terminator_drop(
+ loc, term, flow_state, drop_place, drop_place_ty, span, SeenTy(None));
}
TerminatorKind::DropAndReplace {
location: ref drop_place,
}
}
+/// A simple linked-list threaded up the stack of recursive calls in `visit_terminator_drop`.
+#[derive(Copy, Clone, Debug)]
+struct SeenTy<'a, 'gcx: 'a>(Option<(Ty<'gcx>, &'a SeenTy<'a, 'gcx>)>);
+
+impl<'a, 'gcx> SeenTy<'a, 'gcx> {
+ /// Return a new list with `ty` prepended to the front of `self`.
+ fn cons(&'a self, ty: Ty<'gcx>) -> Self {
+ SeenTy(Some((ty, self)))
+ }
+
+ /// True if and only if `ty` occurs on the linked list `self`.
+ fn have_seen(self, ty: Ty) -> bool {
+ let mut this = self.0;
+ loop {
+ match this {
+ None => return false,
+ Some((seen_ty, recur)) => {
+ if seen_ty == ty {
+ return true;
+ } else {
+ this = recur.0;
+ continue;
+ }
+ }
+ }
+ }
+ }
+}
+
impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
/// Invokes `access_place` as appropriate for dropping the value
/// at `drop_place`. Note that the *actual* `Drop` in the MIR is
drop_place: &Place<'tcx>,
erased_drop_place_ty: ty::Ty<'gcx>,
span: Span,
+ prev_seen: SeenTy<'_, 'gcx>,
) {
+ if prev_seen.have_seen(erased_drop_place_ty) {
+ // if we have directly seen the input ty `T`, then we must
+ // have had some *direct* ownership loop between `T` and
+ // some directly-owned (as in, actually traversed by
+ // recursive calls below) part that is also of type `T`.
+ //
+ // Note: in *all* such cases, the data in question cannot
+ // be constructed (nor destructed) in finite time/space.
+ //
+ // Proper examples, some of which are statically rejected:
+ //
+ // * `struct A { field: A, ... }`:
+ // statically rejected as infinite size
+ //
+ // * `type B = (B, ...);`:
+ // statically rejected as cyclic
+ //
+ // * `struct C { field: Box<C>, ... }`
+ // * `struct D { field: Box<(D, D)>, ... }`:
+ // *accepted*, though impossible to construct
+ //
+ // Here is *NOT* an example:
+ // * `struct Z { field: Option<Box<Z>>, ... }`:
+ // Here, the type is both representable in finite space (due to the boxed indirection)
+ // and constructable in finite time (since the recursion can bottom out with `None`).
+ // This is an obvious instance of something the compiler must accept.
+ //
+ // Since some of the above impossible cases like `C` and
+ // `D` are accepted by the compiler, we must take care not
+ // to infinite-loop while processing them. But since such
+ // cases cannot actually arise, it is sound for us to just
+ // skip them during drop. If the developer uses unsafe
+ // code to construct them, they should not be surprised by
+ // weird drop behavior in their resulting code.
+ debug!("visit_terminator_drop previously seen \
+ erased_drop_place_ty: {:?} on prev_seen: {:?}; returning early.",
+ erased_drop_place_ty, prev_seen);
+ return;
+ }
+
let gcx = self.tcx.global_tcx();
let drop_field = |mir: &mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>,
(index, field): (usize, ty::Ty<'gcx>)| {
let field_ty = gcx.normalize_erasing_regions(mir.param_env, field);
let place = drop_place.clone().field(Field::new(index), field_ty);
- mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span);
+ debug!("visit_terminator_drop drop_field place: {:?} field_ty: {:?}", place, field_ty);
+ let seen = prev_seen.cons(erased_drop_place_ty);
+ mir.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span, seen);
};
match erased_drop_place_ty.sty {
.enumerate()
.for_each(|field| drop_field(self, field));
}
+
+ // #45696: special-case Box<T> by treating its dtor as
+ // only deep *across owned content*. Namely, we know
+ // dropping a box does not touch data behind any
+ // references it holds; if we were to instead fall into
+ // the base case below, we would have a Deep Write due to
+ // the box being `needs_drop`, and that Deep Write would
+ // touch `&mut` data in the box.
+ ty::TyAdt(def, _) if def.is_box() => {
+ // When/if we add a `&own T` type, this action would
+ // be like running the destructor of the `&own T`.
+ // (And the owner of backing storage referenced by the
+ // `&own T` would be responsible for deallocating that
+ // backing storage.)
+
+ // we model dropping any content owned by the box by
+ // recurring on box contents. This catches cases like
+ // `Box<Box<ScribbleWhenDropped<&mut T>>>`, while
+ // still restricting Write to *owned* content.
+ let ty = erased_drop_place_ty.boxed_ty();
+ let deref_place = drop_place.clone().deref();
+ debug!("visit_terminator_drop drop-box-content deref_place: {:?} ty: {:?}",
+ deref_place, ty);
+ let seen = prev_seen.cons(erased_drop_place_ty);
+ self.visit_terminator_drop(
+ loc, term, flow_state, &deref_place, ty, span, seen);
+ }
+
_ => {
// We have now refined the type of the value being
// dropped (potentially) to just the type of a
// subfield; so check whether that field's type still
- // "needs drop". If so, we assume that the destructor
- // may access any data it likes (i.e., a Deep Write).
+ // "needs drop".
if erased_drop_place_ty.needs_drop(gcx, self.param_env) {
+ // If so, we assume that the destructor may access
+ // any data it likes (i.e., a Deep Write).
self.access_place(
ContextKind::Drop.new(loc),
(drop_place, span),
LocalMutationIsAllowed::Yes,
flow_state,
);
+ } else {
+ // If there is no destructor, we still include a
+ // *shallow* write. This essentially ensures that
+ // borrows of the memory directly at `drop_place`
+ // cannot continue to be borrowed across the drop.
+ //
+ // If we were to use a Deep Write here, then any
+ // `&mut T` that is reachable from `drop_place`
+ // would get invalidated; fixing that is the
+ // essence of resolving issue #45696.
+ //
+ // * Note: In the compiler today, doing a Deep
+ // Write here would not actually break
+ // anything beyond #45696; for example it does not
+ // break this example:
+ //
+ // ```rust
+ // fn reborrow(x: &mut i32) -> &mut i32 { &mut *x }
+ // ```
+ //
+ // Why? Because we do not schedule/emit
+ // `Drop(x)` in the MIR unless `x` needs drop in
+ // the first place.
+ //
+ // FIXME: Its possible this logic actually should
+ // be attached to the `StorageDead` statement
+ // rather than the `Drop`. See discussion on PR
+ // #52782.
+ self.access_place(
+ ContextKind::Drop.new(loc),
+ (drop_place, span),
+ (Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
+ LocalMutationIsAllowed::Yes,
+ flow_state,
+ );
}
}
}
use borrow_check::borrow_set::BorrowData;
use borrow_check::nll::region_infer::Cause;
use borrow_check::{Context, MirBorrowckCtxt, WriteKind};
-use rustc::mir::Place;
+use rustc::mir::{Location, Place, TerminatorKind};
use rustc_errors::DiagnosticBuilder;
mod find_use;
match find_use::find(mir, regioncx, tcx, region_sub, context.loc) {
Some(Cause::LiveVar(_local, location)) => {
- err.span_label(
- mir.source_info(location).span,
- "borrow later used here".to_string(),
- );
+ if self.is_borrow_location_in_loop(context.loc) {
+ err.span_label(
+ mir.source_info(location).span,
+ "borrow used here in later iteration of loop".to_string(),
+ );
+ } else {
+ err.span_label(
+ mir.source_info(location).span,
+ "borrow later used here".to_string(),
+ );
+ }
}
Some(Cause::DropVar(local, location)) => match &mir.local_decls[local].name {
}
}
}
+
+ /// Check if a borrow location is within a loop.
+ fn is_borrow_location_in_loop(
+ &self,
+ borrow_location: Location,
+ ) -> bool {
+ let mut visited_locations = Vec::new();
+ let mut pending_locations = vec![ borrow_location ];
+ debug!("is_in_loop: borrow_location={:?}", borrow_location);
+
+ while let Some(location) = pending_locations.pop() {
+ debug!("is_in_loop: location={:?} pending_locations={:?} visited_locations={:?}",
+ location, pending_locations, visited_locations);
+ if location == borrow_location && visited_locations.contains(&borrow_location) {
+ // We've managed to return to where we started (and this isn't the start of the
+ // search).
+ debug!("is_in_loop: found!");
+ return true;
+ }
+
+ // Skip locations we've been.
+ if visited_locations.contains(&location) { continue; }
+
+ let block = &self.mir.basic_blocks()[location.block];
+ if location.statement_index == block.statements.len() {
+ // Add start location of the next blocks to pending locations.
+ match block.terminator().kind {
+ TerminatorKind::Goto { target } => {
+ pending_locations.push(target.start_location());
+ },
+ TerminatorKind::SwitchInt { ref targets, .. } => {
+ for target in targets {
+ pending_locations.push(target.start_location());
+ }
+ },
+ TerminatorKind::Drop { target, unwind, .. } |
+ TerminatorKind::DropAndReplace { target, unwind, .. } |
+ TerminatorKind::Assert { target, cleanup: unwind, .. } |
+ TerminatorKind::Yield { resume: target, drop: unwind, .. } |
+ TerminatorKind::FalseUnwind { real_target: target, unwind, .. } => {
+ pending_locations.push(target.start_location());
+ if let Some(unwind) = unwind {
+ pending_locations.push(unwind.start_location());
+ }
+ },
+ TerminatorKind::Call { ref destination, cleanup, .. } => {
+ if let Some((_, destination)) = destination {
+ pending_locations.push(destination.start_location());
+ }
+ if let Some(cleanup) = cleanup {
+ pending_locations.push(cleanup.start_location());
+ }
+ },
+ TerminatorKind::FalseEdges { real_target, ref imaginary_targets, .. } => {
+ pending_locations.push(real_target.start_location());
+ for target in imaginary_targets {
+ pending_locations.push(target.start_location());
+ }
+ },
+ _ => {},
+ }
+ } else {
+ // Add the next statement to pending locations.
+ pending_locations.push(location.successor_within_block());
+ }
+
+ // Keep track of where we have visited.
+ visited_locations.push(location);
+ }
+
+ false
+ }
}
}
(Place::Promoted(p1), Place::Promoted(p2)) => {
if p1.0 == p2.0 {
+ if let ty::TyArray(_, size) = p1.1.sty {
+ if size.unwrap_usize(tcx) == 0 {
+ // Ignore conflicts with promoted [T; 0].
+ debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
+ return Overlap::Disjoint;
+ }
+ }
// the same promoted - base case, equal
debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
Overlap::EqualOrDisjoint
use build::ForGuard::{self, OutsideGuard, RefWithinGuard, ValWithinGuard};
use build::scope::{CachedBlock, DropKind};
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc::ty::{self, Ty};
use rustc::mir::*;
use rustc::hir;
// test the branches of enum
Switch {
adt_def: &'tcx ty::AdtDef,
- variants: BitVector<usize>,
+ variants: BitArray<usize>,
},
// test the branches of enum
use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc::ty::{self, Ty};
use rustc::ty::util::IntTypeExt;
use rustc::mir::*;
span: match_pair.pattern.span,
kind: TestKind::Switch {
adt_def: adt_def.clone(),
- variants: BitVector::new(adt_def.variants.len()),
+ variants: BitArray::new(adt_def.variants.len()),
},
}
}
pub fn add_variants_to_switch<'pat>(&mut self,
test_place: &Place<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
- variants: &mut BitVector<usize>)
+ variants: &mut BitArray<usize>)
-> bool
{
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
use dataflow::BitDenotation;
/// This calculates if any part of a MIR local could have previously been borrowed.
-/// This means that once a local has been borrowed, its bit will always be set
-/// from that point and onwards, even if the borrow ends. You could also think of this
-/// as computing the lifetimes of infinite borrows.
+/// This means that once a local has been borrowed, its bit will be set
+/// from that point and onwards, until we see a StorageDead statement for the local,
+/// at which points there is no memory associated with the local, so it cannot be borrowed.
/// This is used to compute which locals are live during a yield expression for
/// immovable generators.
#[derive(Copy, Clone)]
fn statement_effect(&self,
sets: &mut BlockSets<Local>,
loc: Location) {
+ let stmt = &self.mir[loc.block].statements[loc.statement_index];
+
BorrowedLocalsVisitor {
sets,
- }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
+ }.visit_statement(loc.block, stmt, loc);
+
+ // StorageDead invalidates all borrows and raw pointers to a local
+ match stmt.kind {
+ StatementKind::StorageDead(l) => sets.kill(&l),
+ _ => (),
+ }
}
fn terminator_effect(&self,
InliningMap {
index: FxHashMap(),
targets: Vec::new(),
- inlines: BitVector::new(1024),
+ inlines: BitVector::with_capacity(1024),
}
}
// The `liveness` variable contains the liveness of MIR locals ignoring borrows.
// This is correct for movable generators since borrows cannot live across
// suspension points. However for immovable generators we need to account for
- // borrows, so we conseratively assume that all borrowed locals live forever.
+ // borrows, so we conseratively assume that all borrowed locals are live until
+ // we find a StorageDead statement referencing the locals.
// To do this we just union our `liveness` result with `borrowed_locals`, which
// contains all the locals which has been borrowed before this suspension point.
// If a borrow is converted to a raw reference, we must also assume that it lives
use rustc::hir::CodegenFnAttrFlags;
use rustc::hir::def_id::DefId;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::*;
// Traverse the MIR manually so we can account for the effects of
// inlining on the CFG.
let mut work_list = vec![START_BLOCK];
- let mut visited = BitVector::new(callee_mir.basic_blocks().len());
+ let mut visited = BitArray::new(callee_mir.basic_blocks().len());
while let Some(bb) = work_list.pop() {
if !visited.insert(bb.index()) { continue; }
let blk = &callee_mir.basic_blocks()[bb];
//! The Qualif flags below can be used to also provide better
//! diagnostics as to why a constant rvalue wasn't promoted.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use rustc_data_structures::fx::FxHashSet;
param_env: ty::ParamEnv<'tcx>,
local_qualif: IndexVec<Local, Option<Qualif>>,
qualif: Qualif,
- const_fn_arg_vars: BitVector<Local>,
+ const_fn_arg_vars: BitArray<Local>,
temp_promotion_state: IndexVec<Local, TempState>,
promotion_candidates: Vec<Candidate>
}
param_env,
local_qualif,
qualif: Qualif::empty(),
- const_fn_arg_vars: BitVector::new(mir.local_decls.len()),
+ const_fn_arg_vars: BitArray::new(mir.local_decls.len()),
temp_promotion_state: temps,
promotion_candidates: vec![]
}
let mir = self.mir;
- let mut seen_blocks = BitVector::new(mir.basic_blocks().len());
+ let mut seen_blocks = BitArray::new(mir.basic_blocks().len());
let mut bb = START_BLOCK;
loop {
seen_blocks.insert(bb.index());
use rustc::ty::TyCtxt;
use rustc::mir::*;
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use transform::{MirPass, MirSource};
use util::patch::MirPatch;
&self,
bb: BasicBlock,
mir: &Mir,
- nop_landing_pads: &BitVector<BasicBlock>,
+ nop_landing_pads: &BitArray<BasicBlock>,
) -> bool {
for stmt in &mir[bb].statements {
match stmt.kind {
let mut jumps_folded = 0;
let mut landing_pads_removed = 0;
- let mut nop_landing_pads = BitVector::new(mir.basic_blocks().len());
+ let mut nop_landing_pads = BitArray::new(mir.basic_blocks().len());
// This is a post-order traversal, so that if A post-dominates B
// then A will be visited before B.
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.
-use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::bitvec::BitArray;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::ty::TyCtxt;
use rustc::mir::*;
}
pub fn remove_dead_blocks(mir: &mut Mir) {
- let mut seen = BitVector::new(mir.basic_blocks().len());
+ let mut seen = BitArray::new(mir.basic_blocks().len());
for (bb, _) in traversal::preorder(mir) {
seen.insert(bb.index());
}
tcx: TyCtxt<'a, 'tcx, 'tcx>,
_: MirSource,
mir: &mut Mir<'tcx>) {
- let mut marker = DeclMarker { locals: BitVector::new(mir.local_decls.len()) };
+ let mut marker = DeclMarker { locals: BitArray::new(mir.local_decls.len()) };
marker.visit_mir(mir);
// Return pointer and arguments are always live
marker.locals.insert(RETURN_PLACE);
/// Construct the mapping while swapping out unused stuff out from the `vec`.
fn make_local_map<'tcx, V>(
vec: &mut IndexVec<Local, V>,
- mask: BitVector<Local>,
+ mask: BitArray<Local>,
) -> IndexVec<Local, Option<Local>> {
let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*vec);
let mut used = Local::new(0);
}
struct DeclMarker {
- pub locals: BitVector<Local>,
+ pub locals: BitArray<Local>,
}
impl<'tcx> Visitor<'tcx> for DeclMarker {
pub fn get_macro(&mut self, def: Def) -> Lrc<SyntaxExtension> {
let def_id = match def {
Def::Macro(def_id, ..) => def_id,
- _ => panic!("Expected Def::Macro(..)"),
+ Def::NonMacroAttr => return Lrc::new(SyntaxExtension::NonMacroAttr),
+ _ => panic!("Expected Def::Macro(..) or Def::NonMacroAttr"),
};
if let Some(ext) = self.macro_map.get(&def_id) {
return ext.clone();
directive.vis.get() == ty::Visibility::Public ||
directive.span.is_dummy() => {
if let ImportDirectiveSubclass::MacroUse = directive.subclass {
- if resolver.session.features_untracked().use_extern_macros &&
- !directive.span.is_dummy() {
+ if resolver.use_extern_macros && !directive.span.is_dummy() {
resolver.session.buffer_lint(
lint::builtin::MACRO_USE_EXTERN_CRATE,
directive.id,
mod build_reduced_graph;
mod resolve_imports;
+fn is_known_tool(name: Name) -> bool {
+ ["clippy", "rustfmt"].contains(&&*name.as_str())
+}
+
/// A free importable items suggested in case of resolution failure.
struct ImportSuggestion {
path: Path,
err.span_label(typaram_span, "type variable from outer function");
}
},
- Def::Mod(..) | Def::Struct(..) | Def::Union(..) | Def::Enum(..) | Def::Variant(..) |
- Def::Trait(..) | Def::TyAlias(..) | Def::TyForeign(..) | Def::TraitAlias(..) |
- Def::AssociatedTy(..) | Def::PrimTy(..) | Def::Fn(..) | Def::Const(..) |
- Def::Static(..) | Def::StructCtor(..) | Def::VariantCtor(..) | Def::Method(..) |
- Def::AssociatedConst(..) | Def::Local(..) | Def::Upvar(..) | Def::Label(..) |
- Def::Existential(..) | Def::AssociatedExistential(..) |
- Def::Macro(..) | Def::GlobalAsm(..) | Def::Err =>
+ _ => {
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
Def::TyParam")
+ }
}
// Try to retrieve the span of the function signature and generate a new message with
vis: ty::Visibility::Public,
}),
- // The `proc_macro` and `decl_macro` features imply `use_extern_macros`
- use_extern_macros:
- features.use_extern_macros || features.decl_macro,
+ use_extern_macros: features.use_extern_macros(),
crate_loader,
macro_names: FxHashSet(),
path_span: Span)
-> Option<LexicalScopeBinding<'a>> {
let record_used = record_used_id.is_some();
+ assert!(ns == TypeNS || ns == ValueNS);
if ns == TypeNS {
ident.span = if ident.name == keywords::SelfType.name() {
// FIXME(jseyfried) improve `Self` hygiene
return Some(LexicalScopeBinding::Item(binding))
}
_ if poisoned.is_some() => break,
- Err(Undetermined) => return None,
- Err(Determined) => {}
+ Err(Determined) => continue,
+ Err(Undetermined) =>
+ span_bug!(ident.span, "undetermined resolution during main resolution pass"),
}
}
ident.span, Mark::root()).to_name_binding(self.arenas);
return Some(LexicalScopeBinding::Item(binding));
}
+ if ns == TypeNS && is_known_tool(ident.name) {
+ let binding = (Def::ToolMod, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ return Some(LexicalScopeBinding::Item(binding));
+ }
if let Some(prelude) = self.prelude {
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
false, false, path_span) {
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def);
if let Some(next_module) = binding.module() {
module = Some(next_module);
+ } else if def == Def::ToolMod && i + 1 != path.len() {
+ return PathResult::NonModule(PathResolution::new(Def::NonMacroAttr))
} else if def == Def::Err {
return PathResult::NonModule(err_path_resolution());
} else if opt_ns.is_some() && (is_last || maybe_assoc) {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use {AmbiguityError, CrateLint, Resolver, ResolutionError, resolve_error};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
-use Namespace::{self, MacroNS};
+use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error};
+use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding};
+use Namespace::{self, TypeNS, MacroNS};
use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport};
use resolve_imports::ImportResolver;
use rustc::hir::def_id::{DefId, BUILTIN_MACROS_CRATE, CRATE_DEF_INDEX, DefIndex,
use syntax::ext::hygiene::{self, Mark};
use syntax::ext::placeholders::placeholder;
use syntax::ext::tt::macro_rules;
-use syntax::feature_gate::{self, emit_feature_err, GateIssue};
+use syntax::feature_gate::{self, feature_err, emit_feature_err, is_builtin_attr_name, GateIssue};
use syntax::fold::{self, Folder};
use syntax::parse::parser::PathStyle;
use syntax::parse::token::{self, Token};
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(invoc.span());
return Err(Determinacy::Determined);
+ } else if let Def::NonMacroAttr = def {
+ if let InvocationKind::Attr { .. } = invoc.kind {
+ if !self.session.features_untracked().tool_attributes {
+ feature_err(&self.session.parse_sess, "tool_attributes",
+ invoc.span(), GateIssue::Language,
+ "tool attributes are unstable").emit();
+ }
+ return Ok(Some(Lrc::new(SyntaxExtension::NonMacroAttr)));
+ } else {
+ self.report_non_macro_attr(invoc.path_span());
+ return Err(Determinacy::Determined);
+ }
}
let def_id = def.def_id();
if let Def::Macro(_, MacroKind::ProcMacroStub) = def {
self.report_proc_macro_stub(path.span);
return Err(Determinacy::Determined);
+ } else if let Def::NonMacroAttr = def {
+ self.report_non_macro_attr(path.span);
+ return Err(Determinacy::Determined);
}
self.unused_macros.remove(&def.def_id());
Ok(self.get_macro(def))
"can't use a procedural macro from the same crate that defines it");
}
+ fn report_non_macro_attr(&self, span: Span) {
+ self.session.span_err(span,
+ "expected a macro, found non-macro attribute");
+ }
+
fn resolve_invoc_to_def(&mut self, invoc: &mut Invocation, scope: Mark, force: bool)
-> Result<Def, Determinacy> {
let (attr, traits, item) = match invoc.kind {
fn resolve_macro_to_def(&mut self, scope: Mark, path: &ast::Path, kind: MacroKind, force: bool)
-> Result<Def, Determinacy> {
- if kind != MacroKind::Bang && path.segments.len() > 1 {
+ 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.
+ path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
+ self.session.span_err(segment.args.as_ref().unwrap().span(),
+ "generic arguments in macro path");
+ });
+ }
+ if kind != MacroKind::Bang && path.segments.len() > 1 && def != Ok(Def::NonMacroAttr) {
if !self.session.features_untracked().proc_macro_path_invoc {
emit_feature_err(
&self.session.parse_sess,
);
}
}
-
- 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.
- path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
- self.session.span_err(segment.args.as_ref().unwrap().span(),
- "generic arguments in macro path");
- });
- }
def
}
result
}
- // Resolve the initial segment of a non-global macro path (e.g. `foo` in `foo::bar!();`)
+ // Resolve the initial segment of a non-global macro path
+ // (e.g. `foo` in `foo::bar!(); or `foo!();`).
+ // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
+ // expansion and import resolution (perhaps they can be merged in the future).
pub fn resolve_lexical_macro_path_segment(&mut self,
mut ident: Ident,
ns: Namespace,
record_used: bool,
path_span: Span)
-> Result<MacroBinding<'a>, Determinacy> {
+ // General principles:
+ // 1. Not controlled (user-defined) names should have higher priority than controlled names
+ // built into the language or standard library. This way we can add new names into the
+ // language or standard library without breaking user code.
+ // 2. "Closed set" below means new names can appear after the current resolution attempt.
+ // Places to search (in order of decreasing priority):
+ // (Type NS)
+ // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
+ // (open set, not controlled).
+ // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled).
+ // 3. Extern prelude (closed, not controlled).
+ // 4. Tool modules (closed, controlled right now, but not in the future).
+ // 5. Standard library prelude (de-facto closed, controlled).
+ // 6. Language prelude (closed, controlled).
+ // (Macro NS)
+ // 1. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+ // (open, not controlled).
+ // 2. Macro prelude (language, standard library, user-defined legacy plugins lumped into
+ // one set) (open, the open part is from macro expansions, not controlled).
+ // 2a. User-defined prelude from macro-use
+ // (open, the open part is from macro expansions, not controlled).
+ // 2b. Standard library prelude, currently just a macro-use (closed, controlled)
+ // 2c. Language prelude, perhaps including builtin attributes
+ // (closed, controlled, except for legacy plugins).
+ // 3. Builtin attributes (closed, controlled).
+
+ assert!(ns == TypeNS || ns == MacroNS);
ident = ident.modern();
- let mut module = Some(self.current_module);
- let mut potential_illegal_shadower = Err(Determinacy::Determined);
- let determinacy =
- if record_used { Determinacy::Determined } else { Determinacy::Undetermined };
+
+ // Names from inner scope that can't shadow names from outer scopes, e.g.
+ // mod m { ... }
+ // {
+ // use prefix::*; // if this imports another `m`, then it can't shadow the outer `m`
+ // // and we have and ambiguity error
+ // m::mac!();
+ // }
+ // This includes names from globs and from macro expansions.
+ let mut potentially_ambiguous_result: Option<MacroBinding> = None;
+
+ enum WhereToResolve<'a> {
+ Module(Module<'a>),
+ MacroPrelude,
+ BuiltinAttrs,
+ ExternPrelude,
+ ToolPrelude,
+ StdLibPrelude,
+ PrimitiveTypes,
+ }
+
+ // Go through all the scopes and try to resolve the name.
+ let mut where_to_resolve = WhereToResolve::Module(self.current_module);
+ let mut use_prelude = !self.current_module.no_implicit_prelude;
loop {
- let orig_current_module = self.current_module;
- let result = if let Some(module) = module {
- self.current_module = module; // Lexical resolutions can never be a privacy error.
- // Since expanded macros may not shadow the lexical scope and
- // globs may not shadow global macros (both enforced below),
- // we resolve with restricted shadowing (indicated by the penultimate argument).
- self.resolve_ident_in_module_unadjusted(
- module, ident, ns, true, record_used, path_span,
- ).map(MacroBinding::Modern)
- } else {
- self.macro_prelude.get(&ident.name).cloned().ok_or(determinacy)
- .map(MacroBinding::Global)
+ let result = match where_to_resolve {
+ WhereToResolve::Module(module) => {
+ let orig_current_module = mem::replace(&mut self.current_module, module);
+ let binding = self.resolve_ident_in_module_unadjusted(
+ module, ident, ns, true, record_used, path_span,
+ );
+ self.current_module = orig_current_module;
+ binding.map(MacroBinding::Modern)
+ }
+ WhereToResolve::MacroPrelude => {
+ match self.macro_prelude.get(&ident.name).cloned() {
+ Some(binding) => Ok(MacroBinding::Global(binding)),
+ None => Err(Determinacy::Determined),
+ }
+ }
+ WhereToResolve::BuiltinAttrs => {
+ if is_builtin_attr_name(ident.name) {
+ let binding = (Def::NonMacroAttr, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
+ WhereToResolve::ExternPrelude => {
+ if use_prelude && self.extern_prelude.contains(&ident.name) {
+ if !self.session.features_untracked().extern_prelude &&
+ !self.ignore_extern_prelude_feature {
+ feature_err(&self.session.parse_sess, "extern_prelude",
+ ident.span, GateIssue::Language,
+ "access to extern crates through prelude is experimental")
+ .emit();
+ }
+
+ let crate_id =
+ self.crate_loader.process_path_extern(ident.name, ident.span);
+ let crate_root =
+ self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
+ self.populate_module_if_necessary(crate_root);
+
+ let binding = (crate_root, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
+ WhereToResolve::ToolPrelude => {
+ if use_prelude && is_known_tool(ident.name) {
+ let binding = (Def::ToolMod, ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
+ WhereToResolve::StdLibPrelude => {
+ let mut result = Err(Determinacy::Determined);
+ if use_prelude {
+ if let Some(prelude) = self.prelude {
+ if let Ok(binding) =
+ self.resolve_ident_in_module_unadjusted(prelude, ident, ns,
+ false, false, path_span) {
+ result = Ok(MacroBinding::Global(binding));
+ }
+ }
+ }
+ result
+ }
+ WhereToResolve::PrimitiveTypes => {
+ if let Some(prim_ty) =
+ self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
+ let binding = (Def::PrimTy(prim_ty), ty::Visibility::Public,
+ ident.span, Mark::root()).to_name_binding(self.arenas);
+ Ok(MacroBinding::Global(binding))
+ } else {
+ Err(Determinacy::Determined)
+ }
+ }
};
- self.current_module = orig_current_module;
- match result.map(MacroBinding::binding) {
- Ok(binding) => {
+ macro_rules! continue_search { () => {
+ where_to_resolve = match where_to_resolve {
+ WhereToResolve::Module(module) => {
+ match self.hygienic_lexical_parent(module, &mut ident.span) {
+ Some(parent_module) => WhereToResolve::Module(parent_module),
+ None => {
+ use_prelude = !module.no_implicit_prelude;
+ if ns == MacroNS {
+ WhereToResolve::MacroPrelude
+ } else {
+ WhereToResolve::ExternPrelude
+ }
+ }
+ }
+ }
+ WhereToResolve::MacroPrelude => WhereToResolve::BuiltinAttrs,
+ WhereToResolve::BuiltinAttrs => break, // nowhere else to search
+ WhereToResolve::ExternPrelude => WhereToResolve::ToolPrelude,
+ WhereToResolve::ToolPrelude => WhereToResolve::StdLibPrelude,
+ WhereToResolve::StdLibPrelude => WhereToResolve::PrimitiveTypes,
+ WhereToResolve::PrimitiveTypes => break, // nowhere else to search
+ };
+
+ continue;
+ }}
+
+ match result {
+ Ok(result) => {
if !record_used {
- return result;
+ return Ok(result);
}
- if let Ok(MacroBinding::Modern(shadower)) = potential_illegal_shadower {
- if shadower.def() != binding.def() {
- let name = ident.name;
+
+ let binding = result.binding();
+
+ // Found a solution that is ambiguous with a previously found solution.
+ // Push an ambiguity error for later reporting and
+ // return something for better recovery.
+ if let Some(previous_result) = potentially_ambiguous_result {
+ if binding.def() != previous_result.binding().def() {
self.ambiguity_errors.push(AmbiguityError {
span: path_span,
- name,
- b1: shadower,
+ name: ident.name,
+ b1: previous_result.binding(),
b2: binding,
lexical: true,
});
- return potential_illegal_shadower;
+ return Ok(previous_result);
}
}
+
+ // Found a solution that's not an ambiguity yet, but is "suspicious" and
+ // can participate in ambiguities later on.
+ // Remember it and go search for other solutions in outer scopes.
if binding.is_glob_import() || binding.expansion != Mark::root() {
- potential_illegal_shadower = result;
- } else {
- return result;
+ potentially_ambiguous_result = Some(result);
+
+ continue_search!();
}
+
+ // Found a solution that can't be ambiguous, great success.
+ return Ok(result);
},
+ Err(Determinacy::Determined) => {
+ continue_search!();
+ }
Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined),
- Err(Determinacy::Determined) => {}
}
+ }
- module = match module {
- Some(module) => self.hygienic_lexical_parent(module, &mut ident.span),
- None => return potential_illegal_shadower,
- }
+ // Previously found potentially ambiguous result turned out to not be ambiguous after all.
+ if let Some(previous_result) = potentially_ambiguous_result {
+ return Ok(previous_result);
}
+
+ if record_used { Err(Determinacy::Determined) } else { Err(Determinacy::Undetermined) }
}
pub fn resolve_legacy_scope(&mut self,
expansion: directive.expansion,
});
let _ = self.try_define(directive.parent, target, TypeNS, binding);
+ let import = self.import_map.entry(directive.id).or_default();
+ import[TypeNS] = Some(PathResolution::new(binding.def()));
return None;
}
}
HirDef::Label(..) |
HirDef::Macro(..) |
HirDef::GlobalAsm(..) |
+ HirDef::ToolMod |
+ HirDef::NonMacroAttr |
HirDef::Err => None,
}
}
mod nvptx64;
mod powerpc;
mod powerpc64;
+mod riscv;
mod s390x;
mod sparc;
mod sparc64;
"nvptx" => nvptx::compute_abi_info(self),
"nvptx64" => nvptx64::compute_abi_info(self),
"hexagon" => hexagon::compute_abi_info(self),
+ "riscv32" => riscv::compute_abi_info(self, 32),
+ "riscv64" => riscv::compute_abi_info(self, 64),
a => return Err(format!("unrecognized arch \"{}\" in target specification", a))
}
--- /dev/null
+// Copyright 2012-2013 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.
+
+// Reference: RISC-V ELF psABI specification
+// https://github.com/riscv/riscv-elf-psabi-doc
+
+use abi::call::{ArgType, FnType};
+
+fn classify_ret_ty<Ty>(arg: &mut ArgType<Ty>, xlen: u64) {
+ // "Scalars wider than 2✕XLEN are passed by reference and are replaced in
+ // the argument list with the address."
+ // "Aggregates larger than 2✕XLEN bits are passed by reference and are
+ // replaced in the argument list with the address, as are C++ aggregates
+ // with nontrivial copy constructors, destructors, or vtables."
+ if arg.layout.size.bits() > 2 * xlen {
+ arg.make_indirect();
+ }
+
+ // "When passed in registers, scalars narrower than XLEN bits are widened
+ // according to the sign of their type up to 32 bits, then sign-extended to
+ // XLEN bits."
+ arg.extend_integer_width_to(xlen); // this method only affects integer scalars
+}
+
+fn classify_arg_ty<Ty>(arg: &mut ArgType<Ty>, xlen: u64) {
+ // "Scalars wider than 2✕XLEN are passed by reference and are replaced in
+ // the argument list with the address."
+ // "Aggregates larger than 2✕XLEN bits are passed by reference and are
+ // replaced in the argument list with the address, as are C++ aggregates
+ // with nontrivial copy constructors, destructors, or vtables."
+ if arg.layout.size.bits() > 2 * xlen {
+ arg.make_indirect();
+ }
+
+ // "When passed in registers, scalars narrower than XLEN bits are widened
+ // according to the sign of their type up to 32 bits, then sign-extended to
+ // XLEN bits."
+ arg.extend_integer_width_to(xlen); // this method only affects integer scalars
+}
+
+pub fn compute_abi_info<Ty>(fty: &mut FnType<Ty>, xlen: u64) {
+ if !fty.ret.is_ignore() {
+ classify_ret_ty(&mut fty.ret, xlen);
+ }
+
+ for arg in &mut fty.args {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg_ty(arg, xlen);
+ }
+}
("aarch64-unknown-hermit", aarch64_unknown_hermit),
("x86_64-unknown-hermit", x86_64_unknown_hermit),
+
+ ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
}
/// Everything `rustc` knows about how to compile for a specific target.
--- /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.
+
+use spec::{LinkerFlavor, PanicStrategy, Target, TargetOptions, TargetResult};
+use spec::abi::{Abi};
+
+pub fn target() -> TargetResult {
+ Ok(Target {
+ data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+ llvm_target: "riscv32".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ target_os: "none".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ arch: "riscv32".to_string(),
+ linker_flavor: LinkerFlavor::Ld,
+
+ options: TargetOptions {
+ linker: Some("riscv32-unknown-elf-ld".to_string()),
+ cpu: "generic-rv32".to_string(),
+ max_atomic_width: Some(32),
+ atomic_cas: false, // incomplete +a extension
+ features: "+m,+a".to_string(), // disable +c extension
+ executables: true,
+ panic_strategy: PanicStrategy::Abort,
+ relocation_model: "static".to_string(),
+ abi_blacklist: vec![
+ Abi::Cdecl,
+ Abi::Stdcall,
+ Abi::Fastcall,
+ Abi::Vectorcall,
+ Abi::Thiscall,
+ Abi::Aapcs,
+ Abi::Win64,
+ Abi::SysV64,
+ Abi::PtxKernel,
+ Abi::Msp430Interrupt,
+ Abi::X86Interrupt,
+ ],
+ .. Default::default()
+ },
+ })
+}
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::query::Providers;
use rustc::traits::{ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt};
+use rustc::util::profiling::ProfileCategory;
use session::{CompileIncomplete, config};
use util::common::time;
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Result<(), CompileIncomplete>
{
+ tcx.sess.profiler(|p| p.start_activity(ProfileCategory::TypeChecking));
+
// this ensures that later parts of type checking can assume that items
// have valid types and not error
tcx.sess.track_errors(|| {
check_unused::check_crate(tcx);
check_for_entry_fn(tcx);
+ tcx.sess.profiler(|p| p.end_activity(ProfileCategory::TypeChecking));
+
tcx.sess.compile_status()
}
})?;
match ty.def {
Def::Struct(did) | Def::Union(did) | Def::Enum(did) | Def::TyAlias(did) => {
- let item = cx.tcx.inherent_impls(did).iter()
+ let item = cx.tcx.inherent_impls(did)
+ .iter()
.flat_map(|imp| cx.tcx.associated_items(*imp))
.find(|item| item.ident.name == item_name);
if let Some(item) = item {
};
Ok((ty.def, Some(format!("{}.{}", out, item_name))))
} else {
- let is_enum = match ty.def {
- Def::Enum(_) => true,
- _ => false,
- };
- let elem = if is_enum {
- cx.tcx.adt_def(did).all_fields().find(|item| item.ident.name == item_name)
- } else {
- cx.tcx.adt_def(did)
- .non_enum_variant()
- .fields
- .iter()
- .find(|item| item.ident.name == item_name)
- };
- if let Some(item) = elem {
- Ok((ty.def,
- Some(format!("{}.{}",
- if is_enum { "variant" } else { "structfield" },
- item.ident))))
- } else {
- Err(())
+ match cx.tcx.type_of(did).sty {
+ ty::TyAdt(def, _) => {
+ if let Some(item) = if def.is_enum() {
+ def.all_fields().find(|item| item.ident.name == item_name)
+ } else {
+ def.non_enum_variant()
+ .fields
+ .iter()
+ .find(|item| item.ident.name == item_name)
+ } {
+ Ok((ty.def,
+ Some(format!("{}.{}",
+ if def.is_enum() {
+ "variant"
+ } else {
+ "structfield"
+ },
+ item.ident))))
+ } else {
+ Err(())
+ }
+ }
+ _ => Err(()),
}
}
}
}
pub fn visit_variant_data(&mut self, item: &hir::Item,
- name: ast::Name, sd: &hir::VariantData,
- generics: &hir::Generics) -> Struct {
+ name: ast::Name, sd: &hir::VariantData,
+ generics: &hir::Generics) -> Struct {
debug!("Visiting struct");
let struct_type = struct_type_from_def(&*sd);
Struct {
#[cfg(not(test))]
#[doc(hidden)]
-#[cfg_attr(stage0, lang = "oom")]
-#[cfg_attr(not(stage0), alloc_error_handler)]
+#[alloc_error_handler]
#[unstable(feature = "alloc_internals", issue = "0")]
pub fn rust_oom(layout: Layout) -> ! {
let hook = HOOK.load(Ordering::SeqCst);
// avoid paying to allocate and zero a huge chunk of memory if the reader only
// has 4 bytes while still making large reads if the reader does have a ton
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
-// time is 4,500 times (!) slower than this if the reader has a very small
-// amount of data to return.
+// time is 4,500 times (!) slower than a default reservation size of 32 if the
+// reader has a very small amount of data to return.
//
// Because we're extending the buffer with uninitialized data for trusted
// readers, we need to make sure to truncate that if any of this panics.
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
+ read_to_end_with_reservation(r, buf, 32)
+}
+
+fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R,
+ buf: &mut Vec<u8>,
+ reservation_size: usize) -> Result<usize>
+{
let start_len = buf.len();
let mut g = Guard { len: buf.len(), buf: buf };
let ret;
loop {
if g.len == g.buf.len() {
unsafe {
- g.buf.reserve(32);
+ g.buf.reserve(reservation_size);
let capacity = g.buf.capacity();
g.buf.set_len(capacity);
r.initializer().initialize(&mut g.buf[g.len..]);
unsafe fn initializer(&self) -> Initializer {
self.inner.initializer()
}
+
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
+ let reservation_size = cmp::min(self.limit, 32) as usize;
+
+ read_to_end_with_reservation(self, buf, reservation_size)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! println {
() => (print!("\n"));
($($arg:tt)*) => ({
- #[cfg(not(stage0))] {
- ($crate::io::_print(format_args_nl!($($arg)*)));
- }
- #[cfg(stage0)] {
- print!("{}\n", format_args!($($arg)*))
- }
+ $crate::io::_print(format_args_nl!($($arg)*));
})
}
macro_rules! eprintln {
() => (eprint!("\n"));
($($arg:tt)*) => ({
- #[cfg(all(not(stage0), not(stage1)))] {
- ($crate::io::_eprint(format_args_nl!($($arg)*)));
- }
- #[cfg(any(stage0, stage1))] {
- eprint!("{}\n", format_args!($($arg)*))
- }
+ $crate::io::_eprint(format_args_nl!($($arg)*));
})
}
pub const FD_SETSIZE: usize = 64;
+pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
+
#[repr(C)]
#[cfg(not(target_pointer_width = "64"))]
pub struct WSADATA {
let stack_size = (stack + 0xfffe) & (!0xfffe);
let ret = c::CreateThread(ptr::null_mut(), stack_size,
thread_start, &*p as *const _ as *mut _,
- 0, ptr::null_mut());
+ c::STACK_SIZE_PARAM_IS_A_RESERVATION,
+ ptr::null_mut());
return if ret as usize == 0 {
Err(io::Error::last_os_error())
use print::pprust;
use ptr::P;
use rustc_data_structures::indexed_vec;
+use rustc_data_structures::indexed_vec::Idx;
use symbol::{Symbol, keywords};
use tokenstream::{ThinTokenStream, TokenStream};
Inner,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, PartialOrd, Ord, Copy)]
pub struct AttrId(pub usize);
+impl Idx for AttrId {
+ fn new(idx: usize) -> Self {
+ AttrId(idx)
+ }
+ fn index(self) -> usize {
+ self.0
+ }
+}
+
/// Meta-data associated with an item
/// Doc-comments are promoted to attributes that have is_sugared_doc = true
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub fn mark_used(attr: &Attribute) {
debug!("Marking {:?} as used.", attr);
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let mut slot = globals.used_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- if slot.len() <= idx {
- slot.resize(idx + 1, 0);
- }
- slot[idx] |= 1 << shift;
+ globals.used_attrs.lock().insert(attr.id);
});
}
pub fn is_used(attr: &Attribute) -> bool {
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let slot = globals.used_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- slot.get(idx).map(|bits| bits & (1 << shift) != 0)
- .unwrap_or(false)
+ globals.used_attrs.lock().contains(attr.id)
})
}
pub fn mark_known(attr: &Attribute) {
debug!("Marking {:?} as known.", attr);
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let mut slot = globals.known_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- if slot.len() <= idx {
- slot.resize(idx + 1, 0);
- }
- slot[idx] |= 1 << shift;
+ globals.known_attrs.lock().insert(attr.id);
});
}
pub fn is_known(attr: &Attribute) -> bool {
- let AttrId(id) = attr.id;
GLOBALS.with(|globals| {
- let slot = globals.known_attrs.lock();
- let idx = (id / 64) as usize;
- let shift = id % 64;
- slot.get(idx).map(|bits| bits & (1 << shift) != 0)
- .unwrap_or(false)
+ globals.known_attrs.lock().contains(attr.id)
})
}
-const RUST_KNOWN_TOOL: &[&str] = &["clippy", "rustfmt"];
-const RUST_KNOWN_LINT_TOOL: &[&str] = &["clippy"];
-
-pub fn is_known_tool(attr: &Attribute) -> bool {
- let tool_name =
- attr.path.segments.iter().next().expect("empty path in attribute").ident.name;
- RUST_KNOWN_TOOL.contains(&tool_name.as_str().as_ref())
-}
-
pub fn is_known_lint_tool(m_item: Ident) -> bool {
- RUST_KNOWN_LINT_TOOL.contains(&m_item.as_str().as_ref())
+ ["clippy"].contains(&m_item.as_str().as_ref())
}
impl NestedMetaItem {
pub fn is_value_str(&self) -> bool {
self.value_str().is_some()
}
-
- pub fn is_scoped(&self) -> bool {
- self.path.segments.len() > 1
- }
}
impl MetaItem {
/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
+ /// A trivial "extension" that does nothing, only keeps the attribute and marks it as known.
+ NonMacroAttr,
+
/// A syntax extension that is attached to an item and creates new items
/// based upon it.
///
SyntaxExtension::IdentTT(..) |
SyntaxExtension::ProcMacro { .. } =>
MacroKind::Bang,
+ SyntaxExtension::NonMacroAttr |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
SyntaxExtension::AttrProcMacro(..) =>
SyntaxExtension::AttrProcMacro(.., edition) |
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
// Unstable legacy stuff
+ SyntaxExtension::NonMacroAttr |
SyntaxExtension::IdentTT(..) |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
use config::{is_test_or_bench, StripUnconfigured};
use errors::{Applicability, FatalError};
use ext::base::*;
+use ext::build::AstBuilder;
use ext::derive::{add_derived_markers, collect_derives};
use ext::hygiene::{self, Mark, SyntaxContext};
use ext::placeholders::{placeholder, PlaceholderExpander};
use std::collections::HashMap;
use std::fs::File;
use std::io::Read;
-use std::mem;
+use std::{iter, mem};
use std::rc::Rc;
use std::path::PathBuf;
}
}
+ pub fn path_span(&self) -> Span {
+ match self.kind {
+ InvocationKind::Bang { ref mac, .. } => mac.node.path.span,
+ InvocationKind::Attr { attr: Some(ref attr), .. } => attr.path.span,
+ InvocationKind::Attr { attr: None, .. } => DUMMY_SP,
+ InvocationKind::Derive { ref path, .. } => path.span,
+ }
+ }
+
pub fn attr_id(&self) -> Option<ast::AttrId> {
match self.kind {
InvocationKind::Attr { attr: Some(ref attr), .. } => Some(attr.id),
cx: self.cx,
invocations: Vec::new(),
monotonic: self.monotonic,
+ tests_nameable: true,
};
(fragment.fold_with(&mut collector), collector.invocations)
};
});
match *ext {
+ NonMacroAttr => {
+ attr::mark_known(&attr);
+ let item = item.map_attrs(|mut attrs| { attrs.push(attr); attrs });
+ Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item)))
+ }
MultiModifier(ref mac) => {
let meta = attr.parse_meta(self.cx.parse_sess)
.map_err(|mut e| { e.emit(); }).ok()?;
}
}
- MultiDecorator(..) | MultiModifier(..) | AttrProcMacro(..) => {
+ MultiDecorator(..) | MultiModifier(..) |
+ AttrProcMacro(..) | SyntaxExtension::NonMacroAttr => {
self.cx.span_err(path.span,
&format!("`{}` can only be used in attributes", path));
self.cx.trace_macros_diag();
cfg: StripUnconfigured<'a>,
invocations: Vec<Invocation>,
monotonic: bool,
+
+ /// Test functions need to be nameable. Tests inside functions or in other
+ /// unnameable locations need to be ignored. `tests_nameable` tracks whether
+ /// any test functions found in the current context would be nameable.
+ tests_nameable: bool,
}
impl<'a, 'b> InvocationCollector<'a, 'b> {
placeholder(fragment_kind, NodeId::placeholder_from_mark(mark))
}
+ /// Folds the item allowing tests to be expanded because they are still nameable.
+ /// This should probably only be called with module items
+ fn fold_nameable(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+ fold::noop_fold_item(item, self)
+ }
+
+ /// Folds the item but doesn't allow tests to occur within it
+ fn fold_unnameable(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
+ let was_nameable = mem::replace(&mut self.tests_nameable, false);
+ let items = fold::noop_fold_item(item, self);
+ self.tests_nameable = was_nameable;
+ items
+ }
+
fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> AstFragment {
self.collect(kind, InvocationKind::Bang { mac: mac, ident: None, span: span })
}
}
ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
if item.ident == keywords::Invalid.ident() {
- return noop_fold_item(item, self);
+ return self.fold_nameable(item);
}
let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
let orig_module =
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
- let result = noop_fold_item(item, self);
+ let result = self.fold_nameable(item);
self.cx.current_expansion.module = orig_module;
self.cx.current_expansion.directory_ownership = orig_directory_ownership;
result
}
// Ensure that test functions are accessible from the test harness.
+ // #[test] fn foo() {}
+ // becomes:
+ // #[test] pub fn foo_gensym(){}
+ // #[allow(unused)]
+ // use foo_gensym as foo;
ast::ItemKind::Fn(..) if self.cx.ecfg.should_test => {
- if item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
+ if self.tests_nameable && item.attrs.iter().any(|attr| is_test_or_bench(attr)) {
+ let orig_ident = item.ident;
+ let orig_vis = item.vis.clone();
+
+ // Publicize the item under gensymed name to avoid pollution
item = item.map(|mut item| {
item.vis = respan(item.vis.span, ast::VisibilityKind::Public);
+ item.ident = item.ident.gensym();
item
});
+
+ // Use the gensymed name under the item's original visibility
+ let mut use_item = self.cx.item_use_simple_(
+ item.ident.span,
+ orig_vis,
+ Some(orig_ident),
+ self.cx.path(item.ident.span,
+ vec![keywords::SelfValue.ident(), item.ident]));
+
+ // #[allow(unused)] because the test function probably isn't being referenced
+ use_item = use_item.map(|mut ui| {
+ ui.attrs.push(
+ self.cx.attribute(DUMMY_SP, attr::mk_list_item(DUMMY_SP,
+ Ident::from_str("allow"), vec![
+ attr::mk_nested_word_item(Ident::from_str("unused"))
+ ]
+ ))
+ );
+
+ ui
+ });
+
+ SmallVector::many(
+ self.fold_unnameable(item).into_iter()
+ .chain(self.fold_unnameable(use_item)))
+ } else {
+ self.fold_unnameable(item)
}
- noop_fold_item(item, self)
}
- _ => noop_fold_item(item, self),
+ _ => self.fold_unnameable(item),
}
}
fn enable_allow_internal_unstable = allow_internal_unstable,
fn enable_custom_derive = custom_derive,
fn enable_format_args_nl = format_args_nl,
- fn use_extern_macros_enabled = use_extern_macros,
fn macros_in_extern_enabled = macros_in_extern,
fn proc_macro_mod = proc_macro_mod,
fn proc_macro_gen = proc_macro_gen,
fn proc_macro_expr = proc_macro_expr,
fn proc_macro_non_items = proc_macro_non_items,
}
+
+ pub fn use_extern_macros_enabled(&self) -> bool {
+ self.features.map_or(false, |features| features.use_extern_macros())
+ }
}
// A Marker adds the given mark to the syntax context.
{
$(f(stringify!($feature), self.$feature);)+
}
+
+ pub fn use_extern_macros(&self) -> bool {
+ // The `decl_macro` and `tool_attributes` features imply `use_extern_macros`.
+ self.use_extern_macros || self.decl_macro || self.tool_attributes
+ }
}
};
BUILTIN_ATTRIBUTES.iter().filter(|a| a.2.is_deprecated()).collect()
}
+pub fn is_builtin_attr_name(name: ast::Name) -> bool {
+ BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| name == builtin_name)
+}
+
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, _, _)| attr.check_name(builtin_name)) ||
attr.name().as_str().starts_with("rustc_")
// before the plugin attributes are registered
// so we skip this then
if !is_macro {
- if attr.is_scoped() {
- gate_feature!(self, tool_attributes, attr.span,
- &format!("scoped attribute `{}` is experimental", attr.path));
- if attr::is_known_tool(attr) {
- attr::mark_used(attr);
- } else {
- span_err!(
- self.parse_sess.span_diagnostic,
- attr.span,
- E0694,
- "an unknown tool name found in scoped attribute: `{}`.",
- attr.path
- );
- }
- } else {
- gate_feature!(self, custom_attribute, attr.span,
- &format!("The attribute `{}` is currently \
- unknown to the compiler and \
- may have meaning \
- added to it in the future",
- attr.path));
- }
+ let msg = format!("The attribute `{}` is currently unknown to the compiler and \
+ may have meaning added to it in the future", attr.path);
+ gate_feature!(self, custom_attribute, attr.span, &msg);
}
}
}
}
}
- if self.context.features.use_extern_macros && attr::is_known(attr) {
+ if self.context.features.use_extern_macros() && attr::is_known(attr) {
return
}
// the branching can be eliminated by modifying `set!()` to set these spans
// only for the features that need to be checked for mutual exclusion.
fn collect(&mut self, features: &Features, span: Span) {
- if features.use_extern_macros {
+ if features.use_extern_macros() {
// If self.use_extern_macros is None, set to Some(span)
self.use_extern_macros = self.use_extern_macros.or(Some(span));
}
extern crate serialize as rustc_serialize; // used by deriving
use rustc_data_structures::sync::Lock;
+use rustc_data_structures::bitvec::BitVector;
+use ast::AttrId;
// A variant of 'try!' that panics on an Err. This is used as a crutch on the
// way towards a non-panic!-prone parser. It should be used for fatal parsing
}
pub struct Globals {
- used_attrs: Lock<Vec<u64>>,
- known_attrs: Lock<Vec<u64>>,
+ used_attrs: Lock<BitVector<AttrId>>,
+ known_attrs: Lock<BitVector<AttrId>>,
syntax_pos_globals: syntax_pos::Globals,
}
impl Globals {
fn new() -> Globals {
Globals {
- used_attrs: Lock::new(Vec::new()),
- known_attrs: Lock::new(Vec::new()),
+ // We have no idea how many attributes their will be, so just
+ // initiate the vectors with 0 bits. We'll grow them as necessary.
+ used_attrs: Lock::new(BitVector::new()),
+ known_attrs: Lock::new(BitVector::new()),
syntax_pos_globals: syntax_pos::Globals::new(),
}
}
!ident_token.is_reserved_ident() ||
ident_token.is_path_segment_keyword() ||
[
+ keywords::Async.name(),
keywords::Do.name(),
keywords::Box.name(),
keywords::Break.name(),
/// The kind of compiler desugaring.
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
pub enum CompilerDesugaringKind {
- DotFill,
QuestionMark,
Catch,
/// Desugaring of an `impl Trait` in return type position
pub fn name(self) -> Symbol {
Symbol::intern(match self {
CompilerDesugaringKind::Async => "async",
- CompilerDesugaringKind::DotFill => "...",
CompilerDesugaringKind::QuestionMark => "?",
CompilerDesugaringKind::Catch => "do catch",
CompilerDesugaringKind::ExistentialReturnType => "existential type",
#define SUBTARGET_MSP430
#endif
+#ifdef LLVM_COMPONENT_RISCV
+#define SUBTARGET_RISCV SUBTARGET(RISCV)
+#else
+#define SUBTARGET_RISCV
+#endif
+
#ifdef LLVM_COMPONENT_SPARC
#define SUBTARGET_SPARC SUBTARGET(Sparc)
#else
SUBTARGET_SYSTEMZ \
SUBTARGET_MSP430 \
SUBTARGET_SPARC \
- SUBTARGET_HEXAGON
+ SUBTARGET_HEXAGON \
+ SUBTARGET_RISCV \
#define SUBTARGET(x) \
namespace llvm { \
OptimizationRemarkOther,
OptimizationFailure,
PGOProfile,
+ Linker,
};
static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) {
return LLVMRustDiagnosticKind::OptimizationRemarkAnalysisAliasing;
case DK_PGOProfile:
return LLVMRustDiagnosticKind::PGOProfile;
+ case DK_Linker:
+ return LLVMRustDiagnosticKind::Linker;
default:
return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark)
? LLVMRustDiagnosticKind::OptimizationRemarkOther
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
# `0.x.0` for Cargo where they were released on `date`.
-date: 2018-07-27
+date: 2018-08-01
rustc: beta
cargo: beta
--- /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-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @vec_clear
+#[no_mangle]
+pub fn vec_clear(x: &mut Vec<u32>) {
+ // CHECK-NOT: load
+ // CHECK-NOT: icmp
+ x.clear()
+}
--- /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 = "lib"]
+#![unstable(feature = "issue_52489_unstable", issue = "0")]
+#![feature(staged_api)]
--- /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 = "rlib"]
+
+#[no_mangle]
+pub extern fn foo() {}
--- /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 = "rlib"]
+
+#[no_mangle]
+pub extern fn foo() {}
+++ /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.
-
-fn main() {
- #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
- let x =
- 3;
-}
--- /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.
+
+// edition:2018
+// aux-build:issue-52489.rs
+
+use issue_52489;
+//~^ ERROR use of unstable library feature 'issue_52489_unstable'
+
+fn main() {}
--- /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:lto-duplicate-symbols1.rs
+// aux-build:lto-duplicate-symbols2.rs
+// error-pattern:Linking globals named 'foo': symbol multiply defined!
+// compile-flags: -C lto
+// no-prefer-dynamic
+
+extern crate lto_duplicate_symbols1;
+extern crate lto_duplicate_symbols2;
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(tool_attributes)]
+#![feature(use_extern_macros, proc_macro_path_invoc)]
-#![foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
-
-#[foo::bar] //~ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
+#[foo::bar] //~ ERROR failed to resolve. Use of undeclared type or module `foo`
fn main() {}
+++ /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.
-
-// Make sure that 'custom_attributes' feature does not allow scoped attributes.
-
-#![feature(custom_attributes)]
-
-#[foo::bar]
-//~^ ERROR scoped attribute `foo::bar` is experimental (see issue #44690) [E0658]
-//~^^ ERROR an unknown tool name found in scoped attribute: `foo::bar`. [E0694]
-fn main() {}
// aux-build:issue-42708.rs
// ignore-stage1
-#![feature(decl_macro, use_extern_macros, proc_macro_path_invoc)]
+#![feature(decl_macro, proc_macro_path_invoc)]
#![allow(unused)]
extern crate issue_42708;
// aux-build:issue-50061.rs
// ignore-stage1
-#![feature(use_extern_macros, proc_macro_path_invoc, decl_macro)]
+#![feature(proc_macro_path_invoc, decl_macro)]
extern crate issue_50061;
--- /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.
+
+#![feature(generators)]
+
+fn main() {
+ static || {
+ loop {
+ // Test that `opt` is not live across the yield, even when borrowed in a loop
+ // See https://github.com/rust-lang/rust/issues/52792
+ let opt = {
+ yield;
+ true
+ };
+ &opt;
+ }
+ };
+}
--- /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.
+
+// This test checks for namespace pollution by private tests.
+// Tests used to marked as public causing name conflicts with normal
+// functions only in test builds.
+
+// compile-flags: --test
+
+mod a {
+ pub fn foo() -> bool {
+ true
+ }
+}
+
+mod b {
+ #[test]
+ fn foo() {
+ local_name(); // ensure the local name still works
+ }
+
+ #[test]
+ fn local_name() {}
+}
+
+use a::*;
+use b::*;
+
+pub fn conflict() {
+ let _: bool = foo();
+}
--- /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.
+
+#![deny(intra_doc_link_resolution_failure)]
+
+pub type TypeAlias = usize;
+
+/// [broken cross-reference](TypeAlias::hoge) //~ ERROR
+pub fn some_public_item() {}
--- /dev/null
+error: `[TypeAlias::hoge]` cannot be resolved, ignoring it...
+ --> $DIR/intra-doc-alias-ice.rs:15:30
+ |
+15 | /// [broken cross-reference](TypeAlias::hoge) //~ ERROR
+ | ^^^^^^^^^^^^^^^ cannot be resolved, ignoring
+ |
+note: lint level defined here
+ --> $DIR/intra-doc-alias-ice.rs:11:9
+ |
+11 | #![deny(intra_doc_link_resolution_failure)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = help: to escape `[` and `]` characters, just add '/' before them like `/[` or `/]`
+
// aux-build:parent-source-spans.rs
// ignore-stage1
-#![feature(use_extern_macros, decl_macro, proc_macro_non_items)]
+#![feature(decl_macro, proc_macro_non_items)]
extern crate parent_source_spans;
error[E0384]: cannot assign twice to immutable variable `x`
- --> $DIR/asm-out-assign-imm.rs:33:9
+ --> $DIR/asm-out-assign-imm.rs:34:9
|
LL | let x: isize;
| - consider changing this to `mut x`
// ignore-sparc
// ignore-sparc64
// ignore-mips
+// ignore-mips64
#![feature(asm)]
error[E0384]: cannot assign twice to immutable variable `x`
- --> $DIR/asm-out-assign-imm.rs:33:9
+ --> $DIR/asm-out-assign-imm.rs:34:9
|
LL | x = 1;
| ----- first assignment to `x`
--- /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
+// edition:2018
+
+#![feature(async_await, await_macro)]
+
+macro_rules! match_expr {
+ ($x:expr) => {}
+}
+
+fn main() {
+ match_expr!(async {});
+ match_expr!(async || {});
+}
macro_rules! mac {
($ident:ident) => { let $ident = 42; }
}
+
+#[macro_export]
+macro_rules! inline {
+ () => ()
+}
--- /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.
+
+// This is a regression test for #52967, where we discovered that in
+// the initial deployment of NLL for the 2018 edition, I forgot to
+// turn on two-phase-borrows in addition to `-Z borrowck=migrate`.
+
+// revisions: ast zflags edition
+//[zflags]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+//[edition]compile-flags: --edition 2018
+
+// run-pass
+
+fn the_bug() {
+ let mut stuff = ("left", "right");
+ match stuff {
+ (ref mut left, _) if *left == "left" => { *left = "new left"; }
+ _ => {}
+ }
+ assert_eq!(stuff, ("new left", "right"));
+}
+
+fn main() {
+ the_bug();
+}
| ^^^^^^^^^^^^^^^ second mutable borrow occurs here
LL | inner_second.use_mut();
LL | inner_first.use_mut();
- | ----------- borrow later used here
+ | ----------- borrow used here in later iteration of loop
error: aborting due to 2 previous errors
-error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:29:5
|
LL | returns_isize!(rust_get_test_int);
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
-error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:31:5
|
LL | takes_u32_returns_u32!(rust_dbg_extern_identity_u32);
|
= help: add #![feature(macros_in_extern)] to the crate attributes to enable
-error[E0658]: macro invocations in `extern {}` blocks are experimental. (see issue #49476)
+error[E0658]: macro and proc-macro invocations in `extern {}` blocks are experimental. (see issue #49476)
--> $DIR/feature-gate-macros_in_extern.rs:33:5
|
LL | emits_nothing!();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(use_extern_macros)]
+
fn main() {
- #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
+ #[rustfmt::skip] //~ ERROR tool attributes are unstable
let x = 3
;
}
-error[E0658]: scoped attribute `rustfmt::skip` is experimental (see issue #44690)
- --> $DIR/feature-gate-tool_attributes.rs:12:5
+error[E0658]: tool attributes are unstable (see issue #44690)
+ --> $DIR/feature-gate-tool_attributes.rs:14:5
|
-LL | #[rustfmt::skip] //~ ERROR scoped attribute `rustfmt::skip` is experimental
+LL | #[rustfmt::skip] //~ ERROR tool attributes are unstable
| ^^^^^^^^^^^^^^^^
|
= help: add #![feature(tool_attributes)] to the crate attributes to enable
| |
| `*cell` dropped here while still borrowed
| borrow later used here, when `gen` is dropped
- |
- = note: values in a scope are dropped in the opposite order they are defined
error[E0597]: `ref_` does not live long enough
--> $DIR/dropck.rs:22:11
// except according to those terms.
fn main() {
- print!(test!());
+ print!(testo!());
//~^ ERROR: format argument must be a string literal
}
error: format argument must be a string literal
--> $DIR/issue-11692-1.rs:12:12
|
-LL | print!(test!());
- | ^^^^^^^
+LL | print!(testo!());
+ | ^^^^^^^^
help: you might be missing a string literal to format with
|
-LL | print!("{}", test!());
+LL | print!("{}", testo!());
| ^^^^^
error: aborting due to previous error
fn main() {
concat!(test!());
- //~^ ERROR cannot find macro `test!` in this scope
+ //~^ ERROR expected a macro, found non-macro attribute
}
-error: cannot find macro `test!` in this scope
+error: expected a macro, found non-macro attribute
--> $DIR/issue-11692-2.rs:12:13
|
LL | concat!(test!());
--- /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.
+
+// rust-lang/rust#45696: This test is checking that we can return
+// mutable borrows owned by boxes even when the boxes are dropped.
+//
+// We will explicitly test AST-borrowck, NLL, and migration modes;
+// thus we will also skip the automated compare-mode=nll.
+
+// revisions: ast nll migrate
+// ignore-compare-mode-nll
+
+#![cfg_attr(nll, feature(nll))]
+//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+// run-pass
+
+// This function shows quite directly what is going on: We have a
+// reborrow of contents within the box.
+fn return_borrow_from_dropped_box_1(x: Box<&mut u32>) -> &mut u32 { &mut **x }
+
+// This function is the way you'll probably see this in practice (the
+// reborrow is now implicit).
+fn return_borrow_from_dropped_box_2(x: Box<&mut u32>) -> &mut u32 { *x }
+
+// For the remaining tests we just add some fields or other
+// indirection to ensure that the compiler isn't just special-casing
+// the above `Box<&mut T>` as the only type that would work.
+
+// Here we add a tuple of indirection between the box and the
+// reference.
+type BoxedTup<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>;
+
+fn return_borrow_of_field_from_dropped_box_1<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ &mut *x.0
+}
+
+fn return_borrow_of_field_from_dropped_box_2<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ x.0
+}
+
+fn return_borrow_from_dropped_tupled_box_1<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ &mut *(x.0).0
+}
+
+fn return_borrow_from_dropped_tupled_box_2<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ (x.0).0
+}
+
+fn basic_tests() {
+ let mut x = 2;
+ let mut y = 3;
+ let mut z = 4;
+ *return_borrow_from_dropped_box_1(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (12, 3, 4));
+ *return_borrow_from_dropped_box_2(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (22, 3, 4));
+ *return_borrow_of_field_from_dropped_box_1(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (32, 3, 4));
+ *return_borrow_of_field_from_dropped_box_2(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (42, 3, 4));
+ *return_borrow_from_dropped_tupled_box_1((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (52, 3, 4));
+ *return_borrow_from_dropped_tupled_box_2((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (62, 3, 4));
+}
+
+// These scribbling tests have been transcribed from
+// issue-45696-scribble-on-boxed-borrow.rs
+//
+// In the context of that file, these tests are meant to show cases
+// that should be *accepted* by the compiler, so here we are actually
+// checking that the code we get when they are compiled matches our
+// expectations.
+
+struct Scribble<'a>(&'a mut u32);
+
+impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
+
+// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has*
+// to strictly outlive `'a`
+fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
+ &mut *s.0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
+ &mut *(*s).0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
+ &mut *(**s).0
+}
+
+fn scribbling_tests() {
+ let mut x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *borrowed_scribble(&mut long_lived) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+}
+
+fn main() {
+ basic_tests();
+ scribbling_tests();
+}
--- /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.
+
+// rust-lang/rust#45696: This test checks the compiler won't infinite
+// loop when you declare a variable of type `struct A(Box<A>, ...);`
+// (which is impossible to construct but *is* possible to declare; see
+// also issues #4287, #44933, and #52852).
+//
+// We will explicitly test AST-borrowck, NLL, and migration modes;
+// thus we will also skip the automated compare-mode=nll.
+
+// revisions: ast nll migrate
+// ignore-compare-mode-nll
+
+#![cfg_attr(nll, feature(nll))]
+//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+// run-pass
+
+// This test has structs and functions that are by definiton unusable
+// all over the place, so just go ahead and allow dead_code
+#![allow(dead_code)]
+
+// direct regular recursion with indirect ownership via box
+struct C { field: Box<C> }
+
+// direct non-regular recursion with indirect ownership via box
+struct D { field: Box<(D, D)> }
+
+// indirect regular recursion with indirect ownership via box.
+struct E { field: F }
+struct F { field: Box<E> }
+
+// indirect non-regular recursion with indirect ownership via box.
+struct G { field: (H, H) }
+struct H { field: Box<G> }
+
+// These enums are cases that are not currently hit by the
+// `visit_terminator_drop` recursion down a type's structural
+// definition.
+//
+// But it seems prudent to include them in this test as variants on
+// the above, in that they are similarly non-constructable data types
+// with destructors that would diverge.
+enum I { One(Box<I>) }
+enum J { One(Box<J>), Two(Box<J>) }
+
+fn impossible_to_call_c(_c: C) { }
+fn impossible_to_call_d(_d: D) { }
+fn impossible_to_call_e(_e: E) { }
+fn impossible_to_call_f(_f: F) { }
+fn impossible_to_call_g(_g: G) { }
+fn impossible_to_call_h(_h: H) { }
+fn impossible_to_call_i(_i: I) { }
+fn impossible_to_call_j(_j: J) { }
+
+fn main() {
+
+}
--- /dev/null
+error: compilation successful
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1
+ |
+LL | / fn main() { //[ast]~ ERROR compilation successful
+LL | | //[migrate]~^ ERROR compilation successful
+LL | | let mut x = 1;
+LL | | {
+... |
+LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
--- /dev/null
+warning[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5
+ |
+LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14
+ |
+LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ | ^^
+ = warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
+ It represents potential unsoundness in your code.
+ This warning will become a hard error in the future.
+
+warning[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5
+ |
+LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20
+ |
+LL | fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ | ^^
+ = warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
+ It represents potential unsoundness in your code.
+ This warning will become a hard error in the future.
+
+warning[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5
+ |
+LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26
+ |
+LL | fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ | ^^
+ = warning: This error has been downgraded to a warning for backwards compatibility with previous releases.
+ It represents potential unsoundness in your code.
+ This warning will become a hard error in the future.
+
+error: compilation successful
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:89:1
+ |
+LL | / fn main() { //[ast]~ ERROR compilation successful
+LL | | //[migrate]~^ ERROR compilation successful
+LL | | let mut x = 1;
+LL | | {
+... |
+LL | | *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+error[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:63:5
+ |
+LL | &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 62:14...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:62:14
+ |
+LL | fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ | ^^
+
+error[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:73:5
+ |
+LL | &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 72:20...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:72:20
+ |
+LL | fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ | ^^
+
+error[E0597]: `*s.0` does not live long enough
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:83:5
+ |
+LL | &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ | ^^^^^^^^^^^^^ borrowed value does not live long enough
+...
+LL | }
+ | - `*s.0` dropped here while still borrowed
+ |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 82:26...
+ --> $DIR/issue-45696-scribble-on-boxed-borrow.rs:82:26
+ |
+LL | fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ | ^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /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.
+
+// rust-lang/rust#45696: This test is checking that we *cannot* return
+// mutable borrows that would be scribbled over by destructors before
+// the return occurs.
+//
+// We will explicitly test AST-borrowck, NLL, and migration modes;
+// thus we will also skip the automated compare-mode=nll.
+
+// revisions: ast nll migrate
+// ignore-compare-mode-nll
+
+// This test is going to pass in the ast and migrate revisions,
+// because the AST-borrowck accepted this code in the past (see notes
+// below). So we use `#[rustc_error]` to keep the outcome as an error
+// in all scenarios, and rely on the stderr files to show what the
+// actual behavior is. (See rust-lang/rust#49855.)
+#![feature(rustc_attrs)]
+
+#![cfg_attr(nll, feature(nll))]
+//[migrate]compile-flags: -Z borrowck=migrate -Z two-phase-borrows
+
+struct Scribble<'a>(&'a mut u32);
+
+impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
+
+// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has*
+// to strictly outlive `'a`
+fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
+ &mut *s.0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
+ &mut *(*s).0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
+ &mut *(**s).0
+}
+
+// this is not okay: in between the time that we take the mutable
+// borrow and the caller receives it as a return value, the drop of
+// `s` will scribble on it, violating our aliasing guarantees.
+//
+// * (Maybe in the future the two-phase borrows system will be
+// extended to support this case. But for now, it is an error in
+// NLL, even with two-phase borrows.)
+//
+// In any case, the AST-borrowck was not smart enough to know that
+// this should be an error. (Which is perhaps the essence of why
+// rust-lang/rust#45696 arose in the first place.)
+fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
+ &mut *s.0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ //[migrate]~^ WARNING `*s.0` does not live long enough [E0597]
+ //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility
+}
+
+// This, by analogy to previous case, is *also* not okay.
+//
+// (But again, AST-borrowck was not smart enogh to know that this
+// should be an error.)
+fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
+ &mut *(*s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ //[migrate]~^ WARNING `*s.0` does not live long enough [E0597]
+ //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility
+}
+
+// This, by analogy to previous case, is *also* not okay.
+//
+// (But again, AST-borrowck was not smart enogh to know that this
+// should be an error.)
+fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
+ &mut *(**s).0 //[nll]~ ERROR `*s.0` does not live long enough [E0597]
+ //[migrate]~^ WARNING `*s.0` does not live long enough [E0597]
+ //[migrate]~| WARNING This error has been downgraded to a warning for backwards compatibility
+}
+
+#[rustc_error]
+fn main() { //[ast]~ ERROR compilation successful
+ //[migrate]~^ ERROR compilation successful
+ let mut x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *borrowed_scribble(&mut long_lived) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ *scribbled(Scribble(&mut x)) += 10;
+ *boxed_scribbled(Box::new(Scribble(&mut x))) += 10;
+ *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;
+}
--- /dev/null
+// Copyright 2013 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
+
+#![feature(nll)]
+
+fn fibs(n: u32) -> impl Iterator<Item=u128> {
+ (0 .. n)
+ .scan((0, 1), |st, _| {
+ *st = (st.1, st.0 + st.1);
+ Some(*st)
+ })
+ .map(&|(f, _)| f)
+}
+
+fn main() {
+ println!("{:?}", fibs(10).collect::<Vec<_>>());
+}
--- /dev/null
+error: unsatisfied lifetime constraints
+ --> $DIR/issue-49824.rs:22:9
+ |
+LL | || {
+ | _____-
+ | |_____|
+ | ||
+LL | || || {
+ | ||_________^
+LL | ||| let _y = &mut x;
+LL | ||| }
+ | |||_________^ requires that `'1` must outlive `'2`
+LL | || };
+ | || -
+ | ||_____|
+ | |______lifetime `'1` represents the closure body
+ | lifetime `'2` appears in return type
+
+error: aborting due to previous error
+
--- /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.
+
+#![feature(rustc_attrs)]
+
+// This test checks that a failure occurs with NLL but does not fail with the
+// legacy AST output. Check issue-49824.nll.stderr for expected compilation error
+// output under NLL and #49824 for more information.
+
+#[rustc_error]
+fn main() {
+ //~^ compilation successful
+ let mut x = 0;
+ || {
+ || {
+ let _y = &mut x;
+ }
+ };
+}
--- /dev/null
+error: compilation successful
+ --> $DIR/issue-49824.rs:18:1
+ |
+LL | / fn main() {
+LL | | //~^ compilation successful
+LL | | let mut x = 0;
+LL | | || {
+... |
+LL | | };
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
// compile-pass
-#![feature(use_extern_macros, decl_macro)]
+#![feature(decl_macro)]
mod type_ns {
pub type A = u8;
| ^^^^ borrowed value does not live long enough
LL | //~^ ERROR `line` does not live long enough
LL | println!("accumulator before add_assign {:?}", acc.map);
- | ------- borrow later used here
+ | ------- borrow used here in later iteration of loop
...
LL | }
| - `line` dropped here while still borrowed
--- /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.
+
+#![feature(use_extern_macros, extern_prelude)]
+
+mod m {
+ fn check() {
+ Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
+ u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0433]: failed to resolve. Not a module `Vec`
+ --> $DIR/macro-path-prelude-fail-1.rs:15:9
+ |
+LL | Vec::clone!(); //~ ERROR failed to resolve. Not a module `Vec`
+ | ^^^ Not a module `Vec`
+
+error[E0433]: failed to resolve. Not a module `u8`
+ --> $DIR/macro-path-prelude-fail-1.rs:16:9
+ |
+LL | u8::clone!(); //~ ERROR failed to resolve. Not a module `u8`
+ | ^^ Not a module `u8`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0433`.
--- /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.
+
+#![feature(use_extern_macros)]
+
+mod m {
+ fn check() {
+ Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
+ }
+}
+
+fn main() {}
--- /dev/null
+error: fail to resolve non-ident macro path
+ --> $DIR/macro-path-prelude-fail-2.rs:15:9
+ |
+LL | Result::Ok!(); //~ ERROR fail to resolve non-ident macro path
+ | ^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /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.
+
+#![feature(use_extern_macros)]
+
+#[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
+struct S;
+
+fn main() {
+ inline!(); //~ ERROR expected a macro, found non-macro attribute
+}
--- /dev/null
+error: expected a macro, found non-macro attribute
+ --> $DIR/macro-path-prelude-fail-3.rs:13:10
+ |
+LL | #[derive(inline)] //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^
+
+error: expected a macro, found non-macro attribute
+ --> $DIR/macro-path-prelude-fail-3.rs:17:5
+ |
+LL | inline!(); //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^
+
+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.
+
+// compile-pass
+
+#![feature(use_extern_macros, extern_prelude)]
+
+mod m {
+ fn check() {
+ std::panic!(); // OK
+ }
+}
+
+fn main() {}
--- /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:macro-in-other-crate.rs
+
+#![feature(decl_macro, extern_prelude)]
+
+macro_rules! add_macro_expanded_things_to_macro_prelude {() => {
+ #[macro_use]
+ extern crate macro_in_other_crate;
+}}
+
+add_macro_expanded_things_to_macro_prelude!();
+
+mod m1 {
+ fn check() {
+ inline!(); //~ ERROR `inline` is ambiguous
+ }
+}
+
+mod m2 {
+ pub mod std {
+ pub macro panic() {}
+ }
+}
+
+mod m3 {
+ use m2::*; // glob-import user-defined `std`
+ fn check() {
+ std::panic!(); //~ ERROR `std` is ambiguous
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0659]: `inline` is ambiguous
+ --> $DIR/macro-path-prelude-shadowing.rs:24:9
+ |
+LL | inline!(); //~ ERROR `inline` is ambiguous
+ | ^^^^^^
+ |
+note: `inline` could refer to the name imported here
+ --> $DIR/macro-path-prelude-shadowing.rs:16:5
+ |
+LL | #[macro_use]
+ | ^^^^^^^^^^^^
+...
+LL | add_macro_expanded_things_to_macro_prelude!();
+ | ---------------------------------------------- in this macro invocation
+note: `inline` could also refer to the name defined here
+ --> $DIR/macro-path-prelude-shadowing.rs:24:9
+ |
+LL | inline!(); //~ ERROR `inline` is ambiguous
+ | ^^^^^^
+ = note: macro-expanded macro imports do not shadow
+
+error[E0659]: `std` is ambiguous
+ --> $DIR/macro-path-prelude-shadowing.rs:37:9
+ |
+LL | std::panic!(); //~ ERROR `std` is ambiguous
+ | ^^^^^^^^^^
+ |
+note: `std` could refer to the name imported here
+ --> $DIR/macro-path-prelude-shadowing.rs:35:9
+ |
+LL | use m2::*; // glob-import user-defined `std`
+ | ^^^^^
+note: `std` could also refer to the name defined here
+ --> $DIR/macro-path-prelude-shadowing.rs:37:9
+ |
+LL | std::panic!(); //~ ERROR `std` is ambiguous
+ | ^^^
+ = note: consider adding an explicit import of `std` to disambiguate
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0659`.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: expanding `println! { "Hello, World!" }`
- = note: to `{
- # [ cfg ( not ( stage0 ) ) ] {
- ( $crate :: io :: _print ( format_args_nl ! ( "Hello, World!" ) ) ) ; } # [
- cfg ( stage0 ) ] { print ! ( "{}/n" , format_args ! ( "Hello, World!" ) ) } }`
+ = note: to `{ $crate :: io :: _print ( format_args_nl ! ( "Hello, World!" ) ) ; }`
--- /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.
+
+// Check that mutable promoted length zero arrays don't check for conflicting
+// access
+
+// run-pass
+
+#![feature(nll)]
+
+pub fn main() {
+ let mut x: Vec<&[i32; 0]> = Vec::new();
+ for i in 0..10 {
+ x.push(&[]);
+ }
+}
| ^^^^^^^^^^^^ mutable borrow occurs here
LL | //~^ ERROR cannot borrow `foo` as mutable
LL | println!("foo={:?}", *string);
- | ------- borrow later used here
+ | ------- borrow used here in later iteration of loop
error: aborting due to previous error
// aux-build:macro-use-warned-against2.rs
// compile-pass
-#![warn(rust_2018_idioms, unused)]
+#![warn(macro_use_extern_crate, unused)]
#![feature(use_extern_macros)]
#[macro_use] //~ WARN should be replaced at use sites with a `use` statement
note: lint level defined here
--> $DIR/macro-use-warned-against.rs:15:9
|
-LL | #![warn(rust_2018_idioms, unused)]
- | ^^^^^^^^^^^^^^^^
- = note: #[warn(macro_use_extern_crate)] implied by #[warn(rust_2018_idioms)]
+LL | #![warn(macro_use_extern_crate, unused)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
warning: unused `#[macro_use]` import
--> $DIR/macro-use-warned-against.rs:20:1
| ^^^^^^^^^^^^
|
note: lint level defined here
- --> $DIR/macro-use-warned-against.rs:15:27
+ --> $DIR/macro-use-warned-against.rs:15:33
|
-LL | #![warn(rust_2018_idioms, unused)]
- | ^^^^^^
+LL | #![warn(macro_use_extern_crate, unused)]
+ | ^^^^^^
= note: #[warn(unused_imports)] implied by #[warn(unused)]
| |
| `*m` dropped here while still borrowed
| borrow later used here, when `m` is dropped
- |
- = note: values in a scope are dropped in the opposite order they are defined
error: aborting due to previous error
--> $DIR/regions-escape-loop-via-variable.rs:21:13
|
LL | let x = 1 + *p;
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
LL | p = &x;
| ^^ borrowed value does not live long enough
LL | }
| ^ use of borrowed `x`
LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
LL | _y.push(&mut z);
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
error[E0503]: cannot use `x` because it was mutably borrowed
--> $DIR/regions-escape-loop-via-vec.rs:16:21
LL | let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
| ^ use of borrowed `x`
LL | _y.push(&mut z);
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
error[E0597]: `z` does not live long enough
--> $DIR/regions-escape-loop-via-vec.rs:17:17
LL | _y.push(&mut z);
| -- ^^^^^^ borrowed value does not live long enough
| |
- | borrow later used here
+ | borrow used here in later iteration of loop
...
LL | }
| - `z` dropped here while still borrowed
| ------ borrow of `x` occurs here
...
LL | _y.push(&mut z);
- | -- borrow later used here
+ | -- borrow used here in later iteration of loop
LL | //~^ ERROR `z` does not live long enough
LL | x += 1; //~ ERROR cannot assign
| ^^^^^^ use of borrowed `x`
// ignore-aarch64
// ignore-wasm
// ignore-emscripten
+// ignore-mips
+// ignore-mips64
// gate-test-sse4a_target_feature
// gate-test-powerpc_target_feature
// gate-test-avx512_target_feature
error[E0658]: the target feature `avx512bw` is currently unstable (see issue #44839)
- --> $DIR/target-feature-gate.rs:26:18
+ --> $DIR/target-feature-gate.rs:28:18
|
LL | #[target_feature(enable = "avx512bw")]
| ^^^^^^^^^^^^^^^^^^^
// ignore-wasm
// ignore-emscripten
// ignore-mips
+// ignore-mips64
// ignore-powerpc
// ignore-powerpc64
// ignore-powerpc64le
error: #[target_feature] attribute must be of the form #[target_feature(..)]
- --> $DIR/target-feature-wrong.rs:25:1
+ --> $DIR/target-feature-wrong.rs:26:1
|
LL | #[target_feature = "+sse2"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: the feature named `foo` is not valid for this target
- --> $DIR/target-feature-wrong.rs:27:18
+ --> $DIR/target-feature-wrong.rs:28:18
|
LL | #[target_feature(enable = "foo")]
| ^^^^^^^^^^^^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:29:18
+ --> $DIR/target-feature-wrong.rs:30:18
|
LL | #[target_feature(bar)]
| ^^^
error: #[target_feature(..)] only accepts sub-keys of `enable` currently
- --> $DIR/target-feature-wrong.rs:31:18
+ --> $DIR/target-feature-wrong.rs:32:18
|
LL | #[target_feature(disable = "baz")]
| ^^^^^^^^^^^^^^^
error: #[target_feature(..)] can only be applied to `unsafe` function
- --> $DIR/target-feature-wrong.rs:35:1
+ --> $DIR/target-feature-wrong.rs:36:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: attribute should be applied to a function
- --> $DIR/target-feature-wrong.rs:39:1
+ --> $DIR/target-feature-wrong.rs:40:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| -------------- not a function
error: cannot use #[inline(always)] with #[target_feature]
- --> $DIR/target-feature-wrong.rs:43:1
+ --> $DIR/target-feature-wrong.rs:44:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
--- /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.
+
+// If macro modularization (`use_extern_macros`) is not enabled,
+// then tool attributes are treated as custom attributes.
+
+#[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
+fn main() {}
--- /dev/null
+error[E0658]: The attribute `rustfmt::bar` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
+ --> $DIR/tool-attributes-disabled-1.rs:14:1
+ |
+LL | #[rustfmt::bar] //~ ERROR The attribute `rustfmt::bar` is currently unknown to the compiler
+ | ^^^^^^^^^^^^^^^
+ |
+ = help: add #![feature(custom_attribute)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+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.
+
+// If macro modularization (`use_extern_macros`) is not enabled,
+// then tool attributes are treated as custom attributes.
+
+// compile-pass
+
+#![feature(custom_attribute)]
+
+#[rustfmt::bar]
+fn main() {}
--- /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.
+
+#![feature(tool_attributes)]
+
+type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
+type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
+
+#[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
+struct S;
+
+#[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
+fn check() {}
+
+#[rustfmt::skip] // OK
+fn main() {
+ rustfmt; //~ ERROR expected value, found tool module `rustfmt`
+ rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
+
+ rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
+}
--- /dev/null
+error: cannot find derive macro `rustfmt` in this scope
+ --> $DIR/tool-attributes-misplaced-1.rs:16:10
+ |
+LL | #[derive(rustfmt)] //~ ERROR cannot find derive macro `rustfmt` in this scope
+ | ^^^^^^^
+
+error: cannot find attribute macro `rustfmt` in this scope
+ --> $DIR/tool-attributes-misplaced-1.rs:19:3
+ |
+LL | #[rustfmt] //~ ERROR cannot find attribute macro `rustfmt` in this scope
+ | ^^^^^^^
+
+error: cannot find macro `rustfmt!` in this scope
+ --> $DIR/tool-attributes-misplaced-1.rs:25:5
+ |
+LL | rustfmt!(); //~ ERROR cannot find macro `rustfmt!` in this scope
+ | ^^^^^^^
+
+error[E0573]: expected type, found tool module `rustfmt`
+ --> $DIR/tool-attributes-misplaced-1.rs:13:10
+ |
+LL | type A = rustfmt; //~ ERROR expected type, found tool module `rustfmt`
+ | ^^^^^^^ not a type
+
+error[E0573]: expected type, found non-macro attribute `rustfmt::skip`
+ --> $DIR/tool-attributes-misplaced-1.rs:14:10
+ |
+LL | type B = rustfmt::skip; //~ ERROR expected type, found non-macro attribute `rustfmt::skip`
+ | ^^^^^^^^^^^^^ not a type
+
+error[E0423]: expected value, found tool module `rustfmt`
+ --> $DIR/tool-attributes-misplaced-1.rs:24:5
+ |
+LL | rustfmt; //~ ERROR expected value, found tool module `rustfmt`
+ | ^^^^^^^ not a value
+
+error[E0423]: expected value, found non-macro attribute `rustfmt::skip`
+ --> $DIR/tool-attributes-misplaced-1.rs:27:5
+ |
+LL | rustfmt::skip; //~ ERROR expected value, found non-macro attribute `rustfmt::skip`
+ | ^^^^^^^^^^^^^ not a value
+
+error: aborting due to 7 previous errors
+
+Some errors occurred: E0423, E0573.
+For more information about an error, try `rustc --explain E0423`.
--- /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.
+
+#![feature(tool_attributes)]
+
+#[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
+struct S;
+
+fn main() {
+ rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
+}
--- /dev/null
+error: expected a macro, found non-macro attribute
+ --> $DIR/tool-attributes-misplaced-2.rs:13:10
+ |
+LL | #[derive(rustfmt::skip)] //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^^^^^^^^
+
+error: expected a macro, found non-macro attribute
+ --> $DIR/tool-attributes-misplaced-2.rs:17:5
+ |
+LL | rustfmt::skip!(); //~ ERROR expected a macro, found non-macro attribute
+ | ^^^^^^^^^^^^^
+
+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.
+
+#![feature(tool_attributes, proc_macro_path_invoc)]
+
+mod rustfmt {}
+
+#[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
+fn main() {}
--- /dev/null
+error[E0433]: failed to resolve. Could not find `skip` in `rustfmt`
+ --> $DIR/tool-attributes-shadowing.rs:15:12
+ |
+LL | #[rustfmt::skip] //~ ERROR failed to resolve. Could not find `skip` in `rustfmt`
+ | ^^^^ Could not find `skip` in `rustfmt`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
"powerpc64-unknown-linux-gnu",
"powerpc64le-unknown-linux-gnu",
"powerpc64le-unknown-linux-musl",
+ "riscv32imac-unknown-none-elf",
"s390x-unknown-linux-gnu",
"sparc-unknown-linux-gnu",
"sparc64-unknown-linux-gnu",
-Subproject commit 2cd36b4ed1aef1ae39a30783e006411d1a4218ac
+Subproject commit 15433e8cc932a2b4c0d3f9638e07d08c1c7ac39d
-Subproject commit b0dabce47803c18b935ec5390de69e04ad5304c2
+Subproject commit 8ef759e0273ad97f1acbb1ea9f94322aa2a20147
-Subproject commit 4c7cc91d5518bd29d3d59599cfb7a2e7e848d7b7
+Subproject commit 0e8d1f3e7acba9737f52dbfc4cb25e5259d4890f
--- /dev/null
+[package]
+name = "rustc-workspace-hack"
+version = "1.0.0"
+authors = ["Alex Crichton <alex@alexcrichton.com>"]
+license = 'MIT/Apache-2.0'
+description = """
+Hack for the compiler's own build system
+"""
+
+[lib]
+path = "lib.rs"
+
+# For documentation about what this is and why in the world these dependencies
+# are appearing, see `README.md`.
+
+[build-dependencies]
+# Currently Cargo/RLS depend on `failure` which depends on `synstructure` which
+# enables this feature. Clippy, however, does not depend on anything that
+# enables this feature. Enable it unconditionally.
+syn = { version = "0.14", features = ['extra-traits'] }
+
+[target.'cfg(windows)'.dependencies.winapi]
+version = "0.3"
+features = [
+ "profileapi",
+ "memoryapi",
+ "minschannel",
+ "securitybaseapi",
+ "jobapi2",
+ "schannel",
+ "sysinfoapi",
+ "jobapi",
+ "synchapi",
+ "wincrypt",
+ "winbase",
+ "minwinbase",
+ "ntsecapi",
+ "basetsd",
+ "ntstatus",
+ "psapi",
+ "timezoneapi",
+ "lmcons",
+ "wincon",
+]
--- /dev/null
+# `rustc-workspace-hack`
+
+This crate is a bit of a hack to make workspaces in rustc work a bit better.
+The rationale for this existence is a bit subtle, but the general idea is that
+we want commands like `./x.py build src/tools/{rls,clippy,cargo}` to share as
+many dependencies as possible.
+
+Each invocation is a different invocation of Cargo, however. Each time Cargo
+runs a build it will re-resolve the dependency graph, notably selecting
+different features sometimes for each build.
+
+For example, let's say there's a very deep dependency like `num-traits` in each
+of these builds. For Cargo the `num-traits`'s `default` feature is turned off.
+In RLS, however, the `default` feature is turned. This means that building Cargo
+and then the RLS will actually build Cargo twice (as a transitive dependency
+changed). This is bad!
+
+The goal of this crate is to solve this problem and ensure that the resolved
+dependency graph for all of these tools is the same in the various subsets of
+each tool, notably enabling the same features of transitive dependencies.
+
+All tools vendored here depend on the `rustc-workspace-hack` crate on crates.io.
+When on crates.io this crate is an empty crate that is just a noop. We override
+it, however, in this workspace to this crate here, which means we can control
+crates in the dependency graph for each of these tools.
--- /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.
+
+// intentionally left blank
-Subproject commit 69ad879d52606ac03440744efa5b4d8ca8cc7566
+Subproject commit d50e3618d419ec074927ea79741f0c595e7ff2d4