AppVeyor: Read back trace from crash dump on failure.
This is an attempt to debug spurious access violations on Windows (#33434, #50604). Thanks to #50276, there should be minidumps to read when rustc segfault.
(The implementation is based on <https://github.com/springmeyer/travis-coredump/blob/master/test.bat>.)
[[package]]
name = "assert_cli"
-version = "0.5.4"
+version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "difference 1.0.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)",
- "error-chain 0.11.0 (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)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "build_helper"
version = "0.1.0"
-[[package]]
-name = "bytecount"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "byteorder"
version = "1.2.2"
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "cargo_metadata"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "cargo_metadata"
version = "0.5.4"
[[package]]
name = "clippy"
-version = "0.0.197"
+version = "0.0.198"
dependencies = [
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy-mini-macro-test 0.2.0",
- "clippy_lints 0.0.197",
+ "clippy_lints 0.0.198",
"compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "clippy_lints"
version = "0.0.197"
+source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "clippy_lints"
+version = "0.0.198"
+dependencies = [
+ "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "cmake"
version = "0.1.30"
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "derive-new"
-version = "0.5.2"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "difference"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "difference"
version = "2.0.0"
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "proc-macro2"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "proc-macro2"
version = "0.3.6"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "quote"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "quote"
version = "0.5.1"
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "regex"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "regex-syntax"
version = "0.5.5"
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "regex-syntax"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "remote-test-client"
version = "0.1.0"
dependencies = [
"cargo 0.28.0",
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy_lints 0.0.197",
+ "clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_target 0.0.0",
]
+[[package]]
+name = "rustc-rayon"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-rayon-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-serialize"
version = "0.3.24"
"log 0.4.1 (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-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_cratesio_shim 0.0.0",
"serialize 0.0.0",
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
+ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_allocator 0.0.0",
"rustc_borrowck 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_traits 0.0.0",
"rustc_trans_utils 0.0.0",
"rustc_typeck 0.0.0",
+ "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_ext 0.0.0",
"syntax_pos 0.0.0",
]
+[[package]]
+name = "rustc_version"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustdoc"
version = "0.0.0"
name = "rustfmt-nightly"
version = "0.6.1"
dependencies = [
- "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "same-file"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "same-file"
version = "1.0.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "semver"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "semver"
version = "0.9.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "skeptic"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "smallvec"
version = "0.6.0"
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "syn"
-version = "0.12.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "syn"
version = "0.13.1"
name = "syntax_pos"
version = "0.0.0"
dependencies = [
+ "arena 0.0.0",
"rustc_data_structures 0.0.0",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",
[[package]]
name = "tempfile"
-version = "3.0.1"
+version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "walkdir"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "walkdir"
version = "2.1.4"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
-"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930"
+"checksum assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8ca6beaa44a3520407b28a4a779a19b1364fcadcb2f258c41a7baf3102ced0"
"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4"
"checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e"
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
-"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de"
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
-"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
"checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3"
"checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873"
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
+"checksum clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)" = "ee3b543abb36b1557180d41dd3758581254644d85d021df7f8f8cb395054581c"
"checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c"
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
"checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0"
"checksum curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71c63a540a9ee4e15e56c3ed9b11a2f121239b9f6d7b7fe30f616e048148df9a"
"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
-"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71"
+"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a"
"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
-"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
-"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
-"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
"checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d"
"checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
+"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
+"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46"
"checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
"checksum rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50671adb9b0a7c57a4690ac6a40cb614879f543b64aada42f55b66212492323"
"checksum rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55793c2a775230c42661194c48d44b35d4c8439d79ad8528e56651e854c48c63"
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
+"checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99"
+"checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b"
"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.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85"
-"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
-"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248"
"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
-"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a"
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
"checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545"
"checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
-"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
"checksum 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 syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
"checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c"
+"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"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561"
"checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
cmd.arg(format!("-Clinker={}", host_linker));
}
+
+ if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
+ if s == "true" {
+ cmd.arg("-C").arg("target-feature=+crt-static");
+ }
+ if s == "false" {
+ cmd.arg("-C").arg("target-feature=-crt-static");
+ }
+ }
}
if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() {
"""
return os.path.join(self.build_dir, self.build, "stage0")
- def get_toml(self, key):
+ def get_toml(self, key, section=None):
"""Returns the value of the given key in config.toml, otherwise returns None
>>> rb = RustBuild()
>>> rb.get_toml("key3") is None
True
+
+ Optionally also matches the section the key appears in
+
+ >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
+ >>> rb.get_toml('key', 'a')
+ 'value1'
+ >>> rb.get_toml('key', 'b')
+ 'value2'
+ >>> rb.get_toml('key', 'c') is None
+ True
"""
+
+ cur_section = None
for line in self.config_toml.splitlines():
+ section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
+ if section_match is not None:
+ cur_section = section_match.group(1)
+
match = re.match(r'^{}\s*=(.*)$'.format(key), line)
if match is not None:
value = match.group(1)
- return self.get_string(value) or value.strip()
+ if section is None or section == cur_section:
+ return self.get_string(value) or value.strip()
return None
def cargo(self):
env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
(os.pathsep + env["LIBRARY_PATH"]) \
if "LIBRARY_PATH" in env else ""
- env["RUSTFLAGS"] = "-Cdebuginfo=2"
+ env["RUSTFLAGS"] = "-Cdebuginfo=2 "
+
+ build_section = "target.{}".format(self.build_triple())
+ target_features = []
+ if self.get_toml("crt-static", build_section) == "true":
+ target_features += ["+crt-static"]
+ elif self.get_toml("crt-static", build_section) == "false":
+ target_features += ["-crt-static"]
+ if target_features:
+ env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " "
+
env["PATH"] = os.path.join(self.bin_root(), "bin") + \
os.pathsep + env["PATH"]
if not os.path.isfile(self.cargo()):
cargo.env("RUSTC_CRT_STATIC", x.to_string());
}
+ if let Some(x) = self.crt_static(compiler.host) {
+ cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
+ }
+
// Enable usage of unstable features
cargo.env("RUSTC_BOOTSTRAP", "1");
self.add_rust_test_threads(&mut cargo);
touch "$TOOLSTATE_FILE"
+# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE
+
set +e
python2.7 "$X_PY" test --no-fail-fast \
src/doc/book \
cat "$TOOLSTATE_FILE"
echo
+# This function checks that if a tool's submodule changed, the tool's state must improve
verify_status() {
echo "Verifying status of $1..."
if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
fi
}
+# deduplicates the submodule check and the assertion that on beta some tools MUST be passing
+check_dispatch() {
+ if [ "$1" = submodule_changed ]; then
+ # ignore $2 (branch id)
+ verify_status $3 $4
+ elif [ "$2" = beta ]; then
+ echo "Requiring test passing for $3..."
+ if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then
+ exit 4
+ fi
+ fi
+}
+
+# list all tools here
+status_check() {
+ check_dispatch $1 beta book src/doc/book
+ check_dispatch $1 beta nomicon src/doc/nomicon
+ check_dispatch $1 beta reference src/doc/reference
+ check_dispatch $1 beta rust-by-example src/doc/rust-by-example
+ check_dispatch $1 beta rls src/tool/rls
+ check_dispatch $1 beta rustfmt src/tool/rustfmt
+ # these tools are not required for beta to successfully branch
+ check_dispatch $1 nightly clippy-driver src/tool/clippy
+ check_dispatch $1 nightly miri src/tool/miri
+}
+
# If this PR is intended to update one of these tools, do not let the build pass
# when they do not test-pass.
-verify_status book src/doc/book
-verify_status nomicon src/doc/nomicon
-verify_status reference src/doc/reference
-verify_status rust-by-example src/doc/rust-by-example
-verify_status rls src/tool/rls
-verify_status rustfmt src/tool/rustfmt
-verify_status clippy-driver src/tool/clippy
-verify_status miri src/tool/miri
+status_check "submodule_changed"
if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
. "$(dirname $0)/repo.sh"
exit 0
fi
-if grep -q fail "$TOOLSTATE_FILE"; then
- exit 4
-fi
+# abort compilation if an important tool doesn't build
+# (this code is reachable if not on the nightly channel)
+status_check "beta_required"
}
fn replace(&mut self, key: K) -> Option<K> {
+ self.ensure_root_is_owned();
match search::search_tree::<marker::Mut, K, (), K>(self.root.as_mut(), &key) {
Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
GoDown(handle) => {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> BTreeMap<K, V> {
BTreeMap {
- root: node::Root::new_leaf(),
+ root: node::Root::shared_empty_root(),
length: 0,
}
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn clear(&mut self) {
- // FIXME(gereeter) .clear() allocates
*self = BTreeMap::new();
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn entry(&mut self, key: K) -> Entry<K, V> {
+ // FIXME(@porglezomp) Avoid allocating if we don't insert
+ self.ensure_root_is_owned();
match search::search_tree(self.root.as_mut(), &key) {
Found(handle) => {
Occupied(OccupiedEntry {
}
fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
+ self.ensure_root_is_owned();
let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node();
// Iterate through all key-value pairs, pushing them into nodes at the right level.
for (key, value) in iter {
let total_num = self.len();
let mut right = Self::new();
+ right.root = node::Root::new_leaf();
for _ in 0..(self.root.as_ref().height()) {
right.root.push_level();
}
self.fix_top();
}
+
+ /// If the root node is the shared root node, allocate our own node.
+ fn ensure_root_is_owned(&mut self) {
+ if self.root.is_shared_root() {
+ self.root = node::Root::new_leaf();
+ }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
self.for_each(drop);
unsafe {
let leaf_node = ptr::read(&self.front).into_node();
+ if leaf_node.is_shared_root() {
+ return;
+ }
+
if let Some(first_parent) = leaf_node.deallocate_and_ascend() {
let mut cur_node = first_parent.into_node();
while let Some(parent) = cur_node.deallocate_and_ascend() {
///
/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
/// avoiding accidentally dropping unused and uninitialized keys and values.
+///
+/// We put the metadata first so that its position is the same for every `K` and `V`, in order
+/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
+/// prevent them from being reordered.
+#[repr(C)]
struct LeafNode<K, V> {
- /// The arrays storing the actual data of the node. Only the first `len` elements of each
- /// array are initialized and valid.
- keys: [K; CAPACITY],
- vals: [V; CAPACITY],
-
/// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
/// This either points to an actual node or is null.
parent: *const InternalNode<K, V>,
/// The number of keys and values this node stores.
///
- /// This is at the end of the node's representation and next to `parent_idx` to encourage
- /// the compiler to join `len` and `parent_idx` into the same 32-bit word, reducing space
- /// overhead.
+ /// This next to `parent_idx` to encourage the compiler to join `len` and
+ /// `parent_idx` into the same 32-bit word, reducing space overhead.
len: u16,
+
+ /// The arrays storing the actual data of the node. Only the first `len` elements of each
+ /// array are initialized and valid.
+ keys: [K; CAPACITY],
+ vals: [V; CAPACITY],
}
impl<K, V> LeafNode<K, V> {
len: 0
}
}
+
+ fn is_shared_root(&self) -> bool {
+ self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V>
+ }
}
+// We need to implement Sync here in order to make a static instance.
+unsafe impl Sync for LeafNode<(), ()> {}
+
+// An empty node used as a placeholder for the root node, to avoid allocations.
+// We use () in order to save space, since no operation on an empty tree will
+// ever take a pointer past the first key.
+static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
+ parent: ptr::null(),
+ parent_idx: 0,
+ len: 0,
+ keys: [(); CAPACITY],
+ vals: [(); CAPACITY],
+};
+
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the
unsafe impl<K: Send, V: Send> Send for Root<K, V> { }
impl<K, V> Root<K, V> {
+ pub fn is_shared_root(&self) -> bool {
+ self.as_ref().is_shared_root()
+ }
+
+ pub fn shared_empty_root() -> Self {
+ Root {
+ node: unsafe {
+ BoxedNode::from_ptr(NonNull::new_unchecked(
+ &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V> as *mut _
+ ))
+ },
+ height: 0,
+ }
+ }
+
pub fn new_leaf() -> Self {
Root {
node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })),
/// new node the root. This increases the height by 1 and is the opposite of `pop_level`.
pub fn push_level(&mut self)
-> NodeRef<marker::Mut, K, V, marker::Internal> {
+ debug_assert!(!self.is_shared_root());
let mut new_node = Box::new(unsafe { InternalNode::new() });
new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) };
}
}
+ pub fn is_shared_root(&self) -> bool {
+ self.as_leaf().is_shared_root()
+ }
+
pub fn keys(&self) -> &[K] {
- self.reborrow().into_slices().0
+ self.reborrow().into_key_slice()
}
- pub fn vals(&self) -> &[V] {
- self.reborrow().into_slices().1
+ fn vals(&self) -> &[V] {
+ self.reborrow().into_val_slice()
}
/// Finds the parent of the current node. Returns `Ok(handle)` if the current
marker::Edge
>
> {
+ debug_assert!(!self.is_shared_root());
let node = self.node;
let ret = self.ascend().ok();
Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>());
}
}
- pub fn keys_mut(&mut self) -> &mut [K] {
- unsafe { self.reborrow_mut().into_slices_mut().0 }
+ fn keys_mut(&mut self) -> &mut [K] {
+ unsafe { self.reborrow_mut().into_key_slice_mut() }
}
- pub fn vals_mut(&mut self) -> &mut [V] {
- unsafe { self.reborrow_mut().into_slices_mut().1 }
+ fn vals_mut(&mut self) -> &mut [V] {
+ unsafe { self.reborrow_mut().into_val_slice_mut() }
}
}
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
- pub fn into_slices(self) -> (&'a [K], &'a [V]) {
- unsafe {
- (
+ fn into_key_slice(self) -> &'a [K] {
+ // When taking a pointer to the keys, if our key has a stricter
+ // alignment requirement than the shared root does, then the pointer
+ // would be out of bounds, which LLVM assumes will not happen. If the
+ // alignment is more strict, we need to make an empty slice that doesn't
+ // use an out of bounds pointer.
+ if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+ &[]
+ } else {
+ // Here either it's not the root, or the alignment is less strict,
+ // in which case the keys pointer will point "one-past-the-end" of
+ // the node, which is allowed by LLVM.
+ unsafe {
slice::from_raw_parts(
self.as_leaf().keys.as_ptr(),
self.len()
- ),
- slice::from_raw_parts(
- self.as_leaf().vals.as_ptr(),
- self.len()
)
+ }
+ }
+ }
+
+ fn into_val_slice(self) -> &'a [V] {
+ debug_assert!(!self.is_shared_root());
+ unsafe {
+ slice::from_raw_parts(
+ self.as_leaf().vals.as_ptr(),
+ self.len()
)
}
}
+
+ fn into_slices(self) -> (&'a [K], &'a [V]) {
+ let k = unsafe { ptr::read(&self) };
+ (k.into_key_slice(), self.into_val_slice())
+ }
}
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
}
}
- pub fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
- unsafe {
- (
+ fn into_key_slice_mut(mut self) -> &'a mut [K] {
+ if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+ &mut []
+ } else {
+ unsafe {
slice::from_raw_parts_mut(
&mut self.as_leaf_mut().keys as *mut [K] as *mut K,
self.len()
- ),
- slice::from_raw_parts_mut(
- &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
- self.len()
)
+ }
+ }
+ }
+
+ fn into_val_slice_mut(mut self) -> &'a mut [V] {
+ debug_assert!(!self.is_shared_root());
+ unsafe {
+ slice::from_raw_parts_mut(
+ &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
+ self.len()
)
}
}
+
+ fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) {
+ let k = unsafe { ptr::read(&self) };
+ (k.into_key_slice_mut(), self.into_val_slice_mut())
+ }
}
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
pub fn push(&mut self, key: K, val: V) {
// Necessary for correctness, but this is an internal module
debug_assert!(self.len() < CAPACITY);
+ debug_assert!(!self.is_shared_root());
let idx = self.len();
pub fn push_front(&mut self, key: K, val: V) {
// Necessary for correctness, but this is an internal module
debug_assert!(self.len() < CAPACITY);
+ debug_assert!(!self.is_shared_root());
unsafe {
slice_insert(self.keys_mut(), 0, key);
fn insert_fit(&mut self, key: K, val: V) -> *mut V {
// Necessary for correctness, but in a private module
debug_assert!(self.node.len() < CAPACITY);
+ debug_assert!(!self.node.is_shared_root());
unsafe {
slice_insert(self.node.keys_mut(), self.idx, key);
/// allocated node.
pub fn split(mut self)
-> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
+ debug_assert!(!self.node.is_shared_root());
unsafe {
let mut new_node = Box::new(LeafNode::new());
/// now adjacent key/value pairs to the left and right of this handle.
pub fn remove(mut self)
-> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
+ debug_assert!(!self.node.is_shared_root());
unsafe {
let k = slice_remove(self.node.keys_mut(), self.idx);
let v = slice_remove(self.node.vals_mut(), self.idx);
#[test]
fn secs() {
assert_eq!(Duration::new(0, 0).as_secs(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0);
+ assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1);
assert_eq!(Duration::from_secs(1).as_secs(), 1);
assert_eq!(Duration::from_millis(999).as_secs(), 0);
assert_eq!(Duration::from_millis(1001).as_secs(), 1);
+ assert_eq!(Duration::from_micros(999_999).as_secs(), 0);
+ assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0);
+ assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1);
+}
+
+#[test]
+fn millis() {
+ assert_eq!(Duration::new(0, 0).subsec_millis(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500);
+ assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50);
+ assert_eq!(Duration::from_secs(1).subsec_millis(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_millis(), 999);
+ assert_eq!(Duration::from_millis(1001).subsec_millis(), 1);
+ assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999);
+ assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999);
+ assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1);
+}
+
+#[test]
+fn micros() {
+ assert_eq!(Duration::new(0, 0).subsec_micros(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000);
+ assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000);
+ assert_eq!(Duration::from_secs(1).subsec_micros(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000);
+ assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000);
+ assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999);
+ assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999);
+ assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1);
}
#[test]
assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
- assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
- assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
+ assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000);
+ assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000);
+ assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000);
+ assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999);
+ assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1);
}
#[test]
///
/// [`subsec_nanos`]: #method.subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn as_secs(&self) -> u64 { self.secs }
+ pub const fn as_secs(&self) -> u64 { self.secs }
/// Returns the fractional part of this `Duration`, in milliseconds.
///
/// assert_eq!(duration.subsec_millis(), 432);
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
+ pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
/// Returns the fractional part of this `Duration`, in microseconds.
///
/// assert_eq!(duration.subsec_micros(), 234_567);
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
+ pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
/// Returns the fractional part of this `Duration`, in nanoseconds.
///
/// assert_eq!(duration.subsec_nanos(), 10_000_000);
/// ```
#[stable(feature = "duration", since = "1.3.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn subsec_nanos(&self) -> u32 { self.nanos }
+ pub const fn subsec_nanos(&self) -> u32 { self.nanos }
/// Checked `Duration` addition. Computes `self + other`, returning [`None`]
/// if overflow occurred.
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
[input] UsedCrateSource(CrateNum),
[input] PostorderCnums,
- // This query is not expected to have inputs -- as a result, it's
- // not a good candidate for "replay" because it's essentially a
- // pure function of its input (and hence the expectation is that
- // no caller would be green **apart** from just this
- // query). Making it anonymous avoids hashing the result, which
+ // These queries are not expected to have inputs -- as a result, they
+ // are not good candidates for "replay" because they are essentially
+ // pure functions of their input (and hence the expectation is that
+ // no caller would be green **apart** from just these
+ // queries). Making them anonymous avoids hashing the result, which
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
+ [anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },
[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::small_vec::SmallVec;
-use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock};
+use rustc_data_structures::sync::{Lrc, Lock};
use std::env;
use std::hash::Hash;
use ty::{self, TyCtxt};
/// this map. We can later look for and extract that data.
previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
- /// Work-products that we generate in this run.
- work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
-
dep_node_debug: Lock<FxHashMap<DepNode, String>>,
// Used for testing, only populated when -Zquery-dep-graph is specified.
DepGraph {
data: Some(Lrc::new(DepGraphData {
previous_work_products: prev_work_products,
- work_products: RwLock::new(FxHashMap()),
dep_node_debug: Lock::new(FxHashMap()),
current: Lock::new(CurrentDepGraph::new()),
previous: prev_graph,
self.data.as_ref().unwrap().previous.node_to_index(dep_node)
}
- /// Indicates that we created the given work-product in this run
- /// for `v`. This record will be preserved and loaded in the next
- /// run.
- pub fn insert_work_product(&self, v: &WorkProductId, data: WorkProduct) {
- debug!("insert_work_product({:?}, {:?})", v, data);
- self.data
- .as_ref()
- .unwrap()
- .work_products
- .borrow_mut()
- .insert(v.clone(), data);
- }
-
/// Check whether a previous work product exists for `v` and, if
/// so, return the path that leads to it. Used to skip doing work.
pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
})
}
- /// Access the map of work-products created during this run. Only
- /// used during saving of the dep-graph.
- pub fn work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> {
- self.data.as_ref().unwrap().work_products.borrow()
- }
-
/// Access the map of work-products created during the cached run. Only
/// used during saving of the dep-graph.
pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
self.visitor.visit_impl_item(impl_item);
}
}
+
+/// A parallel variant of ItemLikeVisitor
+pub trait ParItemLikeVisitor<'hir> {
+ fn visit_item(&self, item: &'hir Item);
+ fn visit_trait_item(&self, trait_item: &'hir TraitItem);
+ fn visit_impl_item(&self, impl_item: &'hir ImplItem);
+}
+
+pub trait IntoVisitor<'hir> {
+ type Visitor: Visitor<'hir>;
+ fn into_visitor(&self) -> Self::Visitor;
+}
+
+pub struct ParDeepVisitor<V>(pub V);
+
+impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor<V>
+ where V: IntoVisitor<'hir>
+{
+ fn visit_item(&self, item: &'hir Item) {
+ self.0.into_visitor().visit_item(item);
+ }
+
+ fn visit_trait_item(&self, trait_item: &'hir TraitItem) {
+ self.0.into_visitor().visit_trait_item(trait_item);
+ }
+
+ fn visit_impl_item(&self, impl_item: &'hir ImplItem) {
+ self.0.into_visitor().visit_impl_item(impl_item);
+ }
+}
use ty::maps::Providers;
use rustc_data_structures::indexed_vec;
+use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope};
use serialize::{self, Encoder, Encodable, Decoder, Decodable};
use std::collections::BTreeMap;
}
}
+ /// A parallel version of visit_all_item_likes
+ pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V)
+ where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send
+ {
+ scope(|s| {
+ s.spawn(|_| {
+ par_iter(&self.items).for_each(|(_, item)| {
+ visitor.visit_item(item);
+ });
+ });
+
+ s.spawn(|_| {
+ par_iter(&self.trait_items).for_each(|(_, trait_item)| {
+ visitor.visit_trait_item(trait_item);
+ });
+ });
+
+ s.spawn(|_| {
+ par_iter(&self.impl_items).for_each(|(_, impl_item)| {
+ visitor.visit_impl_item(impl_item);
+ });
+ });
+ });
+ }
+
pub fn body(&self, id: BodyId) -> &Body {
&self.bodies[&id]
}
}
impl ::std::fmt::Display for Fingerprint {
- fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+ fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(formatter, "{:x}-{:x}", self.0, self.1)
}
}
}
}
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::ConstValue<'gcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use mir::interpret::ConstValue::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+
+ match *self {
+ ByVal(val) => {
+ val.hash_stable(hcx, hasher);
+ }
+ ByValPair(a, b) => {
+ a.hash_stable(hcx, hasher);
+ b.hash_stable(hcx, hasher);
+ }
+ ByRef(alloc) => {
+ alloc.hash_stable(hcx, hasher);
+ }
+ }
+ }
+}
+
impl_stable_hash_for!(enum mir::interpret::Value {
ByVal(v),
ByValPair(a, b),
declare_lint! {
pub SINGLE_USE_LIFETIME,
Allow,
- "detects single use lifetimes"
+ "detects lifetime parameters that are only used once"
+}
+
+declare_lint! {
+ pub UNUSED_LIFETIME,
+ Allow,
+ "detects lifetime parameters that are never used"
}
declare_lint! {
UNUSED_UNSAFE,
UNUSED_MUT,
SINGLE_USE_LIFETIME,
+ UNUSED_LIFETIME,
TYVAR_BEHIND_RAW_POINTER,
ELIDED_LIFETIME_IN_PATH,
BARE_TRAIT_OBJECT,
use hir::def_id::DefId;
use ty::{self, TyCtxt, layout};
use ty::subst::Substs;
-use mir::interpret::{Value, PrimVal};
+use mir::interpret::ConstValue;
use errors::DiagnosticBuilder;
use graphviz::IntoCow;
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
pub enum ConstVal<'tcx> {
Unevaluated(DefId, &'tcx Substs<'tcx>),
- Value(Value),
-}
-
-impl<'tcx> ConstVal<'tcx> {
- pub fn to_raw_bits(&self) -> Option<u128> {
- match *self {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
- Some(b)
- },
- _ => None,
- }
- }
- pub fn unwrap_u64(&self) -> u64 {
- match self.to_raw_bits() {
- Some(val) => {
- assert_eq!(val as u64 as u128, val);
- val as u64
- },
- None => bug!("expected constant u64, got {:#?}", self),
- }
- }
+ Value(ConstValue<'tcx>),
}
#[derive(Clone, Debug)]
use syntax::symbol::Symbol;
use syntax_pos::Span;
use rustc_target::spec::Target;
-use rustc_data_structures::sync::{MetadataRef, Lrc};
+use rustc_data_structures::sync::{self, MetadataRef, Lrc};
pub use self::NativeLibraryKind::*;
fn metadata_encoding_version(&self) -> &[u8];
}
+pub type CrateStoreDyn = CrateStore + sync::Sync;
+
// FIXME: find a better place for this?
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
let mut err_count = 0;
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
let promotable = match expr_ty.sty {
- ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
+ ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
_ => promotable,
};
//! used between functions, and they operate in a purely top-down
//! way. Therefore we break lifetime name resolution into a separate pass.
-use hir::map::Map;
use hir::def::Def;
use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use hir::map::Map;
use hir::ItemLocalId;
use hir::LifetimeName;
use ty::{self, TyCtxt};
+use errors::DiagnosticBuilder;
+use rustc::lint;
+use rustc_data_structures::sync::Lrc;
+use session::Session;
use std::cell::Cell;
use std::mem::replace;
-use rustc_data_structures::sync::Lrc;
+use std::slice;
use syntax::ast;
use syntax::attr;
use syntax::ptr::P;
use syntax_pos::Span;
-use errors::DiagnosticBuilder;
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
-use session::Session;
-use std::slice;
-use rustc::lint;
-use hir::{self, GenericParamsExt};
use hir::intravisit::{self, NestedVisitorMap, Visitor};
+use hir::{self, GenericParamsExt};
/// The origin of a named lifetime definition.
///
tcx: TyCtxt<'a, 'tcx, 'tcx>,
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
- // Deep breath. Our representation for poly trait refs contains a single
- // binder and thus we only allow a single level of quantification. However,
- // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
- // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
- // correct when representing these constraints, we should only introduce one
- // scope. However, we want to support both locations for the quantifier and
- // during lifetime resolution we want precise information (so we can't
- // desugar in an earlier phase).
-
- // SO, if we encounter a quantifier at the outer scope, we set
- // trait_ref_hack to true (and introduce a scope), and then if we encounter
- // a quantifier at the inner scope, we error. If trait_ref_hack is false,
- // then we introduce the scope at the inner quantifier.
-
- // I'm sorry.
+
+ /// Deep breath. Our representation for poly trait refs contains a single
+ /// binder and thus we only allow a single level of quantification. However,
+ /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
+ /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
+ /// correct when representing these constraints, we should only introduce one
+ /// scope. However, we want to support both locations for the quantifier and
+ /// during lifetime resolution we want precise information (so we can't
+ /// desugar in an earlier phase).
+ ///
+ /// SO, if we encounter a quantifier at the outer scope, we set
+ /// trait_ref_hack to true (and introduce a scope), and then if we encounter
+ /// a quantifier at the inner scope, we error. If trait_ref_hack is false,
+ /// then we introduce the scope at the inner quantifier.
+ ///
+ /// I'm sorry.
trait_ref_hack: bool,
- // Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
+ /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
is_in_fn_syntax: bool,
- // List of labels in the function/method currently under analysis.
+ /// List of labels in the function/method currently under analysis.
labels_in_fn: Vec<(ast::Name, Span)>,
- // Cache for cross-crate per-definition object lifetime defaults.
+ /// Cache for cross-crate per-definition object lifetime defaults.
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
- lifetime_uses: DefIdMap<LifetimeUseSet<'tcx>>,
+ lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
}
#[derive(Debug)]
/// we should use for an early-bound region?
next_early_index: u32,
+ /// Flag is set to true if, in this binder, `'_` would be
+ /// equivalent to a "single-use region". This is true on
+ /// impls, but not other kinds of items.
+ track_lifetime_uses: bool,
+
/// Whether or not this binder would serve as the parent
/// binder for abstract types introduced within. For example:
///
is_in_fn_syntax: false,
labels_in_fn: vec![],
xcrate_object_lifetime_defaults: DefIdMap(),
- lifetime_uses: DefIdMap(),
+ lifetime_uses: &mut DefIdMap(),
};
for (_, item) in &krate.items {
visitor.visit_item(item);
| hir::ItemTrait(_, _, ref generics, ..)
| hir::ItemTraitAlias(ref generics, ..)
| hir::ItemImpl(_, _, _, ref generics, ..) => {
+ // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
+ // This is not true for other kinds of items.x
+ let track_lifetime_uses = match item.node {
+ hir::ItemImpl(..) => true,
+ _ => false,
+ };
// These kinds of items have only early bound lifetime parameters.
let mut index = if let hir::ItemTrait(..) = item.node {
1 // Self comes before lifetimes
lifetimes,
next_early_index,
abstract_type_parent: true,
+ track_lifetime_uses,
s: ROOT_SCOPE,
};
self.with(scope, |old_scope, this| {
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- debug!("visit_ty: ty={:?}", ty);
+ debug!("visit_ty: id={:?} ty={:?}", ty.id, ty);
match ty.node {
hir::TyBareFn(ref c) => {
let next_early_index = self.next_early_index();
.collect(),
s: self.scope,
next_early_index,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
self.with(scope, |old_scope, this| {
lifetimes,
next_early_index,
s: this.scope,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
this.with(scope, |_old_scope, this| {
lifetimes,
next_early_index,
s: self.scope,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
self.with(scope, |_old_scope, this| {
lifetimes,
next_early_index,
s: self.scope,
+ track_lifetime_uses: true,
abstract_type_parent: true,
};
self.with(scope, |_old_scope, this| {
lifetimes,
next_early_index,
s: self.scope,
+ track_lifetime_uses: true,
abstract_type_parent: true,
};
self.with(scope, |_old_scope, this| {
.collect(),
s: self.scope,
next_early_index,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
let result = self.with(scope, |old_scope, this| {
.collect(),
s: self.scope,
next_early_index,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
self.with(scope, |old_scope, this| {
}
Scope::Binder {
- ref lifetimes,
- s,
- next_early_index: _,
- abstract_type_parent: _,
+ ref lifetimes, s, ..
} => {
// FIXME (#24278): non-hygienic comparison
if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext {
- tcx, ref mut map, ..
- } = *self;
+ tcx,
+ map,
+ lifetime_uses,
+ ..
+ } = self;
let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
let xcrate_object_lifetime_defaults =
replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
let mut this = LifetimeContext {
- tcx,
- map: *map,
+ tcx: *tcx,
+ map: map,
scope: &wrap_scope,
trait_ref_hack: self.trait_ref_hack,
is_in_fn_syntax: self.is_in_fn_syntax,
labels_in_fn,
xcrate_object_lifetime_defaults,
- lifetime_uses: DefIdMap(),
+ lifetime_uses: lifetime_uses,
};
debug!("entering scope {:?}", this.scope);
f(self.scope, &mut this);
+ this.check_uses_for_lifetimes_defined_by_scope();
debug!("exiting scope {:?}", this.scope);
self.labels_in_fn = this.labels_in_fn;
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
+ }
+
+ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
+ let defined_by = match self.scope {
+ Scope::Binder { lifetimes, .. } => lifetimes,
+ _ => {
+ debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
+ return;
+ }
+ };
- for (def_id, lifetimeuseset) in &this.lifetime_uses {
+ let mut def_ids: Vec<_> = defined_by.values()
+ .flat_map(|region| match region {
+ Region::EarlyBound(_, def_id, _)
+ | Region::LateBound(_, def_id, _)
+ | Region::Free(_, def_id) => Some(*def_id),
+
+ Region::LateBoundAnon(..) | Region::Static => None,
+ })
+ .collect();
+
+ // ensure that we issue lints in a repeatable order
+ def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id));
+
+ for def_id in def_ids {
+ debug!(
+ "check_uses_for_lifetimes_defined_by_scope: def_id = {:?}",
+ def_id,
+ );
+
+ let lifetimeuseset = self.lifetime_uses.remove(&def_id);
+ debug!(
+ "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
+ lifetimeuseset
+ );
match lifetimeuseset {
- &LifetimeUseSet::One(_) => {
- let node_id = this.tcx.hir.as_local_node_id(*def_id).unwrap();
+ Some(LifetimeUseSet::One(_)) => {
+ let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
debug!("node id first={:?}", node_id);
- if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
+ if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
let span = hir_lifetime.span;
let id = hir_lifetime.id;
debug!(
node_id, span, hir_lifetime
);
- this.tcx
+ self.tcx
.struct_span_lint_node(
lint::builtin::SINGLE_USE_LIFETIME,
id,
span,
&format!(
- "lifetime name `{}` only used once",
+ "lifetime parameter `{}` only used once",
hir_lifetime.name.name()
),
)
.emit();
}
}
- _ => {
+ Some(LifetimeUseSet::Many) => {
debug!("Not one use lifetime");
}
+ None => {
+ let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+ if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
+ let span = hir_lifetime.span;
+ let id = hir_lifetime.id;
+
+ self.tcx
+ .struct_span_lint_node(
+ lint::builtin::UNUSED_LIFETIME,
+ id,
+ span,
+ &format!(
+ "lifetime parameter `{}` never used",
+ hir_lifetime.name.name()
+ ),
+ )
+ .emit();
+ }
+ }
}
}
}
next_early_index,
s: self.scope,
abstract_type_parent: true,
+ track_lifetime_uses: false,
};
self.with(scope, move |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
}
Scope::Binder {
- ref lifetimes,
- s,
- next_early_index: _,
- abstract_type_parent: _,
+ ref lifetimes, s, ..
} => {
if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
break Some(def.shifted(late_depth));
inputs: &'tcx [P<hir::Ty>],
output: Option<&'tcx P<hir::Ty>>,
) {
+ debug!("visit_fn_like_elision: enter");
let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
let arg_scope = Scope::Elision {
elide: arg_elide.clone(),
None => return,
};
+ debug!("visit_fn_like_elision: determine output");
+
// Figure out if there's a body we can get argument names from,
// and whether there's a `self` argument (treated specially).
let mut assoc_item_kind = None;
Elide::Error(arg_lifetimes)
};
+ debug!("visit_fn_like_elision: elide={:?}", elide);
+
let scope = Scope::Elision {
elide,
s: self.scope,
};
self.with(scope, |_, this| this.visit_ty(output));
+ debug!("visit_fn_like_elision: exit");
struct GatherLifetimes<'a> {
map: &'a NamedRegionMap,
);
err.emit();
}
- hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
- hir::LifetimeName::Name(_) => {}
+ hir::LifetimeName::Fresh(_)
+ | hir::LifetimeName::Implicit
+ | hir::LifetimeName::Name(_) => {}
}
}
))
.emit();
}
- hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
- hir::LifetimeName::Name(_) => {
+ hir::LifetimeName::Fresh(_)
+ | hir::LifetimeName::Implicit
+ | hir::LifetimeName::Name(_) => {
self.resolve_lifetime_ref(bound);
}
}
}
Scope::Binder {
- ref lifetimes,
- s,
- next_early_index: _,
- abstract_type_parent: _,
+ ref lifetimes, s, ..
} => {
if let Some(&def) = lifetimes.get(&lifetime.name) {
let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
}
}
+ /// Returns true if, in the current scope, replacing `'_` would be
+ /// equivalent to a single-use lifetime.
+ fn track_lifetime_uses(&self) -> bool {
+ let mut scope = self.scope;
+ loop {
+ match *scope {
+ Scope::Root => break false,
+
+ // Inside of items, it depends on the kind of item.
+ Scope::Binder {
+ track_lifetime_uses,
+ ..
+ } => break track_lifetime_uses,
+
+ // Inside a body, `'_` will use an inference variable,
+ // should be fine.
+ Scope::Body { .. } => break true,
+
+ // A lifetime only used in a fn argument could as well
+ // be replaced with `'_`, as that would generate a
+ // fresh name, too.
+ Scope::Elision {
+ elide: Elide::FreshLateAnon(_),
+ ..
+ } => break true,
+
+ // In the return type or other such place, `'_` is not
+ // going to make a fresh name, so we cannot
+ // necessarily replace a single-use lifetime with
+ // `'_`.
+ Scope::Elision {
+ elide: Elide::Exact(_),
+ ..
+ } => break false,
+ Scope::Elision {
+ elide: Elide::Error(_),
+ ..
+ } => break false,
+
+ Scope::ObjectLifetimeDefault { s, .. } => scope = s,
+ }
+ }
+ }
+
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
if lifetime_ref.id == ast::DUMMY_NODE_ID {
span_bug!(
| Region::LateBound(_, def_id, _)
| Region::EarlyBound(_, def_id, _) => {
// A lifetime declared by the user.
- if !self.lifetime_uses.contains_key(&def_id) {
- self.lifetime_uses
- .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+ let def_local_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+ if def_local_id == lifetime_ref.id {
+ // This is weird. Because the HIR defines a
+ // lifetime *definition* as wrapping a Lifetime,
+ // we wind up invoking this method also for the
+ // definitions in some cases (notably
+ // higher-ranked types). This means that a
+ // lifetime with one use (e.g., `for<'a> fn(&'a
+ // u32)`) wind up being counted as two uses. To
+ // avoid that, we just ignore the lifetime that
+ // corresponds to the definition.
} else {
- self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+ let track_lifetime_uses = self.track_lifetime_uses();
+ debug!(
+ "insert_lifetime: track_lifetime_uses={}",
+ track_lifetime_uses
+ );
+ if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) {
+ debug!("insert_lifetime: first use of {:?}", def_id);
+ self.lifetime_uses
+ .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+ } else {
+ debug!("insert_lifetime: many uses of {:?}", def_id);
+ self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+ }
}
}
}
"unions with `Drop` implementations are unstable");
} else {
let param_env = self.tcx.param_env(def_id);
- if !param_env.can_type_implement_copy(self.tcx, ty, item.span).is_ok() {
+ if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
emit_feature_err(&self.tcx.sess.parse_sess,
"untagged_unions", item.span, GateIssue::Language,
"unions with non-`Copy` fields are unstable");
pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
-pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
+pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue};
use std::collections::BTreeMap;
use std::fmt;
use ty::layout::{self, Align, HasDataLayout};
use middle::region;
use std::iter;
+use std::io;
use syntax::ast::Mutability;
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
+use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Lock {
}
}
-#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct Allocation {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer
}
impl Allocation {
- pub fn from_bytes(slice: &[u8]) -> Self {
+ pub fn from_bytes(slice: &[u8], align: Align) -> Self {
let mut undef_mask = UndefMask::new(0);
undef_mask.grow(slice.len() as u64, true);
Self {
bytes: slice.to_owned(),
relocations: BTreeMap::new(),
undef_mask,
- align: Align::from_bytes(1, 1).unwrap(),
+ align,
runtime_mutability: Mutability::Immutable,
}
}
+
+ pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
+ Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
+ }
+
+ pub fn undef(size: u64, align: Align) -> Self {
+ assert_eq!(size as usize as u64, size);
+ Allocation {
+ bytes: vec![0; size as usize],
+ relocations: BTreeMap::new(),
+ undef_mask: UndefMask::new(size),
+ align,
+ runtime_mutability: Mutability::Immutable,
+ }
+ }
+}
+
+impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
+
+////////////////////////////////////////////////////////////////////////////////
+// Methods to access integers in the target endianness
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn write_target_uint(
+ endianness: layout::Endian,
+ mut target: &mut [u8],
+ data: u128,
+) -> Result<(), io::Error> {
+ let len = target.len();
+ match endianness {
+ layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
+ layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
+ }
+}
+
+pub fn write_target_int(
+ endianness: layout::Endian,
+ mut target: &mut [u8],
+ data: i128,
+) -> Result<(), io::Error> {
+ let len = target.len();
+ match endianness {
+ layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
+ layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
+ }
+}
+
+pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
+ match endianness {
+ layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
+ layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
+ }
}
////////////////////////////////////////////////////////////////////////////////
use ty::layout::{Align, HasDataLayout};
use ty;
-use super::{EvalResult, MemoryPointer, PointerArithmetic};
+use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
+
+/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which
+/// matches Value's optimizations for easy conversions between these two types
+#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
+pub enum ConstValue<'tcx> {
+ // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
+ ByVal(PrimVal),
+ // Used only for types with layout::abi::ScalarPair
+ ByValPair(PrimVal, PrimVal),
+ // Used only for the remaining cases
+ ByRef(&'tcx Allocation),
+}
+
+impl<'tcx> ConstValue<'tcx> {
+ #[inline]
+ pub fn from_byval_value(val: Value) -> Self {
+ match val {
+ Value::ByRef(..) => bug!(),
+ Value::ByValPair(a, b) => ConstValue::ByValPair(a, b),
+ Value::ByVal(val) => ConstValue::ByVal(val),
+ }
+ }
+
+ #[inline]
+ pub fn to_byval_value(&self) -> Option<Value> {
+ match *self {
+ ConstValue::ByRef(..) => None,
+ ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)),
+ ConstValue::ByVal(val) => Some(Value::ByVal(val)),
+ }
+ }
+
+ #[inline]
+ pub fn from_primval(val: PrimVal) -> Self {
+ ConstValue::ByVal(val)
+ }
+
+ #[inline]
+ pub fn to_primval(&self) -> Option<PrimVal> {
+ match *self {
+ ConstValue::ByRef(..) => None,
+ ConstValue::ByValPair(..) => None,
+ ConstValue::ByVal(val) => Some(val),
+ }
+ }
+
+ #[inline]
+ pub fn to_bits(&self) -> Option<u128> {
+ match self.to_primval() {
+ Some(PrimVal::Bytes(val)) => Some(val),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_ptr(&self) -> Option<MemoryPointer> {
+ match self.to_primval() {
+ Some(PrimVal::Ptr(ptr)) => Some(ptr),
+ _ => None,
+ }
+ }
+}
/// A `Value` represents a single self-contained Rust value.
///
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html
use graphviz::IntoCow;
-use middle::const_val::ConstVal;
use middle::region;
use rustc_data_structures::sync::{Lrc};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
span,
ty,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty
- })
+ value: ty::Const::zero_sized(tcx, ty),
},
})
}
}
/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
-fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
- use middle::const_val::ConstVal::*;
+pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
+ use middle::const_val::ConstVal;
match const_val.val {
- Unevaluated(..) => write!(fmt, "{:?}", const_val),
- Value(val) => print_miri_value(val, const_val.ty, fmt),
+ ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
+ ConstVal::Value(val) => {
+ if let Some(value) = val.to_byval_value() {
+ print_miri_value(value, const_val.ty, fmt)
+ } else {
+ write!(fmt, "{:?}:{}", val, const_val.ty)
+ }
+ },
}
}
PlaceTy::Ty {
ty: match ty.sty {
ty::TyArray(inner, size) => {
- let size = size.val.unwrap_u64();
+ let size = size.unwrap_usize(tcx);
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}
ret
}
+ /// Returns the number of query threads that should be used for this
+ /// compilation
+ pub fn query_threads_from_opts(opts: &config::Options) -> usize {
+ opts.debugging_opts.query_threads.unwrap_or(1)
+ }
+
/// Returns the number of query threads that should be used for this
/// compilation
pub fn query_threads(&self) -> usize {
- self.opts.debugging_opts.query_threads.unwrap_or(1)
+ Self::query_threads_from_opts(&self.opts)
}
/// Returns the number of codegen units that should be used for this
// we move over to lazy normalization *anyway*.
let fulfill_cx = FulfillmentContext::new_ignoring_regions();
- let predicates = match fully_normalize_with_fulfillcx(
+ let predicates = match fully_normalize(
&infcx,
fulfill_cx,
cause,
})
}
-pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- cause: ObligationCause<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- value: &T)
- -> Result<T, Vec<FulfillmentError<'tcx>>>
- where T : TypeFoldable<'tcx>
-{
- // FIXME (@jroesch) ISSUE 26721
- // I'm not sure if this is a bug or not, needs further investigation.
- // It appears that by reusing the fulfillment_cx here we incur more
- // obligations and later trip an assertion on regionck.rs line 337.
- //
- // The two possibilities I see is:
- // - normalization is not actually fully happening and we
- // have a bug else where
- // - we are adding a duplicate bound into the list causing
- // its size to change.
- //
- // I think we should probably land this refactor and then come
- // back to this is a follow-up patch.
- let fulfillcx = FulfillmentContext::new();
- fully_normalize_with_fulfillcx(infcx, fulfillcx, cause, param_env, value)
-}
-
-pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>(
+pub fn fully_normalize<'a, 'gcx, 'tcx, T>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
mut fulfill_cx: FulfillmentContext<'tcx>,
cause: ObligationCause<'tcx>,
}
debug!("fully_normalize: select_all_or_error start");
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => { }
- Err(e) => {
- debug!("fully_normalize: error={:?}", e);
- return Err(e);
- }
- }
+ fulfill_cx.select_all_or_error(infcx)?;
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
// that this always succeeds.
let impl1_trait_ref =
match traits::fully_normalize(&infcx,
+ FulfillmentContext::new(),
ObligationCause::dummy(),
penv,
&impl1_trait_ref) {
use std::intrinsics;
use ty::{self, Ty, TyCtxt};
use ty::subst::Substs;
+use mir::interpret::Allocation;
/// The shorthand encoding uses an enum's variant index `usize`
/// and is offset by this value so it never matches a real variant.
Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
}
+#[inline]
+pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D)
+ -> Result<&'tcx Allocation, D::Error>
+ where D: TyDecoder<'a, 'tcx>,
+ 'tcx: 'a,
+{
+ Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+}
+
#[macro_export]
macro_rules! __impl_decoder_methods {
($($name:ident -> $ty:ty;)*) => {
decode_const(self)
}
}
+
+ impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
+ for $DecoderName<$($typaram),*> {
+ fn specialized_decode(
+ &mut self
+ ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> {
+ decode_allocation(self)
+ }
+ }
}
}
}
use ich::{StableHashingContext, NodeIdHashingMode};
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use infer::outlives::free_region_map::FreeRegionMap;
-use middle::const_val::ConstVal;
-use middle::cstore::{CrateStore, LinkMeta};
+use middle::cstore::{CrateStoreDyn, LinkMeta};
use middle::cstore::EncodedMetadata;
use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{self, Mir, interpret};
-use mir::interpret::{Value, PrimVal};
use ty::subst::{Kind, Substs, Subst};
use ty::ReprOptions;
use ty::Instance;
}
}
- /// Intern a type. global_interners is Some only if this is
- /// a local interner and global_interners is its counterpart.
- fn intern_ty(&self, st: TypeVariants<'tcx>,
- global_interners: Option<&CtxtInterners<'gcx>>)
- -> Ty<'tcx> {
- let ty = {
- let mut interner = self.type_.borrow_mut();
+ /// Intern a type
+ fn intern_ty(
+ local: &CtxtInterners<'tcx>,
+ global: &CtxtInterners<'gcx>,
+ st: TypeVariants<'tcx>
+ ) -> Ty<'tcx> {
+ let flags = super::flags::FlagComputation::for_sty(&st);
+
+ // HACK(eddyb) Depend on flags being accurate to
+ // determine that all contents are in the global tcx.
+ // See comments on Lift for why we can't use that.
+ if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
+ let mut interner = local.type_.borrow_mut();
if let Some(&Interned(ty)) = interner.get(&st) {
return ty;
}
- let global_interner = global_interners.map(|interners| {
- (interners.type_.borrow_mut(), &interners.arena)
- });
- if let Some((ref type_, _)) = global_interner {
- if let Some(&Interned(ty)) = type_.get(&st) {
- return ty;
- }
- }
- let flags = super::flags::FlagComputation::for_sty(&st);
let ty_struct = TyS {
sty: st,
flags: flags.flags,
region_depth: flags.depth,
};
- // HACK(eddyb) Depend on flags being accurate to
- // determine that all contents are in the global tcx.
- // See comments on Lift for why we can't use that.
- if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
- if let Some((mut type_, arena)) = global_interner {
- let ty_struct: TyS<'gcx> = unsafe {
- mem::transmute(ty_struct)
- };
- let ty: Ty<'gcx> = arena.alloc(ty_struct);
- type_.insert(Interned(ty));
- return ty;
- }
- } else {
- // Make sure we don't end up with inference
- // types/regions in the global tcx.
- if global_interner.is_none() {
- drop(interner);
- bug!("Attempted to intern `{:?}` which contains \
- inference types/regions in the global type context",
- &ty_struct);
- }
+ // Make sure we don't end up with inference
+ // types/regions in the global interner
+ if local as *const _ as usize == global as *const _ as usize {
+ bug!("Attempted to intern `{:?}` which contains \
+ inference types/regions in the global type context",
+ &ty_struct);
}
// Don't be &mut TyS.
- let ty: Ty<'tcx> = self.arena.alloc(ty_struct);
+ let ty: Ty<'tcx> = local.arena.alloc(ty_struct);
interner.insert(Interned(ty));
ty
- };
+ } else {
+ let mut interner = global.type_.borrow_mut();
+ if let Some(&Interned(ty)) = interner.get(&st) {
+ return ty;
+ }
- debug!("Interned type: {:?} Pointer: {:?}",
- ty, ty as *const TyS);
- ty
- }
+ let ty_struct = TyS {
+ sty: st,
+ flags: flags.flags,
+ region_depth: flags.depth,
+ };
+
+ // This is safe because all the types the ty_struct can point to
+ // already is in the global arena
+ let ty_struct: TyS<'gcx> = unsafe {
+ mem::transmute(ty_struct)
+ };
+ // Don't be &mut TyS.
+ let ty: Ty<'gcx> = global.arena.alloc(ty_struct);
+ interner.insert(Interned(ty));
+ ty
+ }
+ }
}
pub struct CommonTypes<'tcx> {
impl<'tcx> CommonTypes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
- let mk = |sty| interners.intern_ty(sty, None);
+ let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
let mk_region = |r| {
if let Some(r) = interners.region.borrow().get(&r) {
return r.0;
global_arenas: &'tcx GlobalArenas<'tcx>,
global_interners: CtxtInterners<'tcx>,
- cstore: &'tcx dyn CrateStore,
+ cstore: &'tcx CrateStoreDyn,
pub sess: &'tcx Session,
return alloc_id;
}
// create an allocation that just contains these bytes
- let alloc = interpret::Allocation::from_bytes(bytes);
+ let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
let alloc = self.intern_const_alloc(alloc);
// the next unique id
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
/// reference to the context, to allow formatting values that need it.
pub fn create_and_enter<F, R>(s: &'tcx Session,
- cstore: &'tcx dyn CrateStore,
+ cstore: &'tcx CrateStoreDyn,
local_providers: ty::maps::Providers<'tcx>,
extern_providers: ty::maps::Providers<'tcx>,
arenas: &'tcx AllArenas<'tcx>,
/// in librustc otherwise. It is used to when diagnostic messages are
/// emitted and stores them in the current query, if there is one.
fn track_diagnostic(diagnostic: &Diagnostic) {
- with_context(|context| {
- if let Some(ref query) = context.query {
- query.diagnostics.lock().push(diagnostic.clone());
+ with_context_opt(|icx| {
+ if let Some(icx) = icx {
+ if let Some(ref query) = icx.query {
+ query.diagnostics.lock().push(diagnostic.clone());
+ }
}
})
}
$keep_in_local_tcx:expr) -> $ty:ty) => {
impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
- {
- let key = ($alloc_to_key)(&v);
- if let Some(i) = self.interners.$name.borrow().get(key) {
- return i.0;
- }
- if !self.is_global() {
- if let Some(i) = self.global_interners.$name.borrow().get(key) {
- return i.0;
- }
- }
- }
+ let key = ($alloc_to_key)(&v);
// HACK(eddyb) Depend on flags being accurate to
// determine that all contents are in the global tcx.
// See comments on Lift for why we can't use that.
- if !($keep_in_local_tcx)(&v) {
- if !self.is_global() {
- let v = unsafe {
- mem::transmute(v)
- };
- let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
- self.global_interners.$name.borrow_mut().insert(Interned(i));
- return i;
+ if ($keep_in_local_tcx)(&v) {
+ let mut interner = self.interners.$name.borrow_mut();
+ if let Some(&Interned(v)) = interner.get(key) {
+ return v;
}
- } else {
+
// Make sure we don't end up with inference
// types/regions in the global tcx.
if self.is_global() {
inference types/regions in the global type context",
v);
}
- }
- let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
- self.interners.$name.borrow_mut().insert(Interned(i));
- i
+ let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
+ interner.insert(Interned(i));
+ i
+ } else {
+ let mut interner = self.global_interners.$name.borrow_mut();
+ if let Some(&Interned(v)) = interner.get(key) {
+ return v;
+ }
+
+ // This transmutes $alloc<'tcx> to $alloc<'gcx>
+ let v = unsafe {
+ mem::transmute(v)
+ };
+ let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
+ interner.insert(Interned(i));
+ i
+ }
}
}
}
self.mk_fn_ptr(converted_sig)
}
- // Interns a type/name combination, stores the resulting box in cx.interners,
- // and returns the box as cast to an unsafe ptr (see comments for Ty above).
- pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
- let global_interners = if !self.is_global() {
- Some(&self.global_interners)
- } else {
- None
- };
- self.interners.intern_ty(st, global_interners)
+ pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
+ CtxtInterners::intern_ty(&self.interners, &self.global_interners, st)
}
pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
}
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
- self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
- ty: self.types.usize
- })))
+ self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n)))
}
pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
ty::TyArray(_, n) => {
- match n.val.to_raw_bits() {
+ match n.assert_usize(tcx) {
Some(n) => format!("array of {} elements", n),
None => "array".to_string(),
}
}))
},
TyArray(ty, len) => {
- match len.val.to_raw_bits() {
+ match len.assert_usize(tcx) {
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
}
let element = self.layout_of(element)?;
- let count = count.val.unwrap_u64();
+ let count = count.unwrap_usize(tcx);
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
use dep_graph::SerializedDepNodeIndex;
use dep_graph::DepNode;
use hir::def_id::{CrateNum, DefId, DefIndex};
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::Substs;
}
}
+impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> {
+ fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String {
+ format!("converting value `{:?}` ({}) to an allocation", val, ty)
+ }
+}
+
impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
format!("erasing regions from `{:?}`", ty)
}
}
+impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
+ fn map_crate(&self) -> CrateNum {
+ LOCAL_CRATE
+ }
+ fn default_span(&self, _: TyCtxt) -> Span {
+ DUMMY_SP
+ }
+}
+
impl<'tcx> Key for Ty<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
use middle::const_val::EvalResult;
use mir::mono::{CodegenUnit, Stats};
use mir;
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, Allocation, ConstValue};
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::{self, Vtable};
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> EvalResult<'tcx>,
+ /// Converts a constant value to an constant allocation
+ [] fn const_value_to_allocation: const_value_to_allocation(
+ (ConstValue<'tcx>, Ty<'tcx>)
+ ) -> &'tcx Allocation,
+
[] fn check_match: CheckMatch(DefId)
-> Result<(), ErrorReported>,
DepConstructor::EraseRegionsTy { ty }
}
+fn const_value_to_allocation<'tcx>(
+ (val, ty): (ConstValue<'tcx>, Ty<'tcx>)
+) -> DepConstructor<'tcx> {
+ DepConstructor::ConstValueToAllocation { val, ty }
+}
+
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
DepConstructor::TypeParamPredicates {
item_id,
DepKind::FulfillObligation |
DepKind::VtableMethods |
DepKind::EraseRegionsTy |
+ DepKind::ConstValueToAllocation |
DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions |
DepKind::DropckOutlives |
use ich::Fingerprint;
use ich::StableHashingContext;
use infer::canonical::{Canonical, Canonicalize};
-use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::privacy::AccessLevels;
use middle::resolve_lifetime::ObjectLifetimeDefault;
use mir::Mir;
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
use mir::GeneratorLayout;
use session::CrateDisambiguator;
use traits::{self, Reveal};
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
- Ok(&ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
- ty,
- }) => {
- trace!("discriminants: {} ({:?})", b, repr_type);
- Some(Discr {
- val: b,
- ty,
- })
- },
- Ok(&ty::Const {
- val: ConstVal::Value(other),
- ..
- }) => {
- info!("invalid enum discriminant: {:#?}", other);
- ::middle::const_val::struct_error(
- tcx,
- tcx.def_span(expr_did),
- "constant evaluation of enum discriminant resulted in non-integer",
- ).emit();
- None
+ Ok(val) => {
+ // FIXME: Find the right type and use it instead of `val.ty` here
+ if let Some(b) = val.assert_bits(val.ty) {
+ trace!("discriminants: {} ({:?})", b, repr_type);
+ Some(Discr {
+ val: b,
+ ty: val.ty,
+ })
+ } else {
+ info!("invalid enum discriminant: {:#?}", val);
+ ::middle::const_val::struct_error(
+ tcx,
+ tcx.def_span(expr_did),
+ "constant evaluation of enum discriminant resulted in non-integer",
+ ).emit();
+ None
+ }
}
Err(err) => {
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
}
None
}
- _ => span_bug!(tcx.def_span(expr_did), "const eval "),
}
}
use ty::subst::{Kind, UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::error::{ExpectedFound, TypeError};
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
use util::common::ErrorReported;
use std::rc::Rc;
use std::iter;
assert_eq!(sz_a.ty, tcx.types.usize);
assert_eq!(sz_b.ty, tcx.types.usize);
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
+ if let Some(s) = x.assert_usize(tcx) {
+ return Ok(s);
+ }
match x.val {
- ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
ConstVal::Unevaluated(def_id, substs) => {
// FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty();
instance,
promoted: None
};
- match tcx.const_eval(param_env.and(cid)) {
- Ok(&ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
- ..
- }) => {
- assert_eq!(b as u64 as u128, b);
- return Ok(b as u64);
- }
- _ => {}
+ if let Some(s) = tcx.const_eval(param_env.and(cid))
+ .ok()
+ .map(|c| c.unwrap_usize(tcx)) {
+ return Ok(s)
}
}
},
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
use util::captures::Captures;
+use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};
use std::iter;
use std::cmp::Ordering;
pub val: ConstVal<'tcx>,
}
+impl<'tcx> Const<'tcx> {
+ pub fn unevaluated(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx Substs<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ tcx.mk_const(Const {
+ val: ConstVal::Unevaluated(def_id, substs),
+ ty,
+ })
+ }
+
+ #[inline]
+ pub fn from_const_val(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: ConstVal<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ tcx.mk_const(Const {
+ val,
+ ty,
+ })
+ }
+
+ #[inline]
+ pub fn from_const_value(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: ConstValue<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_val(tcx, ConstVal::Value(val), ty)
+ }
+
+ #[inline]
+ pub fn from_alloc(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ alloc: &'tcx Allocation,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty)
+ }
+
+ #[inline]
+ pub fn from_byval_value(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: Value,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty)
+ }
+
+ #[inline]
+ pub fn from_primval(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: PrimVal,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_value(tcx, ConstValue::from_primval(val), ty)
+ }
+
+ #[inline]
+ pub fn from_bits(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: u128,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_primval(tcx, PrimVal::Bytes(val), ty)
+ }
+
+ #[inline]
+ pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+ Self::from_primval(tcx, PrimVal::Undef, ty)
+ }
+
+ #[inline]
+ pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
+ Self::from_bits(tcx, v as u128, tcx.types.bool)
+ }
+
+ #[inline]
+ pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
+ Self::from_bits(tcx, n as u128, tcx.types.usize)
+ }
+
+ #[inline]
+ pub fn to_bits(&self, ty: Ty<'_>) -> Option<u128> {
+ if self.ty != ty {
+ return None;
+ }
+ match self.val {
+ ConstVal::Value(val) => val.to_bits(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_ptr(&self) -> Option<MemoryPointer> {
+ match self.val {
+ ConstVal::Value(val) => val.to_ptr(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_primval(&self) -> Option<PrimVal> {
+ match self.val {
+ ConstVal::Value(val) => val.to_primval(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn assert_bits(&self, ty: Ty<'_>) -> Option<u128> {
+ assert_eq!(self.ty, ty);
+ match self.val {
+ ConstVal::Value(val) => val.to_bits(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
+ self.assert_bits(tcx.types.bool).and_then(|v| match v {
+ 0 => Some(false),
+ 1 => Some(true),
+ _ => None,
+ })
+ }
+
+ #[inline]
+ pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
+ self.assert_bits(tcx.types.usize).map(|v| v as u64)
+ }
+
+ #[inline]
+ pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 {
+ match self.assert_bits(ty) {
+ Some(val) => val,
+ None => bug!("expected bits of {}, got {:#?}", ty, self),
+ }
+ }
+
+ #[inline]
+ pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
+ match self.assert_usize(tcx) {
+ Some(val) => val,
+ None => bug!("expected constant usize, got {:#?}", self),
+ }
+ }
+}
+
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
use hir;
use ich::NodeIdHashingMode;
use middle::const_val::ConstVal;
-use traits;
+use traits::{self, ObligationCause};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeVisitor;
use ty::subst::UnpackedKind;
use ty::layout::{Integer, IntegerExt};
use util::common::ErrorReported;
use middle::lang_items;
-use mir::interpret::{Value, PrimVal};
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
HashStable};
}
-#[derive(Copy, Clone)]
+#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
- InfrigingField(&'tcx ty::FieldDef),
+ InfrigingFields(Vec<&'tcx ty::FieldDef>),
NotAnAdt,
HasDestructor,
}
impl<'tcx> ty::ParamEnv<'tcx> {
pub fn can_type_implement_copy<'a>(self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- self_type: Ty<'tcx>, span: Span)
+ self_type: Ty<'tcx>)
-> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt().enter(|infcx| {
_ => return Err(CopyImplementationError::NotAnAdt),
};
- let field_implements_copy = |field: &ty::FieldDef| {
- let cause = traits::ObligationCause::dummy();
- match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) {
- Ok(ty) => !infcx.type_moves_by_default(self, ty, span),
- Err(..) => false,
- }
- };
-
+ let mut infringing = Vec::new();
for variant in &adt.variants {
for field in &variant.fields {
- if !field_implements_copy(field) {
- return Err(CopyImplementationError::InfrigingField(field));
+ let span = tcx.def_span(field.did);
+ let ty = field.ty(tcx, substs);
+ if ty.references_error() {
+ continue;
}
+ let cause = ObligationCause { span, ..ObligationCause::dummy() };
+ let ctx = traits::FulfillmentContext::new();
+ match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
+ Ok(ty) => if infcx.type_moves_by_default(self, ty, span) {
+ infringing.push(field);
+ }
+ Err(errors) => {
+ infcx.report_fulfillment_errors(&errors, None, false);
+ }
+ };
}
}
-
+ if !infringing.is_empty() {
+ return Err(CopyImplementationError::InfrigingFields(infringing));
+ }
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
TyArray(_, n) => {
self.hash_discriminant_u8(&n.val);
match n.val {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
+ ConstVal::Value(alloc) => self.hash(alloc),
ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
- _ => bug!("arrays should not have {:?} as length", n)
}
}
TyRawPtr(m) => self.hash(m.mutbl),
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use util::nodemap::FxHashSet;
-use mir::interpret::{Value, PrimVal};
use std::cell::Cell;
use std::fmt;
TyArray(ty, sz) => {
print!(f, cx, write("["), print(ty), write("; "))?;
match sz.val {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
- write!(f, "{}", sz)?;
- }
+ ConstVal::Value(..) => ty::tls::with(|tcx| {
+ write!(f, "{}", sz.unwrap_usize(tcx))
+ })?,
ConstVal::Unevaluated(_def_id, _substs) => {
write!(f, "_")?;
}
- _ => {
- write!(f, "{:?}", sz)?;
- }
}
write!(f, "]")
}
cfg-if = "0.1.2"
stable_deref_trait = "1.0.0"
parking_lot_core = "0.2.8"
+rustc-rayon = "0.1.0"
[dependencies.parking_lot]
version = "0.5"
}
impl<Node: Idx> fmt::Debug for DominatorTree<Node> {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&DominatorTreeNode {
tree: self,
node: self.root,
}
impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let subtrees: Vec<_> = self.tree
.children(self.node)
.iter()
#[macro_use]
extern crate cfg_if;
extern crate stable_deref_trait;
+extern crate rustc_rayon as rayon;
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
where O: Debug,
T: Debug,
{
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"OwningRef {{ owner: {:?}, reference: {:?} }}",
self.owner(),
where O: Debug,
T: Debug,
{
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"OwningRefMut {{ owner: {:?}, reference: {:?} }}",
self.owner(),
where O: Sync, for<'a> (&'a mut T): Sync {}
impl Debug for Erased {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Erased>",)
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true.
+//! This module defines types which are thread safe if cfg!(parallel_queries) is true.
//!
//! `Lrc` is an alias of either Rc or Arc.
//!
use std::ops::{Deref, DerefMut};
use owning_ref::{Erased, OwningRef};
+pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+ where A: FnOnce() -> RA,
+ B: FnOnce() -> RB
+{
+ (oper_a(), oper_b())
+}
+
+pub struct SerialScope;
+
+impl SerialScope {
+ pub fn spawn<F>(&self, f: F)
+ where F: FnOnce(&SerialScope)
+ {
+ f(self)
+ }
+}
+
+pub fn serial_scope<F, R>(f: F) -> R
+ where F: FnOnce(&SerialScope) -> R
+{
+ f(&SerialScope)
+}
+
cfg_if! {
if #[cfg(not(parallel_queries))] {
pub auto trait Send {}
}
}
+ pub use self::serial_join as join;
+ pub use self::serial_scope as scope;
+
+ pub use std::iter::Iterator as ParallelIterator;
+
+ pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
+ t.into_iter()
+ }
+
pub type MetadataRef = OwningRef<Box<Erased>, [u8]>;
pub use std::rc::Rc as Lrc;
+ pub use std::rc::Weak as Weak;
pub use std::cell::Ref as ReadGuard;
pub use std::cell::RefMut as WriteGuard;
pub use std::cell::RefMut as LockGuard;
pub use parking_lot::MutexGuard as LockGuard;
pub use std::sync::Arc as Lrc;
+ pub use std::sync::Weak as Weak;
pub use self::Lock as MTLock;
use parking_lot::RwLock as InnerRwLock;
use std::thread;
+ pub use rayon::{join, scope};
+
+ pub use rayon::iter::ParallelIterator;
+ use rayon::iter::IntoParallelIterator;
+
+ pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter {
+ t.into_par_iter()
+ }
pub type MetadataRef = OwningRef<Box<Erased + Send + Sync>, [u8]>;
graphviz = { path = "../libgraphviz" }
log = "0.4"
env_logger = { version = "0.5", default-features = false }
+rustc-rayon = "0.1.0"
+scoped-tls = { version = "0.1.1", features = ["nightly"] }
rustc = { path = "../librustc" }
rustc_allocator = { path = "../librustc_allocator" }
rustc_target = { path = "../librustc_target" }
use rustc::session::search_paths::PathKind;
use rustc::lint;
use rustc::middle::{self, reachable, resolve_lifetime, stability};
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
use rustc::traits;
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
use std::sync::mpsc;
use syntax::{self, ast, attr, diagnostics, visit};
use syntax::ext::base::ExtCtxt;
use profile;
+#[cfg(not(parallel_queries))]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+ opts: config::Options,
+ f: F
+) -> R {
+ f(opts)
+}
+
+#[cfg(parallel_queries)]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+ opts: config::Options,
+ f: F
+) -> R {
+ use syntax;
+ use syntax_pos;
+ use rayon::{ThreadPoolBuilder, ThreadPool};
+
+ let config = ThreadPoolBuilder::new().num_threads(Session::query_threads_from_opts(&opts))
+ .stack_size(16 * 1024 * 1024);
+
+ let with_pool = move |pool: &ThreadPool| {
+ pool.install(move || f(opts))
+ };
+
+ syntax::GLOBALS.with(|syntax_globals| {
+ syntax_pos::GLOBALS.with(|syntax_pos_globals| {
+ // The main handler run for each Rayon worker thread and sets up
+ // the thread local rustc uses. syntax_globals and syntax_pos_globals are
+ // captured and set on the new threads. ty::tls::with_thread_locals sets up
+ // thread local callbacks from libsyntax
+ let main_handler = move |worker: &mut FnMut()| {
+ syntax::GLOBALS.set(syntax_globals, || {
+ syntax_pos::GLOBALS.set(syntax_pos_globals, || {
+ ty::tls::with_thread_locals(|| {
+ worker()
+ })
+ })
+ })
+ };
+
+ ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap()
+ })
+ })
+}
+
pub fn compile_input(
trans: Box<TransCrate>,
sess: &Session,
trans: &TransCrate,
control: &CompileController,
sess: &'tcx Session,
- cstore: &'tcx CrateStore,
+ cstore: &'tcx CrateStoreDyn,
hir_map: hir_map::Map<'tcx>,
mut analysis: ty::CrateAnalysis,
resolutions: Resolutions,
#![feature(rustc_stack_internals)]
#![feature(no_debug)]
+#![recursion_limit="256"]
+
extern crate arena;
extern crate getopts;
extern crate graphviz;
extern crate env_logger;
#[cfg(unix)]
extern crate libc;
+extern crate rustc_rayon as rayon;
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_target;
extern crate rustc_traits;
extern crate rustc_trans_utils;
extern crate rustc_typeck;
+extern crate scoped_tls;
extern crate serialize;
#[macro_use]
extern crate log;
use rustc_resolve as resolve;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
use rustc_data_structures::OnDrop;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::CompileIncomplete;
// See comments on CompilerCalls below for details about the callbacks argument.
// The FileLoader provides a way to load files from sources other than the file system.
pub fn run_compiler<'a>(args: &[String],
- callbacks: &mut CompilerCalls<'a>,
+ callbacks: &mut (CompilerCalls<'a> + sync::Send),
file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
emitter_dest: Option<Box<Write + Send>>)
-> (CompileResult, Option<Session>)
{
syntax::with_globals(|| {
- run_compiler_impl(args, callbacks, file_loader, emitter_dest)
+ let matches = match handle_options(args) {
+ Some(matches) => matches,
+ None => return (Ok(()), None),
+ };
+
+ let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+
+ driver::spawn_thread_pool(sopts, |sopts| {
+ run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
+ })
})
}
-fn run_compiler_impl<'a>(args: &[String],
- callbacks: &mut CompilerCalls<'a>,
- file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
- emitter_dest: Option<Box<Write + Send>>)
- -> (CompileResult, Option<Session>)
-{
+fn run_compiler_with_pool<'a>(
+ matches: getopts::Matches,
+ sopts: config::Options,
+ cfg: ast::CrateConfig,
+ callbacks: &mut (CompilerCalls<'a> + sync::Send),
+ file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
+ emitter_dest: Option<Box<Write + Send>>
+) -> (CompileResult, Option<Session>) {
macro_rules! do_or_return {($expr: expr, $sess: expr) => {
match $expr {
Compilation::Stop => return (Ok(()), $sess),
}
}}
- let matches = match handle_options(args) {
- Some(matches) => matches,
- None => return (Ok(()), None),
- };
-
- let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
-
let descriptions = diagnostics_registry();
do_or_return!(callbacks.early_callback(&matches,
use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
use rustc::cfg;
use rustc::cfg::graphviz::LabelledCFG;
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
use rustc::session::Session;
use rustc::session::config::{Input, OutputFilenames};
use rustc_borrowck as borrowck;
}
fn call_with_pp_support_hir<'tcx, A, F>(&self,
sess: &'tcx Session,
- cstore: &'tcx CrateStore,
+ cstore: &'tcx CrateStoreDyn,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
}
pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
- cstore: &'tcx CrateStore,
+ cstore: &'tcx CrateStoreDyn,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
// with a different callback than the standard driver, so that isn't easy.
// Instead, we call that function ourselves.
fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
- cstore: &'a CrateStore,
+ cstore: &'a CrateStoreDyn,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
where F: FnOnce(Env)
{
syntax::with_globals(|| {
- test_env_impl(source_string, args, body)
+ let mut options = config::basic_options();
+ options.debugging_opts.verbose = true;
+ options.unstable_features = UnstableFeatures::Allow;
+
+ driver::spawn_thread_pool(options, |options| {
+ test_env_with_pool(options, source_string, args, body)
+ })
});
}
-fn test_env_impl<F>(source_string: &str,
- (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
- body: F)
+fn test_env_with_pool<F>(
+ options: config::Options,
+ source_string: &str,
+ (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
+ body: F
+)
where F: FnOnce(Env)
{
- let mut options = config::basic_options();
- options.debugging_opts.verbose = true;
- options.unstable_features = UnstableFeatures::Allow;
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
-
let sess = session::build_session_(options,
None,
diagnostic_handler,
}
impl fmt::Display for FatalError {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "parser fatal error")
}
}
pub struct ExplicitBug;
impl fmt::Display for ExplicitBug {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "parser internal bug")
}
}
pub use persist::load_dep_graph;
pub use persist::load_query_result_cache;
pub use persist::LoadResult;
+pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
pub use persist::save_dep_graph;
-pub use persist::save_trans_partition;
-pub use persist::save_work_products;
+pub use persist::save_work_product_index;
pub use persist::in_incr_comp_dir;
pub use persist::prepare_session_directory;
pub use persist::finalize_session_directory;
pub use self::load::load_query_result_cache;
pub use self::load::LoadResult;
pub use self::save::save_dep_graph;
-pub use self::save::save_work_products;
-pub use self::work_product::save_trans_partition;
+pub use self::save::save_work_product_index;
+pub use self::work_product::copy_cgu_workproducts_to_incr_comp_cache_dir;
pub use self::work_product::delete_workproduct_files;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::dep_graph::{DepGraph, DepKind};
+use rustc::dep_graph::{DepGraph, DepKind, WorkProduct, WorkProductId};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::common::time;
})
}
-pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
+pub fn save_work_product_index(sess: &Session,
+ dep_graph: &DepGraph,
+ new_work_products: FxHashMap<WorkProductId, WorkProduct>) {
if sess.opts.incremental.is_none() {
return;
}
- debug!("save_work_products()");
+ debug!("save_work_product_index()");
dep_graph.assert_ignored();
let path = work_products_path(sess);
- save_in(sess, path, |e| encode_work_products(dep_graph, e));
+ save_in(sess, path, |e| encode_work_product_index(&new_work_products, e));
// We also need to clean out old work-products, as not all of them are
// deleted during invalidation. Some object files don't change their
// content, they are just not needed anymore.
- let new_work_products = dep_graph.work_products();
let previous_work_products = dep_graph.previous_work_products();
-
for (id, wp) in previous_work_products.iter() {
if !new_work_products.contains_key(id) {
work_product::delete_workproduct_files(sess, wp);
Ok(())
}
-fn encode_work_products(dep_graph: &DepGraph,
- encoder: &mut Encoder) -> io::Result<()> {
- let work_products: Vec<_> = dep_graph
- .work_products()
+fn encode_work_product_index(work_products: &FxHashMap<WorkProductId, WorkProduct>,
+ encoder: &mut Encoder) -> io::Result<()> {
+ let serialized_products: Vec<_> = work_products
.iter()
.map(|(id, work_product)| {
SerializedWorkProduct {
})
.collect();
- work_products.encode(encoder)
+ serialized_products.encode(encoder)
}
fn encode_query_cache(tcx: TyCtxt,
//! This module contains files for saving intermediate work-products.
use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph, WorkProductFileKind};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
use rustc::session::Session;
use rustc::util::fs::link_or_copy;
use std::path::PathBuf;
use std::fs as std_fs;
-pub fn save_trans_partition(sess: &Session,
- dep_graph: &DepGraph,
- cgu_name: &str,
- files: &[(WorkProductFileKind, PathBuf)]) {
- debug!("save_trans_partition({:?},{:?})",
+pub fn copy_cgu_workproducts_to_incr_comp_cache_dir(
+ sess: &Session,
+ cgu_name: &str,
+ files: &[(WorkProductFileKind, PathBuf)]
+) -> Option<(WorkProductId, WorkProduct)> {
+ debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})",
cgu_name,
files);
if sess.opts.incremental.is_none() {
- return
+ return None
}
let work_product_id = WorkProductId::from_cgu_name(cgu_name);
})
.collect();
let saved_files = match saved_files {
+ None => return None,
Some(v) => v,
- None => return,
};
let work_product = WorkProduct {
saved_files,
};
- dep_graph.insert_work_product(&work_product_id, work_product);
+ Some((work_product_id, work_product))
}
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
if !ty.moves_by_default(cx.tcx, param_env, item.span) {
return;
}
- if param_env.can_type_implement_copy(cx.tcx, ty, item.span).is_ok() {
+ if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
item.span,
"type could implement `Copy`; consider adding `impl \
impl UnreachablePub {
fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
- vis: &hir::Visibility, span: Span, exportable: bool) {
+ vis: &hir::Visibility, span: Span, exportable: bool,
+ mut applicability: Applicability) {
if !cx.access_levels.is_reachable(id) && *vis == hir::Visibility::Public {
+ if span.ctxt().outer().expn_info().is_some() {
+ applicability = Applicability::MaybeIncorrect;
+ }
let def_span = cx.tcx.sess.codemap().def_span(span);
let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span,
&format!("unreachable `pub` {}", what));
- // visibility is token at start of declaration (can be macro
- // variable rather than literal `pub`)
+ // We are presuming that visibility is token at start of
+ // declaration (can be macro variable rather than literal `pub`)
let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' ');
let replacement = if cx.tcx.features().crate_visibility_modifier {
"crate"
} else {
"pub(crate)"
}.to_owned();
- let app = if span.ctxt().outer().expn_info().is_none() {
- // even if macros aren't involved the suggestion
- // may be incorrect -- the user may have mistakenly
- // hidden it behind a private module and this lint is
- // a helpful way to catch that. However, we're trying
- // not to change the nature of the code with this lint
- // so it's marked as machine applicable.
- Applicability::MachineApplicable
- } else {
- Applicability::MaybeIncorrect
- };
- err.span_suggestion_with_applicability(pub_span, "consider restricting its visibility",
- replacement, app);
+ err.span_suggestion_with_applicability(pub_span,
+ "consider restricting its visibility",
+ replacement,
+ applicability);
if exportable {
err.help("or consider exporting it for use by other crates");
}
}
}
+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
- self.perform_lint(cx, "item", item.id, &item.vis, item.span, true);
+ let applicability = match item.node {
+ // suggestion span-manipulation is inadequate for `pub use
+ // module::{item}` (Issue #50455)
+ hir::ItemUse(..) => Applicability::MaybeIncorrect,
+ _ => Applicability::MachineApplicable,
+ };
+ self.perform_lint(cx, "item", item.id, &item.vis, item.span, true, applicability);
}
fn check_foreign_item(&mut self, cx: &LateContext, foreign_item: &hir::ForeignItem) {
- self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis, foreign_item.span, true);
+ self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis,
+ foreign_item.span, true, Applicability::MachineApplicable);
}
fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) {
- self.perform_lint(cx, "field", field.id, &field.vis, field.span, false);
+ self.perform_lint(cx, "field", field.id, &field.vis, field.span, false,
+ Applicability::MachineApplicable);
}
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
- self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
+ self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false,
+ Applicability::MachineApplicable);
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ if !cx.tcx.features().extern_absolute_paths {
+ return
+ }
if let hir::ItemExternCrate(ref orig) = it.node {
if it.attrs.iter().any(|a| a.check_name("macro_use")) {
return
UNUSED_PARENS);
add_lint_group!(sess,
- "rust_2018_migration",
+ "rust_2018_idioms",
BARE_TRAIT_OBJECT,
UNREACHABLE_PUB,
UNNECESSARY_EXTERN_CRATE);
MergeFunctions: bool,
SLPVectorize: bool,
LoopVectorize: bool,
+ PrepareForThinLTO: bool,
PGOGenPath: *const c_char,
PGOUsePath: *const c_char);
pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef,
}
impl fmt::Debug for Constraint {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"({:?}: {:?} @ {:?}) due to {:?}",
ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
ty: match base_ty.sty {
ty::TyArray(inner, size) => {
- let size = size.val.unwrap_u64();
+ let size = size.unwrap_usize(tcx);
let min_size = (from as u64) + (to as u64);
if let Some(rest_size) = size.checked_sub(min_size) {
tcx.mk_array(inner, rest_size)
use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc};
use hair::*;
-use rustc::middle::const_val::ConstVal;
use rustc::middle::region;
use rustc::ty::{self, Ty, UpvarSubsts};
use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::EvalErrorKind;
use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
span: expr_span,
ty: this.hir.tcx().types.u32,
literal: Literal::Value {
- value: this.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty: this.hir.tcx().types.u32
- }),
+ value: ty::Const::from_bits(
+ this.hir.tcx(),
+ 0,
+ this.hir.tcx().types.u32),
},
}));
box AggregateKind::Generator(closure_id, substs, movability)
let bits = self.hir.integer_bit_width(ty);
let n = (!0u128) >> (128 - bits);
let literal = Literal::Value {
- value: self.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
- ty
- })
+ value: ty::Const::from_bits(self.hir.tcx(), n, ty)
};
self.literal_operand(span, ty, literal)
let bits = self.hir.integer_bit_width(ty);
let n = 1 << (bits - 1);
let literal = Literal::Value {
- value: self.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
- ty
- })
+ value: ty::Const::from_bits(self.hir.tcx(), n, ty)
};
self.literal_operand(span, ty, literal)
match *match_pair.pattern.kind {
PatternKind::Constant { value } => {
- // if the places match, the type should match
- assert_eq!(match_pair.pattern.ty, switch_ty);
-
indices.entry(value)
.or_insert_with(|| {
- options.push(value.val.to_raw_bits().expect("switching on int"));
+ options.push(value.unwrap_bits(switch_ty));
options.len() - 1
});
true
use build::Builder;
-use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
-use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::*;
use syntax_pos::{Span, DUMMY_SP};
}
}
let literal = Literal::Value {
- value: self.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty
- })
+ value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
};
self.literal_operand(span, ty, literal)
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::hir::def::{Def, CtorKind};
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::interpret::GlobalId;
use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
use rustc::ty::cast::CastKind as TyCastKind;
promoted: None
};
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
- Ok(cv) => cv.val.unwrap_u64(),
+ Ok(cv) => cv.unwrap_usize(cx.tcx),
Err(e) => {
e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
0
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx().mk_const(ty::Const {
- val,
- ty,
- }),
+ value: val,
},
},
}.to_ref();
- let offset = mk_const(
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))),
- );
+ let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty));
match did {
Some(did) => {
// in case we are offsetting from a computed discriminant
// and not the beginning of discriminants (which is always `0`)
let substs = Substs::identity_for_item(cx.tcx(), did);
- let lhs = mk_const(ConstVal::Unevaluated(did, substs));
+ let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty));
let bin = ExprKind::Binary {
op: BinOp::Add,
lhs,
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty
- }),
+ value: ty::Const::zero_sized(cx.tcx(), ty),
},
},
}
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty: cx.tables().node_id_to_type(expr.hir_id)
- }),
+ value: ty::Const::zero_sized(
+ cx.tcx,
+ cx.tables().node_id_to_type(expr.hir_id)),
},
},
Def::Const(def_id) |
Def::AssociatedConst(def_id) => ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx.mk_const(ty::Const {
- val: ConstVal::Unevaluated(def_id, substs),
- ty: cx.tables().node_id_to_type(expr.hir_id)
- }),
+ value: ty::Const::unevaluated(
+ cx.tcx,
+ def_id,
+ substs,
+ cx.tables().node_id_to_type(expr.hir_id))
},
},
use hair::*;
-use rustc::middle::const_val::ConstVal;
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map::blocks::FnLikeNode;
use syntax::symbol::Symbol;
use rustc::hir;
use rustc_data_structures::sync::Lrc;
-use rustc::mir::interpret::{Value, PrimVal};
use hair::pattern::parse_float;
#[derive(Clone)]
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
- ty: self.tcx.types.usize
- })
+ value: ty::Const::from_usize(self.tcx, value),
}
}
pub fn true_literal(&mut self) -> Literal<'tcx> {
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
- ty: self.tcx.types.bool
- })
+ value: ty::Const::from_bool(self.tcx, true),
}
}
pub fn false_literal(&mut self) -> Literal<'tcx> {
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty: self.tcx.types.bool
- })
+ value: ty::Const::from_bool(self.tcx, false),
}
}
layout::Integer::from_attr(self.tcx, ty).size().bits()
}
+ // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
pub fn const_eval_literal(
&mut self,
lit: &'tcx ast::LitKind,
) -> Literal<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
- let parse_float = |num, fty| -> Value {
+ let parse_float = |num, fty| -> ConstValue<'tcx> {
parse_float(num, fty, neg).unwrap_or_else(|_| {
// FIXME(#31407) this is only necessary because float parsing is buggy
self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
let s = s.as_str();
let id = self.tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
- Value::ByValPair(
+ ConstValue::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
LitKind::ByteStr(ref data) => {
let id = self.tcx.allocate_cached(data);
let ptr = MemoryPointer::new(id, 0);
- Value::ByVal(PrimVal::Ptr(ptr))
+ ConstValue::ByVal(PrimVal::Ptr(ptr))
},
- LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+ LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
let n = clamp(n as u128);
- Value::ByVal(PrimVal::Bytes(n))
+ ConstValue::ByVal(PrimVal::Bytes(n))
},
- LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
+ LitKind::Int(n, _) => ConstValue::ByVal(PrimVal::Bytes(clamp(n))),
LitKind::Float(n, fty) => {
parse_float(n, fty)
}
};
parse_float(n, fty)
}
- LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
- LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+ LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+ LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
};
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(lit),
- ty,
- }),
+ value: ty::Const::from_const_value(self.tcx, lit, ty)
}
}
let method_ty = method_ty.subst(self.tcx, substs);
return (method_ty,
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty: method_ty
- }),
+ value: ty::Const::zero_sized(self.tcx, method_ty)
});
}
}
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::mir::Field;
-use rustc::mir::interpret::{Value, PrimVal};
use rustc::util::common::ErrorReported;
use syntax_pos::{Span, DUMMY_SP};
self.byte_array_map.entry(pat).or_insert_with(|| {
match pat.kind {
box PatternKind::Constant {
- value: &ty::Const { val: ConstVal::Value(b), ty }
+ value: const_val
} => {
- match b {
- Value::ByVal(PrimVal::Ptr(ptr)) => {
- let is_array_ptr = ty
- .builtin_deref(true)
- .and_then(|t| t.ty.builtin_index())
- .map_or(false, |t| t == tcx.types.u8);
- assert!(is_array_ptr);
- let alloc = tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .unwrap();
- assert_eq!(ptr.offset, 0);
- // FIXME: check length
- alloc.bytes.iter().map(|b| {
- &*pattern_arena.alloc(Pattern {
- ty: tcx.types.u8,
- span: pat.span,
- kind: box PatternKind::Constant {
- value: tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(
- PrimVal::Bytes(*b as u128),
- )),
- ty: tcx.types.u8
- })
- }
- })
- }).collect()
- },
- _ => bug!("not a byte str: {:?}", b),
+ if let Some(ptr) = const_val.to_ptr() {
+ let is_array_ptr = const_val.ty
+ .builtin_deref(true)
+ .and_then(|t| t.ty.builtin_index())
+ .map_or(false, |t| t == tcx.types.u8);
+ assert!(is_array_ptr);
+ let alloc = tcx
+ .interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .unwrap();
+ assert_eq!(ptr.offset, 0);
+ // FIXME: check length
+ alloc.bytes.iter().map(|b| {
+ &*pattern_arena.alloc(Pattern {
+ ty: tcx.types.u8,
+ span: pat.span,
+ kind: box PatternKind::Constant {
+ value: ty::Const::from_bits(
+ tcx,
+ *b as u128,
+ tcx.types.u8)
+ }
+ })
+ }).collect()
+ } else {
+ bug!("not a byte str: {:?}", const_val)
}
}
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
match pcx.ty.sty {
ty::TyBool => {
[true, false].iter().map(|&b| {
- ConstantValue(cx.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
- ty: cx.tcx.types.bool
- }))
+ ConstantValue(ty::Const::from_bool(cx.tcx, b))
}).collect()
}
- ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
- let len = len.val.unwrap_u64();
+ ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
+ let len = len.unwrap_usize(cx.tcx);
if len != 0 && cx.is_uninhabited(sub_ty) {
vec![]
} else {
for row in patterns {
match *row.kind {
PatternKind::Constant {
- value: &ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
- ty,
+ value: const_val @ &ty::Const {
+ val: ConstVal::Value(..),
+ ..
}
} => {
- let is_array_ptr = ty
- .builtin_deref(true)
- .and_then(|t| t.ty.builtin_index())
- .map_or(false, |t| t == cx.tcx.types.u8);
- if is_array_ptr {
- let alloc = cx.tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .unwrap();
- max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+ if let Some(ptr) = const_val.to_ptr() {
+ let is_array_ptr = const_val.ty
+ .builtin_deref(true)
+ .and_then(|t| t.ty.builtin_index())
+ .map_or(false, |t| t == cx.tcx.types.u8);
+ if is_array_ptr {
+ let alloc = cx.tcx
+ .interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .unwrap();
+ max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+ }
}
}
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
///
/// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
pat: &Pattern<'tcx>,
pcx: PatternContext)
-> Option<Vec<Constructor<'tcx>>>
Some(vec![ConstantRange(lo, hi, end)]),
PatternKind::Array { .. } => match pcx.ty.sty {
ty::TyArray(_, length) => Some(vec![
- Slice(length.val.unwrap_u64())
+ Slice(length.unwrap_usize(cx.tcx))
]),
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
},
}
}
-fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
- ctor: &Constructor,
- prefix: &[Pattern],
- slice: &Option<Pattern>,
- suffix: &[Pattern])
- -> Result<bool, ErrorReported> {
+fn slice_pat_covered_by_constructor<'tcx>(
+ tcx: TyCtxt<'_, 'tcx, '_>,
+ _span: Span,
+ ctor: &Constructor,
+ prefix: &[Pattern<'tcx>],
+ slice: &Option<Pattern<'tcx>>,
+ suffix: &[Pattern<'tcx>]
+) -> Result<bool, ErrorReported> {
let data: &[u8] = match *ctor {
- ConstantValue(&ty::Const { val: ConstVal::Value(
- Value::ByVal(PrimVal::Ptr(ptr))
- ), ty }) => {
- let is_array_ptr = ty
- .builtin_deref(true)
- .and_then(|t| t.ty.builtin_index())
- .map_or(false, |t| t == tcx.types.u8);
- assert!(is_array_ptr);
- tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .unwrap()
- .bytes
- .as_ref()
+ ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => {
+ if let Some(ptr) = const_val.to_ptr() {
+ let is_array_ptr = const_val.ty
+ .builtin_deref(true)
+ .and_then(|t| t.ty.builtin_index())
+ .map_or(false, |t| t == tcx.types.u8);
+ assert!(is_array_ptr);
+ tcx
+ .interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .unwrap()
+ .bytes
+ .as_ref()
+ } else {
+ bug!()
+ }
}
_ => bug!()
};
data[data.len()-suffix.len()..].iter().zip(suffix))
{
match pat.kind {
- box PatternKind::Constant { value } => match value.val {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
- assert_eq!(b as u8 as u128, b);
- if b as u8 != *ch {
- return Ok(false);
- }
+ box PatternKind::Constant { value } => {
+ let b = value.unwrap_bits(pat.ty);
+ assert_eq!(b as u8 as u128, b);
+ if b as u8 != *ch {
+ return Ok(false);
}
- _ => span_bug!(pat.span, "bad const u8 {:?}", value)
- },
+ }
_ => {}
}
}
fn constructor_covered_by_range<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ctor: &Constructor,
- from: &ConstVal, to: &ConstVal,
+ ctor: &Constructor<'tcx>,
+ from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>,
end: RangeEnd,
ty: Ty<'tcx>,
) -> Result<bool, ErrorReported> {
}
match *ctor {
ConstantValue(value) => {
- let to = some_or_ok!(cmp_to(&value.val));
+ let to = some_or_ok!(cmp_to(value));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
- Ok(some_or_ok!(cmp_from(&value.val)) && end)
+ Ok(some_or_ok!(cmp_from(value)) && end)
},
ConstantRange(from, to, RangeEnd::Included) => {
- let to = some_or_ok!(cmp_to(&to.val));
+ let to = some_or_ok!(cmp_to(to));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
- Ok(some_or_ok!(cmp_from(&from.val)) && end)
+ Ok(some_or_ok!(cmp_from(from)) && end)
},
ConstantRange(from, to, RangeEnd::Excluded) => {
- let to = some_or_ok!(cmp_to(&to.val));
+ let to = some_or_ok!(cmp_to(to));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Excluded && to == Ordering::Equal);
- Ok(some_or_ok!(cmp_from(&from.val)) && end)
+ Ok(some_or_ok!(cmp_from(from)) && end)
}
Single => Ok(true),
_ => bug!(),
PatternKind::Constant { value } => {
match *constructor {
- Slice(..) => match value.val {
- ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
+ Slice(..) => {
+ if let Some(ptr) = value.to_ptr() {
let is_array_ptr = value.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
} else {
None
}
- }
- _ => span_bug!(pat.span,
+ } else {
+ span_bug!(pat.span,
"unexpected const-val {:?} with ctor {:?}", value, constructor)
+ }
},
_ => {
match constructor_covered_by_range(
cx.tcx,
- constructor, &value.val, &value.val, RangeEnd::Included,
+ constructor, value, value, RangeEnd::Included,
value.ty,
) {
Ok(true) => Some(vec![]),
PatternKind::Range { lo, hi, ref end } => {
match constructor_covered_by_range(
cx.tcx,
- constructor, &lo.val, &hi.val, end.clone(), lo.ty,
+ constructor, lo, hi, end.clone(), lo.ty,
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
use interpret::{const_val_field, const_variant_index, self};
use rustc::middle::const_val::ConstVal;
-use rustc::mir::{Field, BorrowKind, Mutability};
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
match value.val {
- ConstVal::Value(v) => print_miri_value(v, value.ty, f),
+ ConstVal::Value(..) => fmt_const_val(f, value),
ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
}
}
-fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
- use rustc::ty::TypeVariants::*;
- match (value, &ty.sty) {
- (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
- (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
- (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
- (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
- (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
- write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
- _ => bug!("{:?}: {} not printable in a pattern", value, ty),
- }
-}
-
impl<'tcx> fmt::Display for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.kind {
(PatternKind::Constant { value: lo },
PatternKind::Constant { value: hi }) => {
use std::cmp::Ordering;
- match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) {
+ match (end, compare_const_vals(self.tcx, lo, hi, ty).unwrap()) {
(RangeEnd::Excluded, Ordering::Less) =>
PatternKind::Range { lo, hi, end },
(RangeEnd::Excluded, _) => {
ty::TyArray(_, len) => {
// fixed-length array
- let len = len.val.unwrap_u64();
+ let len = len.unwrap_usize(self.tcx);
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
}
self.tables.local_id_root.expect("literal outside any scope"),
self.substs,
);
- let cv = self.tcx.mk_const(ty::Const { val, ty });
- *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+ *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
},
Err(()) => {
self.errors.push(PatternError::FloatBug);
self.tables.local_id_root.expect("literal outside any scope"),
self.substs,
);
- let cv = self.tcx.mk_const(ty::Const { val, ty });
- *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+ *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
},
Err(()) => {
self.errors.push(PatternError::FloatBug);
}
ty::TyArray(_, n) => {
PatternKind::Array {
- prefix: (0..n.val.unwrap_u64())
+ prefix: (0..n.unwrap_usize(self.tcx))
.map(|i| adt_subpattern(i as usize, None))
.collect(),
slice: None,
pub fn compare_const_vals<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- a: &ConstVal,
- b: &ConstVal,
+ a: &'tcx ty::Const<'tcx>,
+ b: &'tcx ty::Const<'tcx>,
ty: Ty<'tcx>,
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
- use rustc::mir::interpret::{Value, PrimVal};
- match (a, b) {
- (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
- &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
- use ::rustc_apfloat::Float;
- match ty.sty {
- ty::TyFloat(ast::FloatTy::F32) => {
- let l = ::rustc_apfloat::ieee::Single::from_bits(a);
- let r = ::rustc_apfloat::ieee::Single::from_bits(b);
- l.partial_cmp(&r)
- },
- ty::TyFloat(ast::FloatTy::F64) => {
- let l = ::rustc_apfloat::ieee::Double::from_bits(a);
- let r = ::rustc_apfloat::ieee::Double::from_bits(b);
- l.partial_cmp(&r)
- },
- ty::TyInt(_) => {
- let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
- let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
- Some((a as i128).cmp(&(b as i128)))
- },
- _ => Some(a.cmp(&b)),
- }
- },
- _ if a == b => Some(Ordering::Equal),
- _ => None,
+ // FIXME: This should use assert_bits(ty) instead of use_bits
+ // but triggers possibly bugs due to mismatching of arrays and slices
+ if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
+ use ::rustc_apfloat::Float;
+ match ty.sty {
+ ty::TyFloat(ast::FloatTy::F32) => {
+ let l = ::rustc_apfloat::ieee::Single::from_bits(a);
+ let r = ::rustc_apfloat::ieee::Single::from_bits(b);
+ l.partial_cmp(&r)
+ },
+ ty::TyFloat(ast::FloatTy::F64) => {
+ let l = ::rustc_apfloat::ieee::Double::from_bits(a);
+ let r = ::rustc_apfloat::ieee::Double::from_bits(b);
+ l.partial_cmp(&r)
+ },
+ ty::TyInt(_) => {
+ let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
+ let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
+ Some((a as i128).cmp(&(b as i128)))
+ },
+ _ => Some(a.cmp(&b)),
+ }
+ } else {
+ if a == b {
+ Some(Ordering::Equal)
+ } else {
+ None
+ }
}
}
+// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
neg: bool)
- -> Result<ConstVal<'tcx>, ()> {
+ -> Result<&'tcx ty::Const<'tcx>, ()> {
use syntax::ast::*;
use rustc::mir::interpret::*;
let s = s.as_str();
let id = tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
- Value::ByValPair(
+ ConstValue::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_cached(data);
let ptr = MemoryPointer::new(id, 0);
- Value::ByVal(PrimVal::Ptr(ptr))
+ ConstValue::ByVal(PrimVal::Ptr(ptr))
},
- LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+ LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) => {
enum Int {
Signed(IntTy),
ty::TyUint(other) => Int::Unsigned(other),
_ => bug!(),
};
+ // This converts from LitKind::Int (which is sign extended) to
+ // PrimVal::Bytes (which is zero extended)
let n = match ty {
// FIXME(oli-obk): are these casts correct?
Int::Signed(IntTy::I8) if neg =>
- (n as i128 as i8).overflowing_neg().0 as i128 as u128,
+ (n as i8).overflowing_neg().0 as u8 as u128,
Int::Signed(IntTy::I16) if neg =>
- (n as i128 as i16).overflowing_neg().0 as i128 as u128,
+ (n as i16).overflowing_neg().0 as u16 as u128,
Int::Signed(IntTy::I32) if neg =>
- (n as i128 as i32).overflowing_neg().0 as i128 as u128,
+ (n as i32).overflowing_neg().0 as u32 as u128,
Int::Signed(IntTy::I64) if neg =>
- (n as i128 as i64).overflowing_neg().0 as i128 as u128,
+ (n as i64).overflowing_neg().0 as u64 as u128,
Int::Signed(IntTy::I128) if neg =>
(n as i128).overflowing_neg().0 as u128,
- Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
- Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
- Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
- Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
- Int::Signed(IntTy::I128) => n,
- Int::Unsigned(UintTy::U8) => n as u8 as u128,
- Int::Unsigned(UintTy::U16) => n as u16 as u128,
- Int::Unsigned(UintTy::U32) => n as u32 as u128,
- Int::Unsigned(UintTy::U64) => n as u64 as u128,
- Int::Unsigned(UintTy::U128) => n,
+ Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128,
+ Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128,
+ Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128,
+ Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128,
+ Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
_ => bug!(),
};
- Value::ByVal(PrimVal::Bytes(n))
+ ConstValue::ByVal(PrimVal::Bytes(n))
},
LitKind::Float(n, fty) => {
parse_float(n, fty, neg)?
};
parse_float(n, fty, neg)?
}
- LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
- LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+ LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+ LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
};
- Ok(ConstVal::Value(lit))
+ Ok(ty::Const::from_const_value(tcx, lit, ty))
}
-pub fn parse_float(
+pub fn parse_float<'tcx>(
num: Symbol,
fty: ast::FloatTy,
neg: bool,
-) -> Result<Value, ()> {
+) -> Result<ConstValue<'tcx>, ()> {
let num = num.as_str();
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
}
};
- Ok(Value::ByVal(PrimVal::Bytes(bits)))
+ Ok(ConstValue::ByVal(PrimVal::Bytes(bits)))
}
use rustc::hir;
-use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
+use rustc::middle::const_val::{ConstEvalErr, ErrKind};
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use syntax::ast::Mutability;
use syntax::codemap::Span;
+use syntax::codemap::DUMMY_SP;
-use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
-use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
+use rustc::mir::interpret::{
+ EvalResult, EvalError, EvalErrorKind, GlobalId,
+ Value, Pointer, PrimVal, AllocId, Allocation, ConstValue,
+};
+use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};
use std::fmt;
use std::error::Error;
}
pub fn eval_promoted<'a, 'mir, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
cid: GlobalId<'tcx>,
mir: &'mir mir::Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<(Value, Pointer, Ty<'tcx>)> {
- let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
- match res {
- Ok(val) => Some(val),
- Err(mut err) => {
- ecx.report(&mut err, false, None);
- None
+ ecx.with_fresh_body(|ecx| {
+ let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env);
+ match res {
+ Ok(val) => Some(val),
+ Err(mut err) => {
+ ecx.report(&mut err, false, None);
+ None
+ }
}
- }
+ })
}
pub fn eval_body<'a, 'tcx>(
}
}
+pub fn value_to_const_value<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ val: Value,
+ ty: Ty<'tcx>,
+) -> &'tcx ty::Const<'tcx> {
+ let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+
+ if layout.is_zst() {
+ return ty::Const::from_const_value(
+ tcx,
+ ConstValue::ByVal(PrimVal::Undef),
+ ty);
+ }
+
+ let val = match layout.abi {
+ layout::Abi::Scalar(..) => {
+ if let Value::ByVal(val) = val {
+ ConstValue::ByVal(val)
+ } else {
+ bug!("expected ByVal value, got {:?}", val);
+ }
+ }
+ layout::Abi::ScalarPair(..) => {
+ if let Value::ByValPair(a, b) = val {
+ ConstValue::ByValPair(a, b)
+ } else {
+ bug!("expected ByValPair value, got {:?}", val);
+ }
+ }
+ _ => {
+ if let Value::ByRef(ptr, align) = val {
+ let ptr = ptr.primval.to_ptr().unwrap();
+ assert_eq!(ptr.offset, 0);
+ let alloc = tcx.interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .expect("miri allocation never successfully created");
+ assert_eq!(align, alloc.align);
+ ConstValue::ByRef(alloc)
+ } else {
+ bug!("expected ByRef value, got {:?}", val);
+ }
+ },
+ };
+ ty::Const::from_const_value(tcx, val, ty)
+}
+
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
mir: Option<&'mir mir::Mir<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
- debug!("eval_body: {:?}, {:?}", cid, param_env);
+ debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
// we start out with the best span we have
// and try improving it down the road when more information is available
let span = tcx.def_span(cid.instance.def_id());
- let mut span = mir.map(|mir| mir.span).unwrap_or(span);
+ let span = mir.map(|mir| mir.span).unwrap_or(span);
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
- let res = (|| {
+ let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
+ (r, ecx)
+}
+
+fn eval_body_using_ecx<'a, 'mir, 'tcx>(
+ ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
+ cid: GlobalId<'tcx>,
+ mir: Option<&'mir mir::Mir<'tcx>>,
+ param_env: ty::ParamEnv<'tcx>,
+) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
+ debug!("eval_body: {:?}, {:?}", cid, param_env);
+ let tcx = ecx.tcx.tcx;
let mut mir = match mir {
Some(mir) => mir,
None => ecx.load_mir(cid.instance.def)?,
if let Some(index) = cid.promoted {
mir = &mir.promoted[index];
}
- span = mir.span;
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
assert!(!layout.is_unsized());
let ptr = ecx.memory.allocate(
let ptr = ptr.into();
// always try to read the value and report errors
let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
- // if it's a constant (so it needs no address, directly compute its value)
- Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val,
+ Some(val) => val,
// point at the allocation
_ => Value::ByRef(ptr, layout.align),
};
Ok((value, ptr, layout.ty))
- })();
- (res, ecx)
}
pub struct CompileTimeEvaluator;
instance: ty::Instance<'tcx>,
variant: Option<usize>,
field: mir::Field,
- value: Value,
+ value: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let result = (|| {
+ let value = ecx.const_value_to_value(value, ty)?;
let (mut field, ty) = match value {
- Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
+ Value::ByValPair(..) | Value::ByVal(_) =>
+ ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
Value::ByRef(ptr, align) => {
let place = Place::Ptr {
ptr,
Ok((field, ty))
})();
match result {
- Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
- val: ConstVal::Value(field),
- ty,
- })),
+ Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
Err(err) => {
let (trace, span) = ecx.generate_stacktrace(None);
let err = ErrKind::Miri(err, trace);
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
- value: Value,
+ val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, usize> {
- trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty);
+ trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+ let value = ecx.const_value_to_value(val, ty)?;
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
let layout = ecx.layout_of(ty)?;
- use super::MemoryKind;
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
let ptr: Pointer = ptr.into();
ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
ecx.read_discriminant_as_variant_index(place, ty)
}
+pub fn const_value_to_allocation_provider<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ (val, ty): (ConstValue<'tcx>, Ty<'tcx>),
+) -> &'tcx Allocation {
+ match val {
+ ConstValue::ByRef(alloc) => return alloc,
+ _ => ()
+ }
+ let result = || -> EvalResult<'tcx, &'tcx Allocation> {
+ let mut ecx = EvalContext::new(
+ tcx.at(DUMMY_SP),
+ ty::ParamEnv::reveal_all(),
+ CompileTimeEvaluator,
+ ());
+ let value = ecx.const_value_to_value(val, ty)?;
+ let layout = ecx.layout_of(ty)?;
+ let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
+ ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
+ let alloc = ecx.memory.get(ptr.alloc_id)?;
+ Ok(tcx.intern_const_alloc(alloc.clone()))
+ };
+ result().expect("unable to convert ConstVal to Allocation")
+}
+
pub fn const_eval_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
let cid = key.value;
let def_id = cid.instance.def.def_id();
- if tcx.is_foreign_item(def_id) {
- let id = tcx.interpret_interner.cache_static(def_id);
- let ty = tcx.type_of(def_id);
- let layout = tcx.layout_of(key.param_env.and(ty)).unwrap();
- let ptr = MemoryPointer::new(id, 0);
- return Ok(tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)),
- ty,
- }))
- }
-
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
let tables = tcx.typeck_tables_of(def_id);
let span = tcx.def_span(def_id);
};
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
- res.map(|(miri_value, _, miri_ty)| {
- tcx.mk_const(ty::Const {
- val: ConstVal::Value(miri_value),
- ty: miri_ty,
- })
+ res.map(|(val, _, miri_ty)| {
+ value_to_const_value(tcx, val, miri_ty)
}).map_err(|mut err| {
if tcx.is_static(def_id).is_some() {
ecx.report(&mut err, true, None);
use syntax::ast::Mutability;
use rustc::mir::interpret::{
GlobalId, Value, Pointer, PrimVal, PrimValKind,
- EvalError, EvalResult, EvalErrorKind, MemoryPointer,
+ EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue,
};
use std::mem;
pub ty: Ty<'tcx>,
}
-impl<'tcx> ValTy<'tcx> {
- pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
- match val.val {
- ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
- ConstVal::Unevaluated { .. } => None,
- }
- }
-}
-
impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
type Target = Value;
fn deref(&self) -> &Value {
}
}
+const MAX_TERMINATORS: usize = 1_000_000;
+
impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
pub fn new(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
memory: Memory::new(tcx, memory_data),
stack: Vec::new(),
stack_limit: tcx.sess.const_eval_stack_frame_limit,
- terminators_remaining: 1_000_000,
+ terminators_remaining: MAX_TERMINATORS,
}
}
+ pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
+ let stack = mem::replace(&mut self.stack, Vec::new());
+ let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS);
+ let r = f(self);
+ self.stack = stack;
+ self.terminators_remaining = terminators_remaining;
+ r
+ }
+
pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
))
}
- pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+ pub fn const_value_to_value(
+ &mut self,
+ val: ConstValue<'tcx>,
+ _ty: Ty<'tcx>,
+ ) -> EvalResult<'tcx, Value> {
+ match val {
+ ConstValue::ByRef(alloc) => {
+ // FIXME: Allocate new AllocId for all constants inside
+ let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
+ Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align))
+ },
+ ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
+ ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
+ }
+ }
+
+ pub(super) fn const_to_value(
+ &mut self,
+ const_val: &ConstVal<'tcx>,
+ ty: Ty<'tcx>
+ ) -> EvalResult<'tcx, Value> {
match *const_val {
ConstVal::Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?;
promoted: None,
}, ty)
}
- ConstVal::Value(val) => Ok(val),
+ ConstVal::Value(val) => self.const_value_to_value(val, ty)
}
}
Repeat(ref operand, _) => {
let (elem_ty, length) = match dest_ty.sty {
- ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
+ ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)),
_ => {
bug!(
"tried to assign array-repeat to non-array type {:?}",
// FIXME(CTFE): don't allow computing the length of arrays in const eval
let src = self.eval_place(place)?;
let ty = self.place_ty(place);
- let (_, len) = src.elem_ty_and_len(ty);
+ let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
self.write_primval(
dest,
PrimVal::from_u128(len as u128),
Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
Literal::Promoted { index } => {
+ let instance = self.frame().instance;
self.read_global_as_value(GlobalId {
- instance: self.frame().instance,
+ instance,
promoted: Some(index),
}, ty)?
}
Ok(())
}
- pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+ pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
if self.tcx.is_static(gid.instance.def_id()).is_some() {
let alloc_id = self
.tcx
}
}
- pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
- use syntax::ast::FloatTy;
-
- let layout = self.layout_of(ty)?;
- self.memory.check_align(ptr, ptr_align)?;
-
- if layout.size.bytes() == 0 {
- return Ok(Some(Value::ByVal(PrimVal::Undef)));
- }
-
- let ptr = ptr.to_ptr()?;
- let val = match ty.sty {
+ pub fn validate_ptr_target(
+ &self,
+ ptr: MemoryPointer,
+ ptr_align: Align,
+ ty: Ty<'tcx>
+ ) -> EvalResult<'tcx> {
+ match ty.sty {
ty::TyBool => {
let val = self.memory.read_primval(ptr, ptr_align, 1)?;
- let val = match val {
- PrimVal::Bytes(0) => false,
- PrimVal::Bytes(1) => true,
+ match val {
+ PrimVal::Bytes(0) | PrimVal::Bytes(1) => (),
// TODO: This seems a little overeager, should reading at bool type already be insta-UB?
_ => return err!(InvalidBool),
- };
- PrimVal::from_bool(val)
+ }
}
ty::TyChar => {
let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
match ::std::char::from_u32(c) {
- Some(ch) => PrimVal::from_char(ch),
+ Some(..) => (),
None => return err!(InvalidChar(c as u128)),
}
}
- ty::TyInt(int_ty) => {
- use syntax::ast::IntTy::*;
- let size = match int_ty {
- I8 => 1,
- I16 => 2,
- I32 => 4,
- I64 => 8,
- I128 => 16,
- Isize => self.memory.pointer_size(),
- };
- self.memory.read_primval(ptr, ptr_align, size)?
- }
-
- ty::TyUint(uint_ty) => {
- use syntax::ast::UintTy::*;
- let size = match uint_ty {
- U8 => 1,
- U16 => 2,
- U32 => 4,
- U64 => 8,
- U128 => 16,
- Usize => self.memory.pointer_size(),
- };
- self.memory.read_primval(ptr, ptr_align, size)?
- }
-
- ty::TyFloat(FloatTy::F32) => {
- PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
- }
- ty::TyFloat(FloatTy::F64) => {
- PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
- }
-
- ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
+ ty::TyFnPtr(_) => {
+ self.memory.read_ptr_sized(ptr, ptr_align)?;
+ },
ty::TyRef(_, rty, _) |
ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => {
- return self.read_ptr(ptr, ptr_align, rty).map(Some)
+ self.read_ptr(ptr, ptr_align, rty)?;
}
ty::TyAdt(def, _) => {
if def.is_box() {
- return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
+ self.read_ptr(ptr, ptr_align, ty.boxed_ty())?;
+ return Ok(());
}
if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
let size = scalar.value.size(self).bytes();
- self.memory.read_primval(ptr, ptr_align, size)?
- } else {
- return Ok(None);
+ self.memory.read_primval(ptr, ptr_align, size)?;
}
}
- _ => return Ok(None),
- };
+ _ => (),
+ }
+ Ok(())
+ }
+
+ pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
+ let layout = self.layout_of(ty)?;
+ self.memory.check_align(ptr, ptr_align)?;
- Ok(Some(Value::ByVal(val)))
+ if layout.size.bytes() == 0 {
+ return Ok(Some(Value::ByVal(PrimVal::Undef)));
+ }
+
+ let ptr = ptr.to_ptr()?;
+
+ // Not the right place to do this
+ //self.validate_ptr_target(ptr, ptr_align, ty)?;
+
+ match layout.abi {
+ layout::Abi::Scalar(..) => {
+ let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?;
+ Ok(Some(Value::ByVal(primval)))
+ }
+ layout::Abi::ScalarPair(ref a, ref b) => {
+ let (a, b) = (&a.value, &b.value);
+ let (a_size, b_size) = (a.size(self), b.size(self));
+ let a_ptr = ptr;
+ let b_offset = a_size.abi_align(b.align(self));
+ let b_ptr = ptr.offset(b_offset.bytes(), self)?.into();
+ let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?;
+ let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?;
+ Ok(Some(Value::ByValPair(a_val, b_val)))
+ }
+ _ => Ok(None),
+ }
}
pub fn frame(&self) -> &Frame<'mir, 'tcx> {
let ptr = self.into_ptr(src)?;
// u64 cast is from usize to u64, which is always good
let valty = ValTy {
- value: ptr.to_value_with_len(length.val.unwrap_u64() ),
+ value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)),
ty: dest_ty,
};
self.write_value(valty, dest)
-use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
-use std::collections::{btree_map, BTreeMap, VecDeque};
-use std::{ptr, io};
+use std::collections::{btree_map, VecDeque};
+use std::ptr;
+use rustc::hir::def_id::DefId;
use rustc::ty::Instance;
+use rustc::ty::ParamEnv;
use rustc::ty::maps::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout};
use syntax::ast::Mutability;
+use rustc::middle::const_val::{ConstVal, ErrKind};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
-use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer,
- EvalResult, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer,
+ EvalResult, PrimVal, EvalErrorKind, GlobalId};
+pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
use super::{EvalContext, Machine};
}
/// kind is `None` for statics
- pub fn allocate(
+ pub fn allocate_value(
&mut self,
- size: u64,
- align: Align,
+ alloc: Allocation,
kind: Option<MemoryKind<M::MemoryKinds>>,
- ) -> EvalResult<'tcx, MemoryPointer> {
- assert_eq!(size as usize as u64, size);
- let alloc = Allocation {
- bytes: vec![0; size as usize],
- relocations: BTreeMap::new(),
- undef_mask: UndefMask::new(size),
- align,
- runtime_mutability: Mutability::Immutable,
- };
+ ) -> EvalResult<'tcx, AllocId> {
let id = self.tcx.interpret_interner.reserve();
M::add_lock(self, id);
match kind {
self.uninitialized_statics.insert(id, alloc);
},
}
+ Ok(id)
+ }
+
+ /// kind is `None` for statics
+ pub fn allocate(
+ &mut self,
+ size: u64,
+ align: Align,
+ kind: Option<MemoryKind<M::MemoryKinds>>,
+ ) -> EvalResult<'tcx, MemoryPointer> {
+ let id = self.allocate_value(Allocation::undef(size, align), kind)?;
Ok(MemoryPointer::new(id, 0))
}
/// Allocation accessors
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+ fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
+ let instance = Instance::mono(self.tcx.tcx, def_id);
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
+ match *err.kind {
+ ErrKind::Miri(ref err, _) => match err.kind {
+ EvalErrorKind::TypeckError |
+ EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
+ _ => EvalErrorKind::ReferencedConstant.into(),
+ },
+ ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
+ ref other => bug!("const eval returned {:?}", other),
+ }
+ }).map(|val| {
+ let const_val = match val.val {
+ ConstVal::Value(val) => val,
+ ConstVal::Unevaluated(..) => bug!("should be evaluated"),
+ };
+ self.tcx.const_value_to_allocation((const_val, val.ty))
+ })
+ }
+
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
// normal alloc?
match self.alloc_map.get(&id) {
Some(alloc) => Ok(alloc),
None => {
// static alloc?
- self.tcx.interpret_interner.get_alloc(id)
- // no alloc? produce an error
- .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
- EvalErrorKind::DerefFunctionPointer.into()
- } else {
- EvalErrorKind::DanglingPointerDeref.into()
- })
+ if let Some(a) = self.tcx.interpret_interner.get_alloc(id) {
+ return Ok(a);
+ }
+ // static variable?
+ if let Some(did) = self.tcx.interpret_interner.get_static(id) {
+ return self.const_eval_static(did);
+ }
+ // otherwise return an error
+ Err(if self.tcx.interpret_interner.get_fn(id).is_some() {
+ EvalErrorKind::DerefFunctionPointer.into()
+ } else {
+ EvalErrorKind::DanglingPointerDeref.into()
+ })
},
},
}
}
}
-////////////////////////////////////////////////////////////////////////////////
-// Methods to access integers in the target endianness
-////////////////////////////////////////////////////////////////////////////////
-
-pub fn write_target_uint(
- endianness: layout::Endian,
- mut target: &mut [u8],
- data: u128,
-) -> Result<(), io::Error> {
- let len = target.len();
- match endianness {
- layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
- layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
- }
-}
-
-pub fn write_target_int(
- endianness: layout::Endian,
- mut target: &mut [u8],
- data: i128,
-) -> Result<(), io::Error> {
- let len = target.len();
- match endianness {
- layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
- layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
- }
-}
-
-pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
- match endianness {
- layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
- layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// Unaligned accesses
////////////////////////////////////////////////////////////////////////////////
mk_borrowck_eval_cx,
eval_body,
CompileTimeEvaluator,
+ const_value_to_allocation_provider,
const_eval_provider,
const_val_field,
const_variant_index,
+ value_to_const_value,
};
pub use self::machine::Machine;
use rustc::mir;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx;
self.to_ptr_align().0.to_ptr()
}
- pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
+ pub(super) fn elem_ty_and_len(
+ self,
+ ty: Ty<'tcx>,
+ tcx: TyCtxt<'_, 'tcx, '_>
+ ) -> (Ty<'tcx>, u64) {
match ty.sty {
- ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
+ ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)),
ty::TySlice(elem) => {
match self {
let base = self.force_allocation(base)?;
let (base_ptr, align) = base.to_ptr_align();
- let (elem_ty, len) = base.elem_ty_and_len(outer_ty);
+ let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx);
let elem_size = self.layout_of(elem_ty)?.size.bytes();
assert!(
n < len,
let base = self.force_allocation(base)?;
let (base_ptr, align) = base.to_ptr_align();
- let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+ let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
let elem_size = self.layout_of(elem_ty)?.size.bytes();
assert!(n >= min_length as u64);
let base = self.force_allocation(base)?;
let (base_ptr, align) = base.to_ptr_align();
- let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+ let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
let elem_size = self.layout_of(elem_ty)?.size.bytes();
assert!(u64::from(from) <= n - u64::from(to));
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
shim::provide(providers);
transform::provide(providers);
providers.const_eval = interpret::const_eval_provider;
+ providers.const_value_to_allocation = interpret::const_value_to_allocation_provider;
providers.check_match = hair::pattern::check_match;
}
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer};
+use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
use rustc::mir::{self, Location, Promoted};
use rustc::mir::visit::Visitor as MirVisitor;
use rustc::mir::mono::MonoItem;
-use rustc::mir::interpret::GlobalId;
+use rustc::mir::interpret::{PrimVal, GlobalId};
use monomorphize::{self, Instance};
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
};
match val {
ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
- ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
+ ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
collect_miri(tcx, a.alloc_id, output);
collect_miri(tcx, b.alloc_id, output);
}
- ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
- ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
- ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) =>
+ ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) |
+ ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
+ ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
collect_miri(tcx, ptr.alloc_id, output),
- ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => {
- // by ref should only collect the inner allocation, not the value itself
- let alloc = tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .expect("ByRef to extern static is not allowed");
- for &inner in alloc.relocations.values() {
- collect_miri(tcx, inner, output);
+ ConstVal::Value(ConstValue::ByRef(alloc)) => {
+ for &id in alloc.relocations.values() {
+ collect_miri(tcx, id, output);
}
}
_ => {},
ty::TyArray(inner_type, len) => {
output.push('[');
self.push_type_name(inner_type, output);
- write!(output, "; {}",
- len.val.unwrap_u64()).unwrap();
+ write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
output.push(']');
},
ty::TySlice(inner_type) => {
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer;
-use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::maps::Providers;
-use rustc::mir::interpret::{Value, PrimVal};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
match self_ty.sty {
_ if is_copy => builder.copy_shim(),
ty::TyArray(ty, len) => {
- let len = len.val.unwrap_u64();
+ let len = len.unwrap_usize(tcx);
builder.array_shim(dest, src, ty, len)
}
ty::TyClosure(def_id, substs) => {
span: self.span,
ty: func_ty,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty: func_ty
- }),
+ value: ty::Const::zero_sized(self.tcx, func_ty)
},
});
span: self.span,
ty: self.tcx.types.usize,
literal: Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))),
- ty: self.tcx.types.usize,
- })
+ value: ty::Const::from_usize(self.tcx, value),
}
}
}
span,
ty,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty
- }),
+ value: ty::Const::zero_sized(tcx, ty)
},
}),
vec![rcvr])
use rustc::mir::visit::{Visitor, PlaceContext};
use rustc::middle::const_val::ConstVal;
use rustc::ty::{TyCtxt, self, Instance};
-use rustc::mir::interpret::{Value, PrimVal, GlobalId};
+use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult};
+use interpret::EvalContext;
+use interpret::CompileTimeEvaluator;
use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
use transform::{MirPass, MirSource};
-use syntax::codemap::Span;
+use syntax::codemap::{Span, DUMMY_SP};
use rustc::ty::subst::Substs;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::ty::ParamEnv;
use rustc::ty::layout::{
- LayoutOf, TyLayout, LayoutError,
+ LayoutOf, TyLayout, LayoutError, LayoutCx,
HasTyCtxt, TargetDataLayout, HasDataLayout,
};
/// Finds optimization opportunities on the MIR.
struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
+ ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>,
mir: &'b Mir<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
source: MirSource,
) -> ConstPropagator<'b, 'a, 'tcx> {
let param_env = tcx.param_env(source.def_id);
+ let substs = Substs::identity_for_item(tcx, source.def_id);
+ let instance = Instance::new(source.def_id, substs);
+ let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
ConstPropagator {
+ ecx,
mir,
tcx,
source,
}
}
- fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
+ fn use_ecx<F, T>(
+ &mut self,
+ span: Span,
+ f: F
+ ) -> Option<T>
+ where
+ F: FnOnce(&mut Self) -> EvalResult<'tcx, T>,
+ {
+ self.ecx.tcx.span = span;
+ let r = match f(self) {
+ Ok(val) => Some(val),
+ Err(mut err) => {
+ self.ecx.report(&mut err, false, Some(span));
+ None
+ },
+ };
+ self.ecx.tcx.span = DUMMY_SP;
+ r
+ }
+
+ fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
let value = match self.tcx.const_eval(self.param_env.and(cid)) {
Ok(val) => val,
Err(err) => {
},
};
let val = match value.val {
- ConstVal::Value(v) => v,
+ ConstVal::Value(v) => {
+ self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))?
+ },
_ => bug!("eval produced: {:?}", value),
};
let val = (val, value.ty, span);
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
match c.literal {
Literal::Value { value } => match value.val {
- ConstVal::Value(v) => Some((v, value.ty, c.span)),
+ ConstVal::Value(v) => {
+ let v = self.use_ecx(c.span, |this| {
+ this.ecx.const_value_to_value(v, value.ty)
+ })?;
+ Some((v, value.ty, c.span))
+ },
ConstVal::Unevaluated(did, substs) => {
let instance = Instance::resolve(
self.tcx,
};
// cannot use `const_eval` here, because that would require having the MIR
// for the current function available, but we're producing said MIR right now
- let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
+ let span = self.mir.span;
+ let (value, _, ty) = self.use_ecx(span, |this| {
+ Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env))
+ })??;
let val = (value, ty, c.span);
trace!("evaluated {:?} to {:?}", c, val);
Some(val)
use rustc_data_structures::indexed_vec::Idx;
let field_index = field.index();
let val = [a, b][field_index];
- let field = base_layout.field(&*self, field_index).ok()?;
+ let cx = LayoutCx {
+ tcx: self.tcx,
+ param_env: self.param_env,
+ };
+ let field = base_layout.field(cx, field_index).ok()?;
trace!("projection resulted in: {:?}", val);
Some((Value::ByVal(val), field.ty, span))
},
// FIXME: can't handle code with generics
return None;
}
- let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
- let instance = Instance::new(self.source.def_id, substs);
- let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
let val = self.eval_operand(arg)?;
- let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
- match ecx.unary_op(op, prim, val.1) {
- Ok(val) => Some((Value::ByVal(val), place_ty, span)),
- Err(mut err) => {
- ecx.report(&mut err, false, Some(span));
- None
- },
- }
+ let prim = self.use_ecx(span, |this| {
+ this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 })
+ })?;
+ let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?;
+ Some((Value::ByVal(val), place_ty, span))
}
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
Rvalue::BinaryOp(op, ref left, ref right) => {
// FIXME: can't handle code with generics
return None;
}
- let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
- let instance = Instance::new(self.source.def_id, substs);
- let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
- let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
+ let r = self.use_ecx(span, |this| {
+ this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
+ })?;
if op == BinOp::Shr || op == BinOp::Shl {
let param_env = self.tcx.param_env(self.source.def_id);
let left_ty = left.ty(self.mir, self.tcx);
}
}
let left = self.eval_operand(left)?;
- let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
+ let l = self.use_ecx(span, |this| {
+ this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 })
+ })?;
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
- match ecx.binary_op(op, l, left.1, r, right.1) {
- Ok((val, overflow)) => {
- let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
- Value::ByValPair(
- val,
- PrimVal::from_bool(overflow),
- )
- } else {
- if overflow {
- use rustc::mir::interpret::EvalErrorKind;
- let mut err = EvalErrorKind::Overflow(op).into();
- ecx.report(&mut err, false, Some(span));
- return None;
- }
- Value::ByVal(val)
- };
- Some((val, place_ty, span))
- },
- Err(mut err) => {
- ecx.report(&mut err, false, Some(span));
- None
- },
- }
+ let (val, overflow) = self.use_ecx(span, |this| {
+ this.ecx.binary_op(op, l, left.1, r, right.1)
+ })?;
+ let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
+ Value::ByValPair(
+ val,
+ PrimVal::from_bool(overflow),
+ )
+ } else {
+ if overflow {
+ use rustc::mir::interpret::EvalErrorKind;
+ let mut err = EvalErrorKind::Overflow(op).into();
+ self.use_ecx(span, |this| {
+ this.ecx.report(&mut err, false, Some(span));
+ Ok(())
+ });
+ return None;
+ }
+ Value::ByVal(val)
+ };
+ Some((val, place_ty, span))
},
}
}
use dataflow::{self, do_dataflow, DebugFormatted};
use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal};
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
}
impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> {
- fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
span,
ty: self.tcx.types.bool,
literal: Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
- ty: self.tcx.types.bool
- })
+ value: ty::Const::from_bool(self.tcx, val)
}
})))
}
use rustc::hir;
use rustc::hir::def_id::DefId;
-use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
use rustc::ty::{self, TyCtxt, AdtDef, Ty};
use transform::no_landing_pads::no_landing_pads;
use dataflow::{do_dataflow, DebugFormatted, state_for_location};
use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
-use rustc::mir::interpret::{Value, PrimVal};
pub struct StateTransform;
span: source_info.span,
ty: self.tcx.types.u32,
literal: Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))),
- ty: self.tcx.types.u32
- }),
+ value: ty::Const::from_bits(
+ self.tcx,
+ state_disc.into(),
+ self.tcx.types.u32),
},
});
Statement {
span: mir.span,
ty: tcx.types.bool,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty: tcx.types.bool
- }),
+ value: ty::Const::from_bool(tcx, false),
},
}),
expected: true,
}
Operand::Constant(ref constant) => {
if let Literal::Value {
- value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
+ value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. }
} = constant.literal {
// Don't peek inside trait associated constants.
if self.tcx.trait_of_item(def_id).is_some() {
_ => false
}
} else if let ty::TyArray(_, len) = ty.sty {
- len.val.unwrap_u64() == 0 &&
+ len.unwrap_usize(self.tcx) == 0 &&
self.mode == Mode::Fn
} else {
false
//! A pass that simplifies branches when their condition is known.
-use rustc::ty::{self, TyCtxt};
-use rustc::middle::const_val::ConstVal;
+use rustc::ty::TyCtxt;
use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal};
use transform::{MirPass, MirSource};
use std::borrow::Cow;
}
fn run_pass<'a, 'tcx>(&self,
- _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
for block in mir.basic_blocks_mut() {
terminator.kind = match terminator.kind {
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
literal: Literal::Value { ref value }, ..
- }), ref values, ref targets, .. } => {
- if let Some(constint) = value.val.to_raw_bits() {
+ }), switch_ty, ref values, ref targets, .. } => {
+ if let Some(constint) = value.assert_bits(switch_ty) {
let (otherwise, targets) = targets.split_last().unwrap();
let mut ret = TerminatorKind::Goto { target: *otherwise };
for (&v, t) in values.iter().zip(targets.iter()) {
},
TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
literal: Literal::Value {
- value: &ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
- .. }
+ value
}, ..
- }), expected, .. } if (cond == 1) == expected => {
- assert!(cond <= 1);
+ }), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
TerminatorKind::Goto { target: target }
},
TerminatorKind::FalseEdges { real_target, .. } => {
} else {
let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
if let ty::TyArray(item_ty, const_size) = place_ty.sty {
- if let Some(size) = const_size.val.to_raw_bits() {
- assert!(size <= (u32::max_value() as u128),
- "unform array move out doesn't supported
+ if let Some(size) = const_size.assert_usize(self.tcx) {
+ assert!(size <= u32::max_value() as u64,
+ "uniform array move out doesn't supported
for array bigger then u32");
self.uniform(location, dst_place, proj, item_ty, size as u32);
}
let opt_size = opt_src_place.and_then(|src_place| {
let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
if let ty::TyArray(_, ref size_o) = src_ty.sty {
- size_o.val.to_raw_bits().map(|n| n as u64)
+ size_o.assert_usize(tcx)
} else {
None
}
use std::fmt;
use rustc::hir;
use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
use rustc::middle::lang_items;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::util::IntTypeExt;
use rustc_data_structures::indexed_vec::Idx;
use util::patch::MirPatch;
-use rustc::mir::interpret::{Value, PrimVal};
use std::{iter, u32};
let succ = self.succ;
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
}
- ty::TyArray(ety, size) => self.open_drop_for_array(
- ety, size.val.to_raw_bits().map(|i| i as u64)),
+ ty::TyArray(ety, size) => {
+ let size = size.assert_usize(self.tcx());
+ self.open_drop_for_array(ety, size)
+ },
ty::TySlice(ety) => self.open_drop_for_array(ety, None),
_ => bug!("open drop from non-ADT `{:?}`", ty)
span: self.source_info.span,
ty: self.tcx().types.usize,
literal: Literal::Value {
- value: self.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))),
- ty: self.tcx().types.usize
- })
+ value: ty::Const::from_usize(self.tcx(), val.into())
}
})
}
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
self.super_const(constant);
- let ty::Const { ty, val } = constant;
+ let ty::Const { ty, val, .. } = constant;
self.push(&format!("ty::Const"));
self.push(&format!("+ ty: {:?}", ty));
self.push(&format!("+ val: {:?}", val));
// Make sure that the linker/gcc really don't pull in anything, including
// default objects, libs, etc.
- base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
+ base.pre_link_args_crt.insert(LinkerFlavor::Gcc, Vec::new());
+ base.pre_link_args_crt.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
// At least when this was tested, the linker would not add the
// `GNU_EH_FRAME` program header to executables generated, which is required
//
// Each target directory for musl has these object files included in it so
// they'll be included from there.
- base.pre_link_objects_exe.push("crt1.o".to_string());
- base.pre_link_objects_exe.push("crti.o".to_string());
- base.post_link_objects.push("crtn.o".to_string());
+ base.pre_link_objects_exe_crt.push("crt1.o".to_string());
+ base.pre_link_objects_exe_crt.push("crti.o".to_string());
+ base.pre_link_objects_exe_crt_sys.push("crtbegin.o".to_string());
+ base.post_link_objects_crt_sys.push("crtend.o".to_string());
+ base.post_link_objects_crt.push("crtn.o".to_string());
// These targets statically link libc by default
base.crt_static_default = true;
/// Linker to invoke
pub linker: Option<String>,
- /// Linker arguments that are unconditionally passed *before* any
- /// user-defined libraries.
- pub pre_link_args: LinkArgs,
- /// Objects to link before all others, always found within the
+ /// Linker arguments that are passed *before* any user-defined libraries.
+ pub pre_link_args: LinkArgs, // ... unconditionally
+ pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
+ /// Objects to link before all others, all except *_sys found within the
/// sysroot folder.
- pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
+ pub pre_link_objects_exe: Vec<String>, // ... when linking an executable, unconditionally
+ pub pre_link_objects_exe_crt: Vec<String>, // ... when linking an executable with a bundled crt
+ pub pre_link_objects_exe_crt_sys: Vec<String>, // ... when linking an executable with a bundled
+ // crt, from the system library search path
pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
/// Linker arguments that are unconditionally passed after any
/// user-defined but before post_link_objects. Standard platform
/// libraries that should be always be linked to, usually go here.
pub late_link_args: LinkArgs,
- /// Objects to link after all others, always found within the
+ /// Objects to link after all others, all except *_sys found within the
/// sysroot folder.
- pub post_link_objects: Vec<String>,
+ pub post_link_objects: Vec<String>, // ... unconditionally
+ pub post_link_objects_crt: Vec<String>, // ... when linking with a bundled crt
+ pub post_link_objects_crt_sys: Vec<String>, // ... when linking with a bundled crt, from the
+ // system library search path
/// Linker arguments that are unconditionally passed *after* any
/// user-defined libraries.
pub post_link_args: LinkArgs,
is_builtin: false,
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
pre_link_args: LinkArgs::new(),
+ pre_link_args_crt: LinkArgs::new(),
post_link_args: LinkArgs::new(),
asm_args: Vec::new(),
cpu: "generic".to_string(),
position_independent_executables: false,
relro_level: RelroLevel::None,
pre_link_objects_exe: Vec::new(),
+ pre_link_objects_exe_crt: Vec::new(),
+ pre_link_objects_exe_crt_sys: Vec::new(),
pre_link_objects_dll: Vec::new(),
post_link_objects: Vec::new(),
+ post_link_objects_crt: Vec::new(),
+ post_link_objects_crt_sys: Vec::new(),
late_link_args: LinkArgs::new(),
link_env: Vec::new(),
archive_format: "gnu".to_string(),
key!(is_builtin, bool);
key!(linker, optional);
key!(pre_link_args, link_args);
+ key!(pre_link_args_crt, link_args);
key!(pre_link_objects_exe, list);
+ key!(pre_link_objects_exe_crt, list);
+ key!(pre_link_objects_exe_crt_sys, list);
key!(pre_link_objects_dll, list);
key!(late_link_args, link_args);
key!(post_link_objects, list);
+ key!(post_link_objects_crt, list);
+ key!(post_link_objects_crt_sys, list);
key!(post_link_args, link_args);
key!(link_env, env);
key!(asm_args, list);
target_option_val!(is_builtin);
target_option_val!(linker);
target_option_val!(link_args - pre_link_args);
+ target_option_val!(link_args - pre_link_args_crt);
target_option_val!(pre_link_objects_exe);
+ target_option_val!(pre_link_objects_exe_crt);
+ target_option_val!(pre_link_objects_exe_crt_sys);
target_option_val!(pre_link_objects_dll);
target_option_val!(link_args - late_link_args);
target_option_val!(post_link_objects);
+ target_option_val!(post_link_objects_crt);
+ target_option_val!(post_link_objects_crt_sys);
target_option_val!(link_args - post_link_args);
target_option_val!(env - link_env);
target_option_val!(asm_args);
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
cmd.args(args);
}
+ if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
+ if sess.crt_static() {
+ cmd.args(args);
+ }
+ }
if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
cmd.args(args);
}
cmd.arg(root.join(obj));
}
+ if crate_type == config::CrateTypeExecutable && sess.crt_static() {
+ for obj in &sess.target.target.options.pre_link_objects_exe_crt {
+ cmd.arg(root.join(obj));
+ }
+
+ for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys {
+ if flavor == LinkerFlavor::Gcc {
+ cmd.arg(format!("-l:{}", obj));
+ }
+ }
+ }
+
if sess.target.target.options.is_like_emscripten {
cmd.arg("-s");
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
for obj in &sess.target.target.options.post_link_objects {
cmd.arg(root.join(obj));
}
+ if sess.crt_static() {
+ for obj in &sess.target.target.options.post_link_objects_crt_sys {
+ if flavor == LinkerFlavor::Gcc {
+ cmd.arg(format!("-l:{}", obj));
+ }
+ }
+ for obj in &sess.target.target.options.post_link_objects_crt {
+ cmd.arg(root.join(obj));
+ }
+ }
if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
cmd.args(args);
}
llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
level => level,
};
- with_llvm_pmb(llmod, config, opt_level, &mut |b| {
+ with_llvm_pmb(llmod, config, opt_level, false, &mut |b| {
if thin {
if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
panic!("this version of LLVM does not support ThinLTO");
use back::symbol_export::ExportedSymbols;
use base;
use consts;
-use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
-use rustc::dep_graph::{DepGraph, WorkProductFileKind};
+use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
AllPasses, Sanitizer, Lto};
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
- with_llvm_pmb(llmod, &config, opt_level, &mut |b| {
+ let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal;
+ with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
})
}
}
-fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
- dep_graph: &DepGraph,
- compiled_modules: &CompiledModules) {
+fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
+ sess: &Session,
+ compiled_modules: &CompiledModules
+) -> FxHashMap<WorkProductId, WorkProduct> {
+ let mut work_products = FxHashMap::default();
+
if sess.opts.incremental.is_none() {
- return;
+ return work_products;
}
for module in compiled_modules.modules.iter() {
files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
}
- save_trans_partition(sess, dep_graph, &module.name, &files);
+ if let Some((id, product)) =
+ copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
+ work_products.insert(id, product);
+ }
}
+
+ work_products
}
fn produce_final_output_artifacts(sess: &Session,
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
config: &ModuleConfig,
opt_level: llvm::CodeGenOptLevel,
+ prepare_for_thin_lto: bool,
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
use std::ptr;
config.merge_functions,
config.vectorize_slp,
config.vectorize_loop,
+ prepare_for_thin_lto,
pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
);
}
impl OngoingCrateTranslation {
- pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
+ pub(crate) fn join(
+ self,
+ sess: &Session
+ ) -> (CrateTranslation, FxHashMap<WorkProductId, WorkProduct>) {
self.shared_emitter_main.check(sess, true);
let compiled_modules = match self.future.join() {
Ok(Ok(compiled_modules)) => compiled_modules,
time_graph.dump(&format!("{}-timings", self.crate_name));
}
- copy_module_artifacts_into_incr_comp_cache(sess,
- dep_graph,
- &compiled_modules);
+ let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
+ &compiled_modules);
+
produce_final_output_artifacts(sess,
&compiled_modules,
&self.output_filenames);
metadata_module: compiled_modules.metadata_module,
};
- trans
+ (trans, work_products)
}
pub(crate) fn submit_pre_translated_module_to_llvm(&self,
let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
match (&source.sty, &target.sty) {
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
- C_usize(cx, len.val.unwrap_u64())
+ C_usize(cx, len.unwrap_usize(cx.tcx))
}
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
// For now, upcasts are limited to changes in marker
}
fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
- use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+ use rustc::mir::interpret::GlobalId;
use rustc::middle::const_val::ConstVal;
info!("loading wasm section {:?}", id);
let param_env = ty::ParamEnv::reveal_all();
let val = tcx.const_eval(param_env.and(cid)).unwrap();
- let val = match val.val {
+ let const_val = match val.val {
ConstVal::Value(val) => val,
ConstVal::Unevaluated(..) => bug!("should be evaluated"),
};
- let val = match val {
- Value::ByRef(ptr, _align) => ptr.into_inner_primval(),
- ref v => bug!("should be ByRef, was {:?}", v),
- };
- let mem = match val {
- PrimVal::Ptr(mem) => mem,
- ref v => bug!("should be Ptr, was {:?}", v),
- };
- assert_eq!(mem.offset, 0);
- let alloc = tcx
- .interpret_interner
- .get_alloc(mem.alloc_id)
- .expect("miri allocation never successfully created");
+
+ let alloc = tcx.const_value_to_allocation((const_val, val.ty));
(section.to_string(), alloc.bytes.clone())
}
let upper_bound = match array_or_slice_type.sty {
ty::TyArray(_, len) => {
- len.val.unwrap_u64() as c_longlong
+ len.unwrap_usize(cx.tcx) as c_longlong
}
_ => -1
};
ty::TyArray(inner_type, len) => {
output.push('[');
push_debuginfo_type_name(cx, inner_type, true, output);
- output.push_str(&format!("; {}", len.val.unwrap_u64()));
+ output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
output.push(']');
},
ty::TySlice(inner_type) => {
outputs: &OutputFilenames,
) -> Result<(), CompileIncomplete>{
use rustc::util::common::time;
- let trans = trans.downcast::<::back::write::OngoingCrateTranslation>()
+ let (trans, work_products) = trans.downcast::<::back::write::OngoingCrateTranslation>()
.expect("Expected LlvmTransCrate's OngoingCrateTranslation, found Box<Any>")
- .join(sess, dep_graph);
+ .join(sess);
if sess.opts.debugging_opts.incremental_info {
back::write::dump_incremental_data(&trans);
}
time(sess,
"serialize work products",
- move || rustc_incremental::save_work_products(sess, &dep_graph));
+ move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));
sess.compile_status()?;
use rustc::hir::def_id::DefId;
use rustc::mir;
use rustc_data_structures::indexed_vec::Idx;
-use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
+use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue};
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
use builder::Builder;
consts::get_static(cx, def_id)
} else if let Some(alloc) = cx.tcx.interpret_interner
.get_alloc(ptr.alloc_id) {
- let init = global_initializer(cx, alloc);
+ let init = const_alloc_to_llvm(cx, alloc);
if alloc.runtime_mutability == Mutability::Mutable {
consts::addr_of_mut(cx, init, alloc.align, "byte_str")
} else {
}
}
-pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
+fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef {
+ let layout = cx.layout_of(ty);
+
+ if layout.is_zst() {
+ return C_undef(layout.immediate_llvm_type(cx));
+ }
+
+ match val {
+ ConstValue::ByVal(x) => {
+ let scalar = match layout.abi {
+ layout::Abi::Scalar(ref x) => x,
+ _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout)
+ };
+ primval_to_llvm(
+ cx,
+ x,
+ scalar,
+ layout.immediate_llvm_type(cx),
+ )
+ },
+ ConstValue::ByValPair(a, b) => {
+ let (a_scalar, b_scalar) = match layout.abi {
+ layout::Abi::ScalarPair(ref a, ref b) => (a, b),
+ _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout)
+ };
+ let a_llval = primval_to_llvm(
+ cx,
+ a,
+ a_scalar,
+ layout.scalar_pair_element_llvm_type(cx, 0),
+ );
+ let b_llval = primval_to_llvm(
+ cx,
+ b,
+ b_scalar,
+ layout.scalar_pair_element_llvm_type(cx, 1),
+ );
+ C_struct(cx, &[a_llval, b_llval], false)
+ },
+ ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc),
+ }
+}
+
+pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
let layout = cx.data_layout();
let pointer_size = layout.pointer_size.bytes() as usize;
let ptr_offset = read_target_uint(
layout.endian,
&alloc.bytes[offset..(offset + pointer_size)],
- ).expect("global_initializer: could not read relocation pointer") as u64;
+ ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
llvals.push(primval_to_llvm(
cx,
PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
let param_env = ty::ParamEnv::reveal_all();
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
- let ptr = match static_.val {
- ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr,
+ let val = match static_.val {
+ ConstVal::Value(val) => val,
_ => bug!("static const eval returned {:#?}", static_),
};
-
- let alloc = cx
- .tcx
- .interpret_interner
- .get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id)
- .expect("miri allocation never successfully created");
- Ok(global_initializer(cx, alloc))
+ Ok(const_value_to_llvm(cx, val, static_.ty))
}
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
- fn const_to_miri_value(
+ fn const_to_const_value(
&mut self,
bx: &Builder<'a, 'tcx>,
constant: &'tcx ty::Const<'tcx>,
- ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+ ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
match constant.val {
ConstVal::Unevaluated(def_id, ref substs) => {
let tcx = bx.tcx();
promoted: None,
};
let c = tcx.const_eval(param_env.and(cid))?;
- self.const_to_miri_value(bx, c)
+ self.const_to_const_value(bx, c)
},
- ConstVal::Value(miri_val) => Ok(miri_val),
+ ConstVal::Value(val) => Ok(val),
}
}
- pub fn mir_constant_to_miri_value(
+ pub fn mir_constant_to_const_value(
&mut self,
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
- ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+ ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
match constant.literal {
mir::Literal::Promoted { index } => {
let param_env = ty::ParamEnv::reveal_all();
mir::Literal::Value { value } => {
Ok(self.monomorphize(&value))
}
- }.and_then(|c| self.const_to_miri_value(bx, c))
+ }.and_then(|c| self.const_to_const_value(bx, c))
}
/// process constant containing SIMD shuffle indices
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
) -> (ValueRef, Ty<'tcx>) {
- self.mir_constant_to_miri_value(bx, constant)
+ self.mir_constant_to_const_value(bx, constant)
.and_then(|c| {
let field_ty = constant.ty.builtin_index().unwrap();
let fields = match constant.ty.sty {
- ty::TyArray(_, n) => n.val.unwrap_u64(),
+ ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()),
ref other => bug!("invalid simd shuffle type: {}", other),
};
let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
c,
constant.ty,
)?;
- match field.val {
- ConstVal::Value(MiriValue::ByVal(prim)) => {
- let layout = bx.cx.layout_of(field_ty);
- let scalar = match layout.abi {
- layout::Abi::Scalar(ref x) => x,
- _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
- };
- Ok(primval_to_llvm(
- bx.cx, prim, scalar,
- layout.immediate_llvm_type(bx.cx),
- ))
- },
- other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
+ if let Some(prim) = field.to_primval() {
+ let layout = bx.cx.layout_of(field_ty);
+ let scalar = match layout.abi {
+ layout::Abi::Scalar(ref x) => x,
+ _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+ };
+ Ok(primval_to_llvm(
+ bx.cx, prim, scalar,
+ layout.immediate_llvm_type(bx.cx),
+ ))
+ } else {
+ bug!("simd shuffle field {:?}", field)
}
}).collect();
let llval = C_struct(bx.cx, &values?, false);
use llvm::ValueRef;
use rustc::middle::const_val::ConstEvalErr;
use rustc::mir;
-use rustc::mir::interpret::Value as MiriValue;
+use rustc::mir::interpret::ConstValue;
use rustc::ty;
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx;
use value::Value;
use type_of::LayoutLlvmExt;
use type_::Type;
+use consts;
use std::fmt;
use std::ptr;
use super::{FunctionCx, LocalRef};
-use super::constant::{primval_to_llvm};
+use super::constant::{primval_to_llvm, const_alloc_to_llvm};
use super::place::PlaceRef;
/// The representation of a Rust value. The enum variant is in fact
}
pub fn from_const(bx: &Builder<'a, 'tcx>,
- miri_val: MiriValue,
+ val: ConstValue<'tcx>,
ty: ty::Ty<'tcx>)
-> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
let layout = bx.cx.layout_of(ty);
return Ok(OperandRef::new_zst(bx.cx, layout));
}
- let val = match miri_val {
- MiriValue::ByVal(x) => {
+ let val = match val {
+ ConstValue::ByVal(x) => {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
);
OperandValue::Immediate(llval)
},
- MiriValue::ByValPair(a, b) => {
+ ConstValue::ByValPair(a, b) => {
let (a_scalar, b_scalar) = match layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
_ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
);
OperandValue::Pair(a_llval, b_llval)
},
- MiriValue::ByRef(ptr, align) => {
- let scalar = layout::Scalar {
- value: layout::Primitive::Pointer,
- valid_range: 0..=!0
- };
- let ptr = primval_to_llvm(
- bx.cx,
- ptr.into_inner_primval(),
- &scalar,
- layout.llvm_type(bx.cx).ptr_to(),
- );
- return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx));
+ ConstValue::ByRef(alloc) => {
+ let init = const_alloc_to_llvm(bx.cx, alloc);
+ let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str");
+ let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
+ return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
},
};
mir::Operand::Constant(ref constant) => {
let ty = self.monomorphize(&constant.ty);
- self.mir_constant_to_miri_value(bx, constant)
+ self.mir_constant_to_const_value(bx, constant)
.and_then(|c| OperandRef::from_const(bx, c, ty))
.unwrap_or_else(|err| {
match constant.literal {
if let mir::Place::Local(index) = *place {
if let LocalRef::Operand(Some(op)) = self.locals[index] {
if let ty::TyArray(_, n) = op.layout.ty.sty {
- let n = n.val.unwrap_u64();
+ let n = n.unwrap_usize(bx.cx.tcx);
return common::C_usize(bx.cx, n);
}
}
//! representation. The main routine here is `ast_ty_to_ty()`: each use
//! is parameterized by an instance of `AstConv`.
-use rustc::middle::const_val::ConstVal;
use rustc_data_structures::accumulate_vec::AccumulateVec;
use hir;
use hir::def::Def;
hir::TyArray(ref ty, length) => {
let length_def_id = tcx.hir.body_owner_def_id(length);
let substs = Substs::identity_for_item(tcx, length_def_id);
- let length = tcx.mk_const(ty::Const {
- val: ConstVal::Unevaluated(length_def_id, substs),
- ty: tcx.types.usize
- });
+ let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize);
let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
self.normalize_ty(ast_ty.span, array_ty)
}
let expected_ty = self.structurally_resolved_type(pat.span, expected);
let (inner_ty, slice_ty) = match expected_ty.sty {
ty::TyArray(inner_ty, size) => {
- let size = size.val.unwrap_u64();
+ let size = size.unwrap_usize(tcx);
let min_len = before.len() as u64 + after.len() as u64;
if slice.is_none() {
if min_len != size {
};
if let Ok(count) = count {
- let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1);
+ let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1);
if !zero_or_one {
// For [foo, ..n] where n > 1, `foo` must have
// Copy type:
use super::{FnCtxt, Needs};
use super::method::MethodCallee;
-use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
-use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray};
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::infer::type_variable::TypeVariableOrigin;
use errors;
Err(()) => {
// error types are considered "builtin"
if !lhs_ty.references_error() {
- if let IsAssign::Yes = is_assign {
- struct_span_err!(self.tcx.sess, expr.span, E0368,
- "binary assignment operation `{}=` \
- cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty)
- .span_label(lhs_expr.span,
- format!("cannot use `{}=` on type `{}`",
- op.node.as_str(), lhs_ty))
- .emit();
- } else {
- let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
- "binary operation `{}` cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty);
-
- if let TypeVariants::TyRef(_, rty, _) = lhs_ty.sty {
- if {
- !self.infcx.type_moves_by_default(self.param_env,
- rty,
- lhs_expr.span) &&
- self.lookup_op_method(rty,
- &[rhs_ty],
- Op::Binary(op, is_assign))
- .is_ok()
- } {
- err.note(
- &format!(
- "this is a reference to a type that `{}` can be applied \
- to; you need to dereference this variable once for this \
- operation to work",
- op.node.as_str()));
+ let codemap = self.tcx.sess.codemap();
+ match is_assign {
+ IsAssign::Yes => {
+ let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
+ "binary assignment operation `{}=` \
+ cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty);
+ err.span_label(lhs_expr.span,
+ format!("cannot use `{}=` on type `{}`",
+ op.node.as_str(), lhs_ty));
+ let mut suggested_deref = false;
+ if let TyRef(_, mut rty, _) = lhs_ty.sty {
+ if {
+ !self.infcx.type_moves_by_default(self.param_env,
+ rty,
+ lhs_expr.span) &&
+ self.lookup_op_method(rty,
+ &[rhs_ty],
+ Op::Binary(op, is_assign))
+ .is_ok()
+ } {
+ if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+ while let TyRef(_, rty_inner, _) = rty.sty {
+ rty = rty_inner;
+ }
+ let msg = &format!(
+ "`{}=` can be used on '{}', you can \
+ dereference `{2}`: `*{2}`",
+ op.node.as_str(),
+ rty,
+ lstring
+ );
+ err.help(msg);
+ suggested_deref = true;
+ }
+ }
}
+ let missing_trait = match op.node {
+ hir::BiAdd => Some("std::ops::AddAssign"),
+ hir::BiSub => Some("std::ops::SubAssign"),
+ hir::BiMul => Some("std::ops::MulAssign"),
+ hir::BiDiv => Some("std::ops::DivAssign"),
+ hir::BiRem => Some("std::ops::RemAssign"),
+ hir::BiBitAnd => Some("std::ops::BitAndAssign"),
+ hir::BiBitXor => Some("std::ops::BitXorAssign"),
+ hir::BiBitOr => Some("std::ops::BitOrAssign"),
+ hir::BiShl => Some("std::ops::ShlAssign"),
+ hir::BiShr => Some("std::ops::ShrAssign"),
+ _ => None
+ };
+ if let Some(missing_trait) = missing_trait {
+ if op.node == hir::BiAdd &&
+ self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+ rhs_ty, &mut err) {
+ // This has nothing here because it means we did string
+ // concatenation (e.g. "Hello " + "World!"). This means
+ // we don't want the note in the else clause to be emitted
+ } else if let ty::TyParam(_) = lhs_ty.sty {
+ // FIXME: point to span of param
+ err.note(&format!(
+ "`{}` might need a bound for `{}`",
+ lhs_ty, missing_trait
+ ));
+ } else if !suggested_deref {
+ err.note(&format!(
+ "an implementation of `{}` might \
+ be missing for `{}`",
+ missing_trait, lhs_ty
+ ));
+ }
+ }
+ err.emit();
}
-
- let missing_trait = match op.node {
- hir::BiAdd => Some("std::ops::Add"),
- hir::BiSub => Some("std::ops::Sub"),
- hir::BiMul => Some("std::ops::Mul"),
- hir::BiDiv => Some("std::ops::Div"),
- hir::BiRem => Some("std::ops::Rem"),
- hir::BiBitAnd => Some("std::ops::BitAnd"),
- hir::BiBitOr => Some("std::ops::BitOr"),
- hir::BiShl => Some("std::ops::Shl"),
- hir::BiShr => Some("std::ops::Shr"),
- hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
- hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
- Some("std::cmp::PartialOrd"),
- _ => None
- };
-
- if let Some(missing_trait) = missing_trait {
- if missing_trait == "std::ops::Add" &&
- self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
- rhs_ty, &mut err) {
- // This has nothing here because it means we did string
- // concatenation (e.g. "Hello " + "World!"). This means
- // we don't want the note in the else clause to be emitted
- } else if let ty::TyParam(_) = lhs_ty.sty {
- // FIXME: point to span of param
- err.note(
- &format!("`{}` might need a bound for `{}`",
- lhs_ty, missing_trait));
- } else {
- err.note(
- &format!("an implementation of `{}` might be missing for `{}`",
- missing_trait, lhs_ty));
+ IsAssign::No => {
+ let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
+ "binary operation `{}` cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty);
+ let mut suggested_deref = false;
+ if let TyRef(_, mut rty, _) = lhs_ty.sty {
+ if {
+ !self.infcx.type_moves_by_default(self.param_env,
+ rty,
+ lhs_expr.span) &&
+ self.lookup_op_method(rty,
+ &[rhs_ty],
+ Op::Binary(op, is_assign))
+ .is_ok()
+ } {
+ if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+ while let TyRef(_, rty_inner, _) = rty.sty {
+ rty = rty_inner;
+ }
+ let msg = &format!(
+ "`{}` can be used on '{}', you can \
+ dereference `{2}`: `*{2}`",
+ op.node.as_str(),
+ rty,
+ lstring
+ );
+ err.help(msg);
+ suggested_deref = true;
+ }
+ }
}
+ let missing_trait = match op.node {
+ hir::BiAdd => Some("std::ops::Add"),
+ hir::BiSub => Some("std::ops::Sub"),
+ hir::BiMul => Some("std::ops::Mul"),
+ hir::BiDiv => Some("std::ops::Div"),
+ hir::BiRem => Some("std::ops::Rem"),
+ hir::BiBitAnd => Some("std::ops::BitAnd"),
+ hir::BiBitXor => Some("std::ops::BitXor"),
+ hir::BiBitOr => Some("std::ops::BitOr"),
+ hir::BiShl => Some("std::ops::Shl"),
+ hir::BiShr => Some("std::ops::Shr"),
+ hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+ hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+ Some("std::cmp::PartialOrd"),
+ _ => None
+ };
+ if let Some(missing_trait) = missing_trait {
+ if op.node == hir::BiAdd &&
+ self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+ rhs_ty, &mut err) {
+ // This has nothing here because it means we did string
+ // concatenation (e.g. "Hello " + "World!"). This means
+ // we don't want the note in the else clause to be emitted
+ } else if let ty::TyParam(_) = lhs_ty.sty {
+ // FIXME: point to span of param
+ err.note(&format!(
+ "`{}` might need a bound for `{}`",
+ lhs_ty, missing_trait
+ ));
+ } else if !suggested_deref {
+ err.note(&format!(
+ "an implementation of `{}` might \
+ be missing for `{}`",
+ missing_trait, lhs_ty
+ ));
+ }
+ }
+ err.emit();
}
- err.emit();
}
}
self.tcx.types.err
Err(()) => {
let actual = self.resolve_type_vars_if_possible(&operand_ty);
if !actual.references_error() {
- struct_span_err!(self.tcx.sess, ex.span, E0600,
+ let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
"cannot apply unary operator `{}` to type `{}`",
- op.as_str(), actual).emit();
+ op.as_str(), actual);
+ err.span_label(ex.span, format!("cannot apply unary \
+ operator `{}`", op.as_str()));
+ match actual.sty {
+ TyUint(_) if op == hir::UnNeg => {
+ err.note(&format!("unsigned values cannot be negated"));
+ },
+ TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {},
+ TyRef(_, ref lty, _) if lty.sty == TyStr => {},
+ _ => {
+ let missing_trait = match op {
+ hir::UnNeg => "std::ops::Neg",
+ hir::UnNot => "std::ops::Not",
+ hir::UnDeref => "std::ops::UnDerf"
+ };
+ err.note(&format!("an implementation of `{}` might \
+ be missing for `{}`",
+ missing_trait, operand_ty));
+ }
+ }
+ err.emit();
}
self.tcx.types.err
}
debug!("visit_implementation_of_copy: self_type={:?} (free)",
self_type);
- match param_env.can_type_implement_copy(tcx, self_type, span) {
+ match param_env.can_type_implement_copy(tcx, self_type) {
Ok(()) => {}
- Err(CopyImplementationError::InfrigingField(field)) => {
+ Err(CopyImplementationError::InfrigingFields(fields)) => {
let item = tcx.hir.expect_item(impl_node_id);
let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
tr.path.span
span
};
- struct_span_err!(tcx.sess,
- span,
- E0204,
- "the trait `Copy` may not be implemented for this type")
- .span_label(
- tcx.def_span(field.did),
- "this field does not implement `Copy`")
- .emit()
+ let mut err = struct_span_err!(tcx.sess,
+ span,
+ E0204,
+ "the trait `Copy` may not be implemented for this type");
+ for span in fields.iter().map(|f| tcx.def_span(f.did)) {
+ err.span_label(span, "this field does not implement `Copy`");
+ }
+ err.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
let item = tcx.hir.expect_item(impl_node_id);
pub struct Attributes {
pub doc_strings: Vec<DocFragment>,
pub other_attrs: Vec<ast::Attribute>,
- pub cfg: Option<Rc<Cfg>>,
+ pub cfg: Option<Arc<Cfg>>,
pub span: Option<syntax_pos::Span>,
/// map from Rust paths to resolved defs and potential URL fragments
pub links: Vec<(String, Option<DefId>, Option<String>)>,
Attributes {
doc_strings,
other_attrs,
- cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) },
+ cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
span: sp,
links: vec![],
}
promoted: None
};
let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
- cx.tcx.mk_const(ty::Const {
- val: ConstVal::Unevaluated(def_id, substs),
- ty: cx.tcx.types.usize
- })
+ ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
});
let n = print_const(cx, n);
Array(box ty.clean(cx), n)
inline::print_inlined_const(cx, def_id)
}
},
- ConstVal::Value(val) => {
+ ConstVal::Value(..) => {
let mut s = String::new();
- ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap();
+ ::rustc::mir::fmt_const_val(&mut s, n).unwrap();
// array lengths are obviously usize
if s.ends_with("usize") {
let n = s.len() - "usize".len();
edition,
..config::basic_options().clone()
};
-
- let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
- let emitter: Box<dyn Emitter + sync::Send> = match error_format {
- ErrorOutputType::HumanReadable(color_config) => Box::new(
- EmitterWriter::stderr(
- color_config,
- Some(codemap.clone()),
- false,
- sessopts.debugging_opts.teach,
- ).ui_testing(sessopts.debugging_opts.ui_testing)
- ),
- ErrorOutputType::Json(pretty) => Box::new(
- JsonEmitter::stderr(
- None,
- codemap.clone(),
- pretty,
- sessopts.debugging_opts.suggestion_applicability,
- ).ui_testing(sessopts.debugging_opts.ui_testing)
- ),
- ErrorOutputType::Short(color_config) => Box::new(
- EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
- ),
- };
-
- let diagnostic_handler = errors::Handler::with_emitter_and_flags(
- emitter,
- errors::HandlerFlags {
- can_emit_warnings: true,
- treat_err_as_bug: false,
- external_macro_backtrace: false,
- ..Default::default()
- },
- );
-
- let mut sess = session::build_session_(
- sessopts, cpath, diagnostic_handler, codemap,
- );
- let trans = rustc_driver::get_trans(&sess);
- let cstore = Rc::new(CStore::new(trans.metadata_loader()));
- rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
- target_features::add_configuration(&mut cfg, &sess, &*trans);
- sess.parse_sess.config = cfg;
-
- let control = &driver::CompileController::basic();
-
- let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
-
- let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
-
- let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
-
- let resolver_arenas = resolve::Resolver::arenas();
- let result = driver::phase_2_configure_and_expand_inner(&sess,
- &cstore,
- krate,
- None,
- &name,
- None,
- resolve::MakeGlobMap::No,
- &resolver_arenas,
- &mut crate_loader,
- |_| Ok(()));
- let driver::InnerExpansionResult {
- mut hir_forest,
- resolver,
- ..
- } = abort_on_err(result, &sess);
-
- // We need to hold on to the complete resolver, so we clone everything
- // for the analysis passes to use. Suboptimal, but necessary in the
- // current architecture.
- let defs = resolver.definitions.clone();
- let resolutions = ty::Resolutions {
- freevars: resolver.freevars.clone(),
- export_map: resolver.export_map.clone(),
- trait_map: resolver.trait_map.clone(),
- maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
- maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
- };
- let analysis = ty::CrateAnalysis {
- access_levels: Lrc::new(AccessLevels::default()),
- name: name.to_string(),
- glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
- };
-
- let arenas = AllArenas::new();
- let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
- let output_filenames = driver::build_output_filenames(&input,
- &None,
- &None,
- &[],
- &sess);
-
- let resolver = RefCell::new(resolver);
-
- abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
- control,
- &sess,
- &*cstore,
- hir_map,
- analysis,
- resolutions,
- &arenas,
- &name,
- &output_filenames,
- |tcx, analysis, _, result| {
- if let Err(_) = result {
- sess.fatal("Compilation failed, aborting rustdoc");
- }
-
- let ty::CrateAnalysis { access_levels, .. } = analysis;
-
- // Convert from a NodeId set to a DefId set since we don't always have easy access
- // to the map from defid -> nodeid
- let access_levels = AccessLevels {
- map: access_levels.map.iter()
- .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
- .collect()
+ driver::spawn_thread_pool(sessopts, move |sessopts| {
+ let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
+ let emitter: Box<dyn Emitter + sync::Send> = match error_format {
+ ErrorOutputType::HumanReadable(color_config) => Box::new(
+ EmitterWriter::stderr(
+ color_config,
+ Some(codemap.clone()),
+ false,
+ sessopts.debugging_opts.teach,
+ ).ui_testing(sessopts.debugging_opts.ui_testing)
+ ),
+ ErrorOutputType::Json(pretty) => Box::new(
+ JsonEmitter::stderr(
+ None,
+ codemap.clone(),
+ pretty,
+ sessopts.debugging_opts.suggestion_applicability,
+ ).ui_testing(sessopts.debugging_opts.ui_testing)
+ ),
+ ErrorOutputType::Short(color_config) => Box::new(
+ EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
+ ),
};
- let send_trait = if crate_name == Some("core".to_string()) {
- clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
- } else {
- clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+ let diagnostic_handler = errors::Handler::with_emitter_and_flags(
+ emitter,
+ errors::HandlerFlags {
+ can_emit_warnings: true,
+ treat_err_as_bug: false,
+ external_macro_backtrace: false,
+ ..Default::default()
+ },
+ );
+
+ let mut sess = session::build_session_(
+ sessopts, cpath, diagnostic_handler, codemap,
+ );
+ let trans = rustc_driver::get_trans(&sess);
+ let cstore = Rc::new(CStore::new(trans.metadata_loader()));
+ rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+ let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
+ sess.parse_sess.config = cfg;
+
+ let control = &driver::CompileController::basic();
+
+ let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
+
+ let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
+
+ let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
+
+ let resolver_arenas = resolve::Resolver::arenas();
+ let result = driver::phase_2_configure_and_expand_inner(&sess,
+ &cstore,
+ krate,
+ None,
+ &name,
+ None,
+ resolve::MakeGlobMap::No,
+ &resolver_arenas,
+ &mut crate_loader,
+ |_| Ok(()));
+ let driver::InnerExpansionResult {
+ mut hir_forest,
+ resolver,
+ ..
+ } = abort_on_err(result, &sess);
+
+ // We need to hold on to the complete resolver, so we clone everything
+ // for the analysis passes to use. Suboptimal, but necessary in the
+ // current architecture.
+ let defs = resolver.definitions.clone();
+ let resolutions = ty::Resolutions {
+ freevars: resolver.freevars.clone(),
+ export_map: resolver.export_map.clone(),
+ trait_map: resolver.trait_map.clone(),
+ maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
+ maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
};
-
- let ctxt = DocContext {
- tcx,
- resolver: &resolver,
- crate_name,
- cstore: cstore.clone(),
- populated_all_crate_impls: Cell::new(false),
- access_levels: RefCell::new(access_levels),
- external_traits: Default::default(),
- active_extern_traits: Default::default(),
- renderinfo: Default::default(),
- ty_substs: Default::default(),
- lt_substs: Default::default(),
- impl_trait_bounds: Default::default(),
- mod_ids: Default::default(),
- send_trait: send_trait,
- fake_def_ids: RefCell::new(FxHashMap()),
- all_fake_def_ids: RefCell::new(FxHashSet()),
- generated_synthetics: RefCell::new(FxHashSet()),
- };
- debug!("crate: {:?}", tcx.hir.krate());
-
- let krate = {
- let mut v = RustdocVisitor::new(&*cstore, &ctxt);
- v.visit(tcx.hir.krate());
- v.clean(&ctxt)
+ let analysis = ty::CrateAnalysis {
+ access_levels: Lrc::new(AccessLevels::default()),
+ name: name.to_string(),
+ glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
};
- (krate, ctxt.renderinfo.into_inner())
- }), &sess)
+ let arenas = AllArenas::new();
+ let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
+ let output_filenames = driver::build_output_filenames(&input,
+ &None,
+ &None,
+ &[],
+ &sess);
+
+ let resolver = RefCell::new(resolver);
+
+ abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
+ control,
+ &sess,
+ &*cstore,
+ hir_map,
+ analysis,
+ resolutions,
+ &arenas,
+ &name,
+ &output_filenames,
+ |tcx, analysis, _, result| {
+ if let Err(_) = result {
+ sess.fatal("Compilation failed, aborting rustdoc");
+ }
+
+ let ty::CrateAnalysis { access_levels, .. } = analysis;
+
+ // Convert from a NodeId set to a DefId set since we don't always have easy access
+ // to the map from defid -> nodeid
+ let access_levels = AccessLevels {
+ map: access_levels.map.iter()
+ .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
+ .collect()
+ };
+
+ let send_trait = if crate_name == Some("core".to_string()) {
+ clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
+ } else {
+ clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+ };
+
+ let ctxt = DocContext {
+ tcx,
+ resolver: &resolver,
+ crate_name,
+ cstore: cstore.clone(),
+ populated_all_crate_impls: Cell::new(false),
+ access_levels: RefCell::new(access_levels),
+ external_traits: Default::default(),
+ active_extern_traits: Default::default(),
+ renderinfo: Default::default(),
+ ty_substs: Default::default(),
+ lt_substs: Default::default(),
+ impl_trait_bounds: Default::default(),
+ mod_ids: Default::default(),
+ send_trait: send_trait,
+ fake_def_ids: RefCell::new(FxHashMap()),
+ all_fake_def_ids: RefCell::new(FxHashSet()),
+ generated_synthetics: RefCell::new(FxHashSet()),
+ };
+ debug!("crate: {:?}", tcx.hir.krate());
+
+ let krate = {
+ let mut v = RustdocVisitor::new(&*cstore, &ctxt);
+ v.visit(tcx.hir.krate());
+ v.clean(&ctxt)
+ };
+
+ (krate, ctxt.renderinfo.into_inner())
+ }), &sess)
+ })
}
}
fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter,
- implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> Result<(), fmt::Error> {
+ implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result {
write!(w, "<li><table class='table-display'><tbody><tr><td><code>")?;
// If there's already another implementor that has the same abbridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
fn render_impls(cx: &Context, w: &mut fmt::Formatter,
traits: &[&&Impl],
- containing_item: &clean::Item) -> Result<(), fmt::Error> {
+ containing_item: &clean::Item) -> fmt::Result {
for i in traits {
let did = i.trait_did().unwrap();
let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
#![feature(vec_remove_item)]
#![feature(entry_and_modify)]
+#![recursion_limit="256"]
+
extern crate arena;
extern crate getopts;
extern crate env_logger;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::rc::Rc;
+use std::sync::Arc;
use clean::{Crate, Item};
use clean::cfg::Cfg;
}
struct CfgPropagator {
- parent_cfg: Option<Rc<Cfg>>,
+ parent_cfg: Option<Arc<Cfg>>,
}
impl DocFolder for CfgPropagator {
(None, None) => None,
(Some(rc), None) | (None, Some(rc)) => Some(rc),
(Some(mut a), Some(b)) => {
- let b = Rc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
- *Rc::make_mut(&mut a) &= b;
+ let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
+ *Arc::make_mut(&mut a) &= b;
Some(a)
}
};
edition,
..config::basic_options().clone()
};
-
- let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
- let handler =
- errors::Handler::with_tty_emitter(ColorConfig::Auto,
- true, false,
- Some(codemap.clone()));
-
- let mut sess = session::build_session_(
- sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
- );
- let trans = rustc_driver::get_trans(&sess);
- let cstore = CStore::new(trans.metadata_loader());
- rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
- target_features::add_configuration(&mut cfg, &sess, &*trans);
- sess.parse_sess.config = cfg;
-
- let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
- &sess,
- &input));
- let driver::ExpansionResult { defs, mut hir_forest, .. } = {
- phase_2_configure_and_expand(
- &sess,
- &cstore,
- krate,
- None,
- "rustdoc-test",
- None,
- MakeGlobMap::No,
- |_| Ok(()),
- ).expect("phase_2_configure_and_expand aborted in rustdoc!")
- };
-
- let crate_name = crate_name.unwrap_or_else(|| {
- ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
- });
- let mut opts = scrape_test_config(hir_forest.krate());
- opts.display_warnings |= display_warnings;
- let mut collector = Collector::new(crate_name,
- cfgs,
- libs,
- cg,
- externs,
- false,
- opts,
- maybe_sysroot,
- Some(codemap),
- None,
- linker,
- edition);
-
- {
- let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
- let krate = map.krate();
- let mut hir_collector = HirCollector {
- sess: &sess,
- collector: &mut collector,
- map: &map
+ driver::spawn_thread_pool(sessopts, |sessopts| {
+ let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
+ let handler =
+ errors::Handler::with_tty_emitter(ColorConfig::Auto,
+ true, false,
+ Some(codemap.clone()));
+
+ let mut sess = session::build_session_(
+ sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
+ );
+ let trans = rustc_driver::get_trans(&sess);
+ let cstore = CStore::new(trans.metadata_loader());
+ rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+ let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
+ sess.parse_sess.config = cfg;
+
+ let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
+ &sess,
+ &input));
+ let driver::ExpansionResult { defs, mut hir_forest, .. } = {
+ phase_2_configure_and_expand(
+ &sess,
+ &cstore,
+ krate,
+ None,
+ "rustdoc-test",
+ None,
+ MakeGlobMap::No,
+ |_| Ok(()),
+ ).expect("phase_2_configure_and_expand aborted in rustdoc!")
};
- hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
- intravisit::walk_crate(this, krate);
+
+ let crate_name = crate_name.unwrap_or_else(|| {
+ ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
});
- }
+ let mut opts = scrape_test_config(hir_forest.krate());
+ opts.display_warnings |= display_warnings;
+ let mut collector = Collector::new(
+ crate_name,
+ cfgs,
+ libs,
+ cg,
+ externs,
+ false,
+ opts,
+ maybe_sysroot,
+ Some(codemap),
+ None,
+ linker,
+ edition
+ );
+
+ {
+ let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
+ let krate = map.krate();
+ let mut hir_collector = HirCollector {
+ sess: &sess,
+ collector: &mut collector,
+ map: &map
+ };
+ hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
+ intravisit::walk_crate(this, krate);
+ });
+ }
- test_args.insert(0, "rustdoctest".to_string());
+ test_args.insert(0, "rustdoctest".to_string());
- testing::test_main(&test_args,
- collector.tests.into_iter().collect(),
- testing::Options::new().display_output(display_warnings));
- 0
+ testing::test_main(&test_args,
+ collector.tests.into_iter().collect(),
+ testing::Options::new().display_output(display_warnings));
+ 0
+ })
}
// Look for #![doc(test(no_crate_inject))], used by crates in the std facade
..config::basic_options().clone()
};
- // Shuffle around a few input and output handles here. We're going to pass
- // an explicit handle into rustc to collect output messages, but we also
- // want to catch the error message that rustc prints when it fails.
- //
- // We take our thread-local stderr (likely set by the test runner) and replace
- // it with a sink that is also passed to rustc itself. When this function
- // returns the output of the sink is copied onto the output of our own thread.
- //
- // The basic idea is to not use a default Handler for rustc, and then also
- // not print things by default to the actual stderr.
- struct Sink(Arc<Mutex<Vec<u8>>>);
- impl Write for Sink {
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- Write::write(&mut *self.0.lock().unwrap(), data)
+ let (libdir, outdir) = driver::spawn_thread_pool(sessopts, |sessopts| {
+ // Shuffle around a few input and output handles here. We're going to pass
+ // an explicit handle into rustc to collect output messages, but we also
+ // want to catch the error message that rustc prints when it fails.
+ //
+ // We take our thread-local stderr (likely set by the test runner) and replace
+ // it with a sink that is also passed to rustc itself. When this function
+ // returns the output of the sink is copied onto the output of our own thread.
+ //
+ // The basic idea is to not use a default Handler for rustc, and then also
+ // not print things by default to the actual stderr.
+ struct Sink(Arc<Mutex<Vec<u8>>>);
+ impl Write for Sink {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ Write::write(&mut *self.0.lock().unwrap(), data)
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
- fn flush(&mut self) -> io::Result<()> { Ok(()) }
- }
- struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
- impl Drop for Bomb {
- fn drop(&mut self) {
- let _ = self.1.write_all(&self.0.lock().unwrap());
+ struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
+ impl Drop for Bomb {
+ fn drop(&mut self) {
+ let _ = self.1.write_all(&self.0.lock().unwrap());
+ }
}
- }
- let data = Arc::new(Mutex::new(Vec::new()));
- let codemap = Lrc::new(CodeMap::new_doctest(
- sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
- ));
- let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
- Some(codemap.clone()),
- false,
- false);
- let old = io::set_panic(Some(box Sink(data.clone())));
- let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
-
- // Compile the code
- let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
-
- let mut sess = session::build_session_(
- sessopts, None, diagnostic_handler, codemap,
- );
- let trans = rustc_driver::get_trans(&sess);
- let cstore = CStore::new(trans.metadata_loader());
- rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
- let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
- let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
- let mut control = driver::CompileController::basic();
-
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
- target_features::add_configuration(&mut cfg, &sess, &*trans);
- sess.parse_sess.config = cfg;
-
- let out = Some(outdir.lock().unwrap().path().to_path_buf());
-
- if no_run {
- control.after_analysis.stop = Compilation::Stop;
- }
-
- let res = panic::catch_unwind(AssertUnwindSafe(|| {
- driver::compile_input(
- trans,
- &sess,
- &cstore,
- &None,
- &input,
- &out,
- &None,
- None,
- &control
- )
- }));
-
- let compile_result = match res {
- Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
- Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
- };
-
- match (compile_result, compile_fail) {
- (Ok(()), true) => {
- panic!("test compiled while it wasn't supposed to")
+ let data = Arc::new(Mutex::new(Vec::new()));
+ let codemap = Lrc::new(CodeMap::new_doctest(
+ sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
+ ));
+ let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
+ Some(codemap.clone()),
+ false,
+ false);
+ let old = io::set_panic(Some(box Sink(data.clone())));
+ let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
+
+ // Compile the code
+ let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
+
+ let mut sess = session::build_session_(
+ sessopts, None, diagnostic_handler, codemap,
+ );
+ let trans = rustc_driver::get_trans(&sess);
+ let cstore = CStore::new(trans.metadata_loader());
+ rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+ let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
+ let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
+ let mut control = driver::CompileController::basic();
+
+ let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
+ sess.parse_sess.config = cfg;
+
+ let out = Some(outdir.lock().unwrap().path().to_path_buf());
+
+ if no_run {
+ control.after_analysis.stop = Compilation::Stop;
}
- (Ok(()), false) => {}
- (Err(()), true) => {
- if error_codes.len() > 0 {
- let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
- error_codes.retain(|err| !out.contains(err));
+
+ let res = panic::catch_unwind(AssertUnwindSafe(|| {
+ driver::compile_input(
+ trans,
+ &sess,
+ &cstore,
+ &None,
+ &input,
+ &out,
+ &None,
+ None,
+ &control
+ )
+ }));
+
+ let compile_result = match res {
+ Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
+ Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
+ };
+
+ match (compile_result, compile_fail) {
+ (Ok(()), true) => {
+ panic!("test compiled while it wasn't supposed to")
+ }
+ (Ok(()), false) => {}
+ (Err(()), true) => {
+ if error_codes.len() > 0 {
+ let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
+ error_codes.retain(|err| !out.contains(err));
+ }
+ }
+ (Err(()), false) => {
+ panic!("couldn't compile the test")
}
}
- (Err(()), false) => {
- panic!("couldn't compile the test")
+
+ if error_codes.len() > 0 {
+ panic!("Some expected error codes were not found: {:?}", error_codes);
}
- }
- if error_codes.len() > 0 {
- panic!("Some expected error codes were not found: {:?}", error_codes);
- }
+ (libdir, outdir)
+ });
if no_run { return }
///
/// fn main() -> std::io::Result<()> {
/// fs::write("foo.txt", b"Lorem ipsum")?;
+/// fs::write("bar.txt", "dolor sit")?;
/// Ok(())
/// }
/// ```
fs_imp::readlink(path.as_ref())
}
-/// Returns the canonical form of a path with all intermediate components
-/// normalized and symbolic links resolved.
+/// Returns the canonical, absolute form of a path with all intermediate
+/// components normalized and symbolic links resolved.
///
/// # Platform-specific behavior
///
/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
/// Note that, this [may change in the future][changes].
///
+/// On Windows, this converts the path to use [extended length path][path]
+/// syntax, which allows your program to use longer path names, but means you
+/// can only join backslash-delimited paths to it, and it may be incompatible
+/// with other applications (if passed to the application on the command-line,
+/// or written to a file another application may read).
+///
/// [changes]: ../io/index.html#platform-specific-behavior
+/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
///
/// # Errors
///
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for PathBuf {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter)
}
}
fs::symlink_metadata(self)
}
- /// Returns the canonical form of the path with all intermediate components
- /// normalized and symbolic links resolved.
+ /// Returns the canonical, absolute form of the path with all intermediate
+ /// components normalized and symbolic links resolved.
///
/// This is an alias to [`fs::canonicalize`].
///
}
impl fmt::Debug for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.text())
}
}
impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.text())
}
}
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
-> io::Result<isize>
{
+ use convert::TryInto;
use libc::pread64;
- cvt(pread64(fd, buf, count, offset as i32))
+ // pread64 on emscripten actually takes a 32 bit offset
+ if let Ok(o) = offset.try_into() {
+ cvt(pread64(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pread >2GB"))
+ }
}
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
-> io::Result<isize>
{
+ use convert::TryInto;
use libc::pwrite64;
- cvt(pwrite64(fd, buf, count, offset as i32))
+ // pwrite64 on emscripten actually takes a 32 bit offset
+ if let Ok(o) = offset.try_into() {
+ cvt(pwrite64(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pwrite >2GB"))
+ }
}
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
/// Example: `U+1F4A9`
impl fmt::Debug for CodePoint {
#[inline]
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "U+{:04X}", self.value)
}
}
/// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]
impl fmt::Debug for Wtf8Buf {
#[inline]
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter)
}
}
impl Edition {
pub fn lint_name(&self) -> &'static str {
match *self {
- Edition::Edition2015 => "rust_2015_breakage",
- Edition::Edition2018 => "rust_2018_breakage",
+ Edition::Edition2015 => "rust_2015_compatibility",
+ Edition::Edition2018 => "rust_2018_compatibility",
}
}
(active, rustc_attrs, "1.0.0", Some(29642), None),
// Allows the use of non lexical lifetimes; RFC 2094
- (active, nll, "1.0.0", Some(43234), Some(Edition::Edition2018)),
+ (active, nll, "1.0.0", Some(43234), None),
// Allows the use of #[allow_internal_unstable]. This is an
// attribute on macro_rules! and can't use the attribute handling
continue
}
- match attr.meta_item_list() {
+ let list = match attr.meta_item_list() {
+ Some(list) => list,
None => {
span_err!(span_handler, attr.span, E0555,
"malformed feature attribute, expected #![feature(...)]");
+ continue
+ }
+ };
+
+ for mi in list {
+ let name = if let Some(word) = mi.word() {
+ word.name()
+ } else {
+ span_err!(span_handler, mi.span, E0556,
+ "malformed feature, expected just one word");
+ continue
+ };
+
+ if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
+ set(&mut features, mi.span);
+ feature_checker.collect(&features, mi.span);
+ continue
}
- Some(list) => {
- for mi in list {
- let name = if let Some(word) = mi.word() {
- word.name()
- } else {
- span_err!(span_handler, mi.span, E0556,
- "malformed feature, expected just one word");
- continue
- };
-
- if let Some(&(_, _, _, _, set)) = ACTIVE_FEATURES.iter()
- .find(|& &(n, ..)| name == n) {
- set(&mut features, mi.span);
- feature_checker.collect(&features, mi.span);
- }
- else if let Some(&(.., reason)) = REMOVED_FEATURES.iter()
- .find(|& &(n, ..)| name == n)
- .or_else(|| STABLE_REMOVED_FEATURES.iter()
- .find(|& &(n, ..)| name == n)) {
- feature_removed(span_handler, mi.span, reason);
- }
- else if let Some(&(..)) = ACCEPTED_FEATURES.iter()
- .find(|& &(n, ..)| name == n) {
- features.declared_stable_lang_features.push((name, mi.span));
- } else if let Some(&edition) = ALL_EDITIONS.iter()
- .find(|e| name == e.feature_name()) {
- if edition <= crate_edition {
- feature_removed(span_handler, mi.span, None);
- } else {
- for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
- if let Some(f_edition) = f_edition {
- if edition >= f_edition {
- // FIXME(Manishearth) there is currently no way to set
- // lib features by edition
- set(&mut features, DUMMY_SP);
- }
- }
- }
+ let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
+ let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
+ if let Some((.., reason)) = removed.or(stable_removed) {
+ feature_removed(span_handler, mi.span, *reason);
+ continue
+ }
+
+ if ACCEPTED_FEATURES.iter().any(|f| name == f.0) {
+ features.declared_stable_lang_features.push((name, mi.span));
+ continue
+ }
+
+ if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
+ if *edition <= crate_edition {
+ continue
+ }
+
+ for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
+ if let Some(f_edition) = f_edition {
+ if *edition >= f_edition {
+ // FIXME(Manishearth) there is currently no way to set
+ // lib features by edition
+ set(&mut features, DUMMY_SP);
}
- } else {
- features.declared_lib_features.push((name, mi.span));
}
}
+
+ continue
}
+
+ features.declared_lib_features.push((name, mi.span));
}
}
}
}
-struct Globals {
+pub struct Globals {
used_attrs: Lock<Vec<u64>>,
known_attrs: Lock<Vec<u64>>,
syntax_pos_globals: syntax_pos::Globals,
})
}
-scoped_thread_local!(static GLOBALS: Globals);
+scoped_thread_local!(pub static GLOBALS: Globals);
#[macro_use]
pub mod diagnostics {
}
impl<'a> std::fmt::Debug for StrCursor<'a> {
- fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
}
}
[dependencies]
serialize = { path = "../libserialize" }
rustc_data_structures = { path = "../librustc_data_structures" }
+arena = { path = "../libarena" }
scoped-tls = { version = "0.1.1", features = ["nightly"] }
unicode-width = "0.1.4"
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{Lrc, Lock};
+extern crate arena;
extern crate rustc_data_structures;
#[macro_use]
use {Span, DUMMY_SP, GLOBALS};
use rustc_data_structures::fx::FxHashMap;
+use arena::DroplessArena;
use serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
+use std::str;
use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
use std::hash::{Hash, Hasher};
}
}
-#[derive(Default)]
+// The &'static strs in this type actually point into the arena
pub struct Interner {
- names: FxHashMap<Box<str>, Symbol>,
- strings: Vec<Box<str>>,
+ arena: DroplessArena,
+ names: FxHashMap<&'static str, Symbol>,
+ strings: Vec<&'static str>,
gensyms: Vec<Symbol>,
}
impl Interner {
pub fn new() -> Self {
- Interner::default()
+ Interner {
+ arena: DroplessArena::new(),
+ names: Default::default(),
+ strings: Default::default(),
+ gensyms: Default::default(),
+ }
}
fn prefill(init: &[&str]) -> Self {
let mut this = Interner::new();
for &string in init {
- this.intern(string);
+ if string == "" {
+ // We can't allocate empty strings in the arena, so handle this here
+ let name = Symbol(this.strings.len() as u32);
+ this.names.insert("", name);
+ this.strings.push("");
+ } else {
+ this.intern(string);
+ }
}
this
}
}
let name = Symbol(self.strings.len() as u32);
- let string = string.to_string().into_boxed_str();
- self.strings.push(string.clone());
+
+ // from_utf8_unchecked is safe since we just allocated a &str which is known to be utf8
+ let string: &str = unsafe {
+ str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes()))
+ };
+ // It is safe to extend the arena allocation to 'static because we only access
+ // these while the arena is still alive
+ let string: &'static str = unsafe {
+ &*(string as *const str)
+ };
+ self.strings.push(string);
self.names.insert(string, name);
name
}
pub fn get(&self, symbol: Symbol) -> &str {
match self.strings.get(symbol.0 as usize) {
- Some(ref string) => string,
+ Some(string) => string,
None => self.get(self.gensyms[(!0 - symbol.0) as usize]),
}
}
if self.symbol == other.symbol {
return Some(Ordering::Equal);
}
- self.with(|self_str| other.with(|other_str| self_str.partial_cmp(&other_str)))
+ self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str)))
}
}
extern "C" void LLVMRustConfigurePassManagerBuilder(
LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
- bool MergeFunctions, bool SLPVectorize, bool LoopVectorize,
+ bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
const char* PGOGenPath, const char* PGOUsePath) {
// Ignore mergefunc for now as enabling it causes crashes.
// unwrap(PMBR)->MergeFunctions = MergeFunctions;
unwrap(PMBR)->SLPVectorize = SLPVectorize;
unwrap(PMBR)->OptLevel = fromRust(OptLevel);
unwrap(PMBR)->LoopVectorize = LoopVectorize;
+#if LLVM_VERSION_GE(4, 0)
+ unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
+#endif
#ifdef PGO_AVAILABLE
if (PGOGenPath) {
#![crate_type = "lib"]
-// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
+// CHECK: @VAR1 = constant i32 1, section ".test_one"
#[no_mangle]
#[link_section = ".test_one"]
-#[cfg(target_endian = "little")]
pub static VAR1: u32 = 1;
-#[no_mangle]
-#[link_section = ".test_one"]
-#[cfg(target_endian = "big")]
-pub static VAR1: u32 = 0x01000000;
-
pub enum E {
A(u32),
B(f32)
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// intentionally empty
--- /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:edition-extern-crate-allowed.rs
+// compile-flags: --edition 2015
+// compile-pass
+
+#![deny(rust_2018_idioms)]
+
+extern crate edition_extern_crate_allowed;
+
+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.
+
+// compile-flags:--edition 2018
+// compile-pass
+
+#![feature(rust_2018_preview)]
+
+fn main() {}
--- /dev/null
+-include ../tools.mk
+
+all: foo
+ $(call RUN,foo)
+
+foo: foo.rs $(call NATIVE_STATICLIB,foo)
+ $(RUSTC) $< -lfoo $(EXTRACXXFLAGS)
+
+$(TMPDIR)/libfoo.o: foo.cpp
+ $(call COMPILE_OBJ_CXX,$@,$<)
+
+.PHONY: all
--- /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.
+
+#include <stdint.h>
+
+struct A {
+ A() { v = 1234; }
+ ~A() { v = 1; }
+ uint32_t v;
+};
+
+A a;
+
+extern "C" {
+ uint32_t get() {
+ return a.v;
+ }
+}
--- /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.
+
+// Tests that linking to C++ code with global destructors works.
+
+extern { fn get() -> u32; }
+
+fn main() {
+ let i = unsafe { get() };
+ assert_eq!(i, 1234);
+}
ifdef IS_MSVC
COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -Fo:`cygpath -w $(1)` $(2)
NATIVE_STATICLIB_FILE = $(1).lib
NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
-Fo:`cygpath -w $(TMPDIR)/$(1).obj`
else
COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
NATIVE_STATICLIB_FILE = lib$(1).a
NATIVE_STATICLIB = $(call STATICLIB,$(1))
OUT_EXE=-o $(TMPDIR)/$(1)
struct SlowFmt(u32);
impl fmt::Debug for SlowFmt {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
thread::sleep_ms(3);
self.0.fmt(f)
}
}
impl fmt::Display for U {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe { write!(f, "Oh hai {}", self.a) }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --edition 2018
+
#![deny(unnecessary_extern_crate)]
#![feature(alloc, test, libc)]
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:14:1
+ --> $DIR/unnecessary-extern-crate.rs:16:1
|
LL | extern crate alloc;
| ^^^^^^^^^^^^^^^^^^^ help: remove it
|
note: lint level defined here
- --> $DIR/unnecessary-extern-crate.rs:11:9
+ --> $DIR/unnecessary-extern-crate.rs:13:9
|
LL | #![deny(unnecessary_extern_crate)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:17:1
+ --> $DIR/unnecessary-extern-crate.rs:19:1
|
LL | extern crate alloc as x;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:23:1
+ --> $DIR/unnecessary-extern-crate.rs:25:1
|
LL | pub extern crate test as y;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:26:1
+ --> $DIR/unnecessary-extern-crate.rs:28:1
|
LL | pub extern crate libc;
| ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:32:5
+ --> $DIR/unnecessary-extern-crate.rs:34:5
|
LL | extern crate alloc;
| ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:35:5
+ --> $DIR/unnecessary-extern-crate.rs:37:5
|
LL | extern crate alloc as x;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:38:5
+ --> $DIR/unnecessary-extern-crate.rs:40:5
|
LL | pub extern crate test;
| ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:41:5
+ --> $DIR/unnecessary-extern-crate.rs:43:5
|
LL | pub extern crate test as y;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:45:9
+ --> $DIR/unnecessary-extern-crate.rs:47:9
|
LL | extern crate alloc;
| ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:48:9
+ --> $DIR/unnecessary-extern-crate.rs:50:9
|
LL | extern crate alloc as x;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
LL | x % 2 == 0
| ^^^^^
|
- = note: this is a reference to a type that `%` can be applied to; you need to dereference this variable once for this operation to work
- = note: an implementation of `std::ops::Rem` might be missing for `&&{integer}`
+ = help: `%` can be used on '{integer}', you can dereference `x`: `*x`
error: aborting due to previous error
--> $DIR/issue-28308.rs:12:5
|
LL | assert!("foo");
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
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.
+
+// compile-pass
+
+#![feature(duration_getters)]
+
+use std::time::Duration;
+
+fn main() {
+ const _ONE_SECOND: Duration = Duration::from_nanos(1_000_000_000);
+ const _ONE_MILLISECOND: Duration = Duration::from_nanos(1_000_000);
+ const _ONE_MICROSECOND: Duration = Duration::from_nanos(1_000);
+ const _ONE_NANOSECOND: Duration = Duration::from_nanos(1);
+ const _ONE: usize = _ONE_SECOND.as_secs() as usize;
+ const _TWO: usize = _ONE_MILLISECOND.subsec_millis() as usize;
+ const _THREE: usize = _ONE_MICROSECOND.subsec_micros() as usize;
+ const _FOUR: usize = _ONE_NANOSECOND.subsec_nanos() as usize;
+ const _0: [[u8; _ONE]; _TWO] = [[1; _ONE]; _TWO];
+ const _1: [[u8; _THREE]; _FOUR] = [[3; _THREE]; _FOUR];
+}
| -----------------^^^^^
| |
| cannot use `+=` on type `std::collections::LinkedList<_>`
+ |
+ = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>`
error[E0067]: invalid left-hand side expression
--> $DIR/E0067.rs:14:5
--> $DIR/E0600.rs:12:5
|
LL | !"a"; //~ ERROR E0600
- | ^^^^
+ | ^^^^ cannot apply unary operator `!`
error: aborting due to previous error
| -^^^^^
| |
| cannot use `+=` on type `&str`
+ |
+ = note: an implementation of `std::ops::AddAssign` might be missing for `&str`
error[E0599]: no method named `z` found for type `&str` in the current scope
--> $DIR/error-festival.rs:26:7
--> $DIR/error-festival.rs:29:5
|
LL | !Question::Yes;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ cannot apply unary operator `!`
+ |
+ = note: an implementation of `std::ops::Not` might be missing for `Question`
error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/error-festival.rs:35:5
--> $DIR/feature-gate-negate-unsigned.rs:20:23
|
LL | let _max: usize = -1;
- | ^^
+ | ^^ cannot apply unary operator `-`
+ |
+ = note: unsigned values cannot be negated
error[E0600]: cannot apply unary operator `-` to type `u8`
--> $DIR/feature-gate-negate-unsigned.rs:24:14
|
LL | let _y = -x;
- | ^^
+ | ^^ cannot apply unary operator `-`
+ |
+ = note: unsigned values cannot be negated
error: aborting due to 2 previous errors
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-// FIXME(#44752) -- this scenario should not be warned
-fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
- 22
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-2.rs:12:10
- |
-LL | fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-2.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- x: &'x u32 // no warning!
-}
-
-// Once #44524 is fixed, this should issue a warning.
-impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
- fn method() { }
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-3.rs:11:12
- |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-3.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'y` only used once
- --> $DIR/single_use_lifetimes-3.rs:16:6
- |
-LL | impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
- | ^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
- // Neither should issue a warning, as explicit lifetimes are mandatory in this case
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- x: &'x u32
-}
-
-enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
- Variant(&'x u32)
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-4.rs:12:12
- |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-4.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-4.rs:16:10
- |
-LL | enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-// Should not issue a warning, as explicit lifetimes are mandatory in this case:
-trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
- fn foo(&self, arg: &'x u32);
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-5.rs:12:11
- |
-LL | trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-5.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-
-fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
- *v
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes.rs:12:10
- |
-LL | fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-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.
+
+#[derive(Clone, Copy)]
+//~^ ERROR the trait `Copy` may not be implemented for this type
+struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+//~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR the trait bound `i32: std::iter::Iterator` is not satisfied
+
+fn main() {}
--- /dev/null
+error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:13:12
+ |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^ not found in this scope
+
+error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+ --> $DIR/issue-50480.rs:13:24
+ |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+ |
+ = help: the trait `std::iter::Iterator` is not implemented for `i32`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/issue-50480.rs:11:17
+ |
+LL | #[derive(Clone, Copy)]
+ | ^^^^
+LL | //~^ ERROR the trait `Copy` may not be implemented for this type
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -------- ------ this field does not implement `Copy`
+ | |
+ | this field does not implement `Copy`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0204, E0277, E0412.
+For more information about an error, try `rustc --explain E0204`.
| -^^^^^
| |
| cannot use `+=` on type `&isize`
+ |
+ = help: `+=` can be used on 'isize', you can dereference `x`: `*x`
error: aborting due to previous error
mod private_mod {
// non-leaked `pub` items in private module should be linted
pub use std::fmt;
+ pub use std::env::{Args}; // braced-use has different item spans than unbraced
pub struct Hydrogen {
// `pub` struct fields, too
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:28:5
+ --> $DIR/unreachable_pub-pub_crate.rs:27:24
+ |
+LL | pub use std::env::{Args}; // braced-use has different item spans than unbraced
+ | ^^^^ help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:29:5
|
LL | pub struct Hydrogen {
| ---^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` field
- --> $DIR/unreachable_pub-pub_crate.rs:30:9
+ --> $DIR/unreachable_pub-pub_crate.rs:31:9
|
LL | pub neutrons: usize,
| ---^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `pub(crate)`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:36:9
+ --> $DIR/unreachable_pub-pub_crate.rs:37:9
|
LL | pub fn count_neutrons(&self) -> usize { self.neutrons }
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `pub(crate)`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:40:5
+ --> $DIR/unreachable_pub-pub_crate.rs:41:5
|
LL | pub enum Helium {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:41:5
+ --> $DIR/unreachable_pub-pub_crate.rs:42:5
|
LL | pub union Lithium { c1: usize, c2: u8 }
| ---^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:42:5
+ --> $DIR/unreachable_pub-pub_crate.rs:43:5
|
LL | pub fn beryllium() {}
| ---^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:43:5
+ --> $DIR/unreachable_pub-pub_crate.rs:44:5
|
LL | pub trait Boron {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:44:5
+ --> $DIR/unreachable_pub-pub_crate.rs:45:5
|
LL | pub const CARBON: usize = 1;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:45:5
+ --> $DIR/unreachable_pub-pub_crate.rs:46:5
|
LL | pub static NITROGEN: usize = 2;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:46:5
+ --> $DIR/unreachable_pub-pub_crate.rs:47:5
|
LL | pub type Oxygen = bool;
| ---^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:49:47
+ --> $DIR/unreachable_pub-pub_crate.rs:50:47
|
LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
| -----------^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:54:9
+ --> $DIR/unreachable_pub-pub_crate.rs:55:9
|
LL | pub fn catalyze() -> bool;
| ---^^^^^^^^^^^^^^^^^^^^^^^
mod private_mod {
// non-leaked `pub` items in private module should be linted
pub use std::fmt;
+ pub use std::env::{Args}; // braced-use has different item spans than unbraced
pub struct Hydrogen {
// `pub` struct fields, too
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:23:5
+ --> $DIR/unreachable_pub.rs:22:24
+ |
+LL | pub use std::env::{Args}; // braced-use has different item spans than unbraced
+ | ^^^^ help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:24:5
|
LL | pub struct Hydrogen {
| ---^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` field
- --> $DIR/unreachable_pub.rs:25:9
+ --> $DIR/unreachable_pub.rs:26:9
|
LL | pub neutrons: usize,
| ---^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `crate`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:31:9
+ --> $DIR/unreachable_pub.rs:32:9
|
LL | pub fn count_neutrons(&self) -> usize { self.neutrons }
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `crate`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:35:5
+ --> $DIR/unreachable_pub.rs:36:5
|
LL | pub enum Helium {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:36:5
+ --> $DIR/unreachable_pub.rs:37:5
|
LL | pub union Lithium { c1: usize, c2: u8 }
| ---^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:37:5
+ --> $DIR/unreachable_pub.rs:38:5
|
LL | pub fn beryllium() {}
| ---^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:38:5
+ --> $DIR/unreachable_pub.rs:39:5
|
LL | pub trait Boron {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:39:5
+ --> $DIR/unreachable_pub.rs:40:5
|
LL | pub const CARBON: usize = 1;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:40:5
+ --> $DIR/unreachable_pub.rs:41:5
|
LL | pub static NITROGEN: usize = 2;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:41:5
+ --> $DIR/unreachable_pub.rs:42:5
|
LL | pub type Oxygen = bool;
| ---^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:44:47
+ --> $DIR/unreachable_pub.rs:45:47
|
LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
| -----------^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:49:9
+ --> $DIR/unreachable_pub.rs:50:9
|
LL | pub fn catalyze() -> bool;
| ---^^^^^^^^^^^^^^^^^^^^^^^
--> $DIR/expr_unary.rs:17:16
|
LL | let x: ! = ! { return; }; //~ ERROR unreachable
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^ cannot apply unary operator `!`
error: unreachable expression
--> $DIR/expr_unary.rs:17:16
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+struct Foo {
+ a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+ b: for<'a> fn(&'a u32, &'a u32), // OK, used twice.
+ c: for<'a> fn(&'a u32) -> &'a u32, // OK, used twice.
+ d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+ //~^ ERROR return type references lifetime `'a`, which is not constrained by the fn input types
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` only used once
+ --> $DIR/fn-types.rs:19:10
+ |
+LL | a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/fn-types.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
+ --> $DIR/fn-types.rs:22:22
+ |
+LL | d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0581`.
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(in_band_lifetimes)]
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument, even with in band lifetimes.
+
+fn a(x: &'a u32, y: &'b u32) {
+ //~^ ERROR `'a` only used once
+ //~| ERROR `'b` only used once
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'b` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:19:22
+ |
+LL | fn a(x: &'a u32, y: &'b u32) {
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-fn-argument-in-band.rs:12:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:19:10
+ |
+LL | fn a(x: &'a u32, y: &'b u32) {
+ | ^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-fn-argument.rs:18:6
+ |
+LL | fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-fn-argument.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn when lifetime name is used only
+// once in a fn return type -- using `'_` is not legal there,
+// as it must refer back to an argument.
+//
+// (Normally, using `'static` would be preferred, but there are
+// times when that is not what you want.)
+//
+// run-pass
+
+fn b<'a>() -> &'a u32 { // OK: used only in return type
+ &22
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an impl.
+//
+// (Actually, until #15872 is fixed, you can't use `'_` here, but
+// hopefully that will come soon.)
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a(&self) {
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'f` only used once
+ --> $DIR/one-use-in-inherent-impl-header.rs:24:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-inherent-impl-header.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an inherent method.
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-inherent-method-argument.rs:22:19
+ |
+LL | fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-inherent-method-argument.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'f` only used once
+ --> $DIR/one-use-in-inherent-method-argument.rs:21:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn for a lifetime used just once in a return type,
+// where that return type is in an inherent method.
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a<'a>(&self) -> &'a u32 { // OK for 'a
+ &22
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'f` only used once
+ --> $DIR/one-use-in-inherent-method-return.rs:22:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-inherent-method-return.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we do not warn for named lifetimes in structs,
+// even when they are only used once (since to not use a named
+// lifetime is illegal!)
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+enum Bar<'f> {
+ Data(&'f u32)
+}
+
+trait Baz<'f> { }
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn for a lifetime on an impl used only in `&self`
+// in a trait method.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+ type Item = &'f u32;
+
+ fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+ None
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'g` only used once
+ --> $DIR/one-use-in-trait-method-argument.rs:25:13
+ |
+LL | fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-trait-method-argument.rs:14:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn when lifetime name is used in
+// both the argument and return.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32) -> &'a u32 { // OK: used twice
+ &22
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn when lifetime name is used multiple
+// argments, or more than once in a single argument.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32, y: &'a u32) { // OK: used twice
+}
+
+fn d<'a>(x: (&'a u32, &'a u32)) { // OK: used twice
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> {
+ fn inherent_a(&self, data: &'f u32) {
+ }
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl method and
+// header.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a<'a>(&self, data: &'a u32) -> &'a u32{
+ data
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'f` only used once
+ --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:22:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:14:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime on an impl used in both
+// header and in an associated type.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+ type Item = &'f u32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn d<'a>() { } //~ ERROR `'a` never used
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` never used
+ --> $DIR/zero-uses-in-fn.rs:17:6
+ |
+LL | fn d<'a>() { } //~ ERROR `'a` never used
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/zero-uses-in-fn.rs:13:9
+ |
+LL | #![deny(unused_lifetime)]
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo { }
+
+impl<'a> Foo { } //~ ERROR `'a` never used
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` never used
+ --> $DIR/zero-uses-in-impl.rs:19:6
+ |
+LL | impl<'a> Foo { } //~ ERROR `'a` never used
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/zero-uses-in-impl.rs:13:9
+ |
+LL | #![deny(unused_lifetime)]
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
fn foo<T>(x: T, y: T) {
let z = x + y; //~ ERROR binary operation `+` cannot be applied to type `T`
}
+
+fn bar<T>(x: T) {
+ x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+}
|
= note: `T` might need a bound for `std::ops::Add`
-error: aborting due to previous error
+error[E0368]: binary assignment operation `+=` cannot be applied to type `T`
+ --> $DIR/missing_trait_impl.rs:19:5
+ |
+LL | x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+ | -^^^^^
+ | |
+ | cannot use `+=` on type `T`
+ |
+ = note: `T` might need a bound for `std::ops::AddAssign`
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0369`.
+Some errors occurred: E0368, E0369.
+For more information about an error, try `rustc --explain E0368`.
-Subproject commit e456241f18227c7eb8d78a45daa66c756a9b65e7
+Subproject commit 7a4c00c669b3bf0ffb24c7aa89a776cd48f1e2d0
.env("IS_WINDOWS", "1")
.env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
.env("CC", format!("'{}' {}", self.config.cc, cflags))
- .env("CXX", &self.config.cxx);
+ .env("CXX", format!("'{}'", &self.config.cxx));
} else {
cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
.env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
-Subproject commit e0e1bd7ff778e5913b566c9e03224faecc0eb486
+Subproject commit 6a4c62c1673c3dabcc9a0c99018bd08fec46fda7
static WHITELIST: &'static [Crate] = &[
Crate("aho-corasick"),
Crate("ar"),
+ Crate("arrayvec"),
Crate("atty"),
Crate("backtrace"),
Crate("backtrace-sys"),
Crate("cc"),
Crate("cfg-if"),
Crate("cmake"),
+ Crate("crossbeam-deque"),
+ Crate("crossbeam-epoch"),
+ Crate("crossbeam-utils"),
+ Crate("either"),
Crate("ena"),
Crate("env_logger"),
Crate("filetime"),
Crate("log"),
Crate("log_settings"),
Crate("memchr"),
+ Crate("memoffset"),
Crate("miniz-sys"),
+ Crate("nodrop"),
Crate("num_cpus"),
Crate("owning_ref"),
Crate("parking_lot"),
Crate("regex-syntax"),
Crate("remove_dir_all"),
Crate("rustc-demangle"),
+ Crate("rustc-rayon"),
+ Crate("rustc-rayon-core"),
Crate("scoped-tls"),
+ Crate("scopeguard"),
Crate("smallvec"),
Crate("stable_deref_trait"),
Crate("tempdir"),
&libcore_path,
&mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
&mut |subpath| {
- if t!(read_to_string(subpath)).contains("#[test]") {
- tidy_error!(
- bad,
- "{} contains #[test]; libcore tests must be placed inside `src/libcore/tests/`",
- subpath.display()
- );
+ if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
+ match read_to_string(subpath) {
+ Ok(contents) => {
+ if contents.contains("#[test]") {
+ tidy_error!(
+ bad,
+ "{} contains #[test]; libcore tests must be placed inside \
+ `src/libcore/tests/`",
+ subpath.display()
+ );
+ }
+ }
+ Err(err) => {
+ panic!("failed to read file {:?}: {}", subpath, err);
+ }
+ }
}
},
);