# compiler.
#codegen-units = 1
+# Whether to enable ThinLTO (and increase the codegen units to either a default
+# or the configured value). On by default. If we want the fastest possible
+# compiler, we should disable this.
+#thinlto = true
+
# Whether or not debug assertions are enabled for the compiler and standard
# library. Also enables compilation of debug! and trace! logging macros.
#debug-assertions = false
# Flag indicating whether git info will be retrieved from .git automatically.
# Having the git information can cause a lot of rebuilds during development.
-# Note: If this attribute is not explicity set (e.g. if left commented out) it
+# Note: If this attribute is not explicitly set (e.g. if left commented out) it
# will default to true if channel = "dev", but will default to false otherwise.
#ignore-git = true
# bootstrap)
#codegen-backends = ["llvm"]
+# Flag indicating whether `libstd` calls an imported function to handle basic IO
+# when targeting WebAssembly. Enable this to debug tests for the `wasm32-unknown-unknown`
+# target, as without this option the test output will not be captured.
+#wasm-syscall = false
+
# =============================================================================
# Options for specific targets
#
#linker = "cc"
# Path to the `llvm-config` binary of the installation of a custom LLVM to link
-# against. Note that if this is specifed we don't compile LLVM at all for this
+# against. Note that if this is specified we don't compile LLVM at all for this
# target.
#llvm-config = "../path/to/llvm/root/bin/llvm-config"
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "clippy"
-version = "0.0.174"
+version = "0.0.186"
dependencies = [
"cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy-mini-macro-test 0.1.0",
- "clippy_lints 0.0.174",
- "compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clippy-mini-macro-test 0.2.0",
+ "clippy_lints 0.0.186",
+ "compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"duct 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "clippy-mini-macro-test"
-version = "0.1.0"
+version = "0.2.0"
[[package]]
name = "clippy_lints"
-version = "0.0.174"
+version = "0.0.186"
dependencies = [
"if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.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.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "compiletest_rs"
-version = "0.3.3"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "is-match"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "itertools"
version = "0.6.5"
"either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "itertools"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "itoa"
version = "0.3.4"
[[package]]
name = "mdbook"
-version = "0.0.28"
+version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
+ "chrono 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "compiletest_rs 0.3.6 (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.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rls"
-version = "0.124.0"
+version = "0.125.0"
dependencies = [
"cargo 0.26.0",
"env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.3.6",
+ "rustfmt-nightly 0.3.8",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.0"
dependencies = [
"clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "mdbook 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_errors"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-serialize"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-ap-syntax"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-syntax_pos"
-version = "12.0.0"
+version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustfmt-nightly"
-version = "0.3.6"
+version = "0.3.8"
dependencies = [
"cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "shlex"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "siphasher"
version = "0.2.2"
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "toml-query"
+version = "0.6.0"
+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)",
+ "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "unicode-bidi"
version = "0.3.4"
"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
"checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2"
-"checksum compiletest_rs 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "562bafeec9aef1e3e08f1c5b0c542220bb80ff2894e5373a1f9d17c346412c66"
+"checksum compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6c5aafb5d4a77c6b5fa384fe93c7a9a3561bd88c4b8b8e45187cf5e779b1badc"
"checksum core-foundation 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8047f547cd6856d45b1cdd75ef8d2f21f3d0e4bf1dab0a0041b0ae9a5dda9c0e"
"checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5"
"checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be"
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
"checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8"
"checksum ignore 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bb2f0238094bd1b41800fb6eb9b16fdd5e9832ed6053ed91409f0cd5bf28dcfd"
+"checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053"
"checksum itertools 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d3f2be4da1690a039e9ae5fd575f706a63ad5a2120f161b1d653c9da3930dd21"
+"checksum itertools 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b07332223953b5051bceb67e8c4700aa65291535568e1f12408c43c4a42c0394"
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
"checksum jobserver 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "565f6106bd87b394398f813bea4e5ecad6d6b0f6aa077592d088f882a506481d"
"checksum json 0.11.12 (registry+https://github.com/rust-lang/crates.io-index)" = "39ebf0fac977ee3a4a3242b6446004ff64514889e3e2730bbd4f764a67a2e483"
"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
"checksum markup5ever 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "047150a0e03b57e638fc45af33a0b63a0362305d5b9f92ecef81df472a4cceb0"
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
-"checksum mdbook 0.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "1ee8ba20c002000546681dc78d7f7e91fd35832058b1e2fdd492ca842bb6e9be"
+"checksum mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fef236caad7ba3b5b3944df946f19ab3e190bca53c111dd00fe05fa8d879f2fd"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
-"checksum rustc-ap-rustc_cratesio_shim 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a51c10af5abd5d698b7e3487e869e6d15f6feb04cbedb5c792e2824f9d845e"
-"checksum rustc-ap-rustc_data_structures 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1aa227490501072780d57f74b1164d361833ff8e172f817da0da2cdf2e4280cc"
-"checksum rustc-ap-rustc_errors 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21ff6c6e13ac4fc04b7d4d398828b024c4b6577045cb3175b33d35fea35ff6d0"
-"checksum rustc-ap-serialize 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b4e7f51e298675c2bf830f7265621a8936fb09e63b825b58144cbaac969e604"
-"checksum rustc-ap-syntax 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf5639869ba2f7fa581939cd217cb71a85506b82ad0ea520614fb0dceb2386c"
-"checksum rustc-ap-syntax_pos 12.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1c020cdb7379e1c733ae0a311ae47c748337ba584d2dd7b7f53baaae78de6f8b"
+"checksum rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524"
+"checksum rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c0d65325492aba7db72899e3edbab34d39af98c42ab7c7e450c9a288ffe4ad"
+"checksum rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d4ab2e06a671b5b5c5b0359dac346f164c99d059dce6a22feb08f2f56bd182"
+"checksum rustc-ap-serialize 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e0745fa445ff41c4b6699936cf35ce3ca49502377dd7b3929c829594772c3a7b"
+"checksum rustc-ap-syntax 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "82efedabe30f393161e11214a9130edfa01ad476372d1c6f3fec1f8d30488c9d"
+"checksum rustc-ap-syntax_pos 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db9de2e927e280c75b8efab9c5f591ad31082d5d2c4c562c68fdba2ee77286b0"
"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb"
"checksum shared_child 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "099b38928dbe4a0a01fcd8c233183072f14a7d126a34bed05880869be66e14cc"
"checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
+"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
"checksum smallvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f8266519bc1d17d0b5b16f6c21295625d562841c708f6376f49028a43e9c11e"
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4"
"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e"
+"checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
serde_json = "1.0.2"
toml = "0.4"
lazy_static = "0.2"
+time = "0.1"
})
.env("TEST_MIRI", self.config.test_miri.to_string())
.env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir());
- if let Some(n) = self.config.rust_codegen_units {
- cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
- }
-
if let Some(host_linker) = self.build.linker(compiler.host) {
cargo.env("RUSTC_HOST_LINKER", host_linker);
if self.is_very_verbose() {
cargo.arg("-v");
}
+
+ // This must be kept before the thinlto check, as we set codegen units
+ // to 1 forcibly there.
+ if let Some(n) = self.config.rust_codegen_units {
+ cargo.env("RUSTC_CODEGEN_UNITS", n.to_string());
+ }
+
if self.config.rust_optimize {
// FIXME: cargo bench does not accept `--release`
if cmd != "bench" {
}
if self.config.rust_codegen_units.is_none() &&
- self.build.is_rust_llvm(compiler.host)
- {
+ self.build.is_rust_llvm(compiler.host) &&
+ self.config.rust_thinlto {
cargo.env("RUSTC_THINLTO", "1");
+ } else if self.config.rust_codegen_units.is_none() {
+ // Generally, if ThinLTO has been disabled for some reason, we
+ // want to set the codegen units to 1. However, we shouldn't do
+ // this if the option was specifically set by the user.
+ cargo.env("RUSTC_CODEGEN_UNITS", "1");
}
}
+
if self.config.locked_deps {
cargo.arg("--locked");
}
// rust codegen options
pub rust_optimize: bool,
pub rust_codegen_units: Option<u32>,
+ pub rust_thinlto: bool,
pub rust_debug_assertions: bool,
pub rust_debuginfo: bool,
pub rust_debuginfo_lines: bool,
pub debug_jemalloc: bool,
pub use_jemalloc: bool,
pub backtrace: bool, // support for RUST_BACKTRACE
+ pub wasm_syscall: bool,
// misc
pub low_priority: bool,
struct Rust {
optimize: Option<bool>,
codegen_units: Option<u32>,
+ thinlto: Option<bool>,
debug_assertions: Option<bool>,
debuginfo: Option<bool>,
debuginfo_lines: Option<bool>,
test_miri: Option<bool>,
save_toolstates: Option<String>,
codegen_backends: Option<Vec<String>>,
+ wasm_syscall: Option<bool>,
}
/// TOML representation of how each build target is configured.
// Store off these values as options because if they're not provided
// we'll infer default values for them later
+ let mut thinlto = None;
let mut llvm_assertions = None;
let mut debuginfo_lines = None;
let mut debuginfo_only_std = None;
optimize = rust.optimize;
ignore_git = rust.ignore_git;
debug_jemalloc = rust.debug_jemalloc;
+ thinlto = rust.thinlto;
set(&mut config.rust_optimize_tests, rust.optimize_tests);
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
set(&mut config.codegen_tests, rust.codegen_tests);
set(&mut config.rust_dist_src, rust.dist_src);
set(&mut config.quiet_tests, rust.quiet_tests);
set(&mut config.test_miri, rust.test_miri);
+ set(&mut config.wasm_syscall, rust.wasm_syscall);
config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false);
config.rustc_default_linker = rust.default_linker.clone();
config.musl_root = rust.musl_root.clone().map(PathBuf::from);
"stable" | "beta" | "nightly" => true,
_ => false,
};
+ config.rust_thinlto = thinlto.unwrap_or(true);
config.rust_debuginfo_lines = debuginfo_lines.unwrap_or(default);
config.rust_debuginfo_only_std = debuginfo_only_std.unwrap_or(default);
# Optimization and debugging options. These may be overridden by the release
# channel, etc.
o("optimize", "rust.optimize", "build optimized rust code")
+o("thinlto", "rust.thinlto", "build Rust with ThinLTO enabled")
o("optimize-llvm", "llvm.optimize", "build optimized LLVM")
o("llvm-assertions", "llvm.assertions", "build LLVM with assertions")
o("debug-assertions", "rust.debug-assertions", "build with debugging assertions")
use compile;
use tool::{self, Tool};
use cache::{INTERNER, Interned};
+use time;
pub fn pkgname(build: &Build, component: &str) -> String {
if component == "cargo" {
t!(fs::create_dir_all(image.join("share/man/man1")));
let man_src = build.src.join("src/doc/man");
let man_dst = image.join("share/man/man1");
- let date_output = output(Command::new("date").arg("+%B %Y"));
- let month_year = date_output.trim();
+ let month_year = t!(time::strftime("%B %Y", &time::now()));
// don't use our `bootstrap::util::{copy, cp_r}`, because those try
// to hardlink, and we don't want to edit the source templates
for entry_result in t!(fs::read_dir(man_src)) {
t!(fs::copy(&page_src, &page_dst));
// template in month/year and version number
replace_in_file(&page_dst,
- &[("<INSERT DATE HERE>", month_year),
+ &[("<INSERT DATE HERE>", &month_year),
("<INSERT VERSION HERE>", channel::CFG_RELEASE_NUM)]);
}
extern crate getopts;
extern crate num_cpus;
extern crate toml;
+extern crate time;
#[cfg(unix)]
extern crate libc;
if self.config.profiler {
features.push_str(" profiler");
}
+ if self.config.wasm_syscall {
+ features.push_str(" wasm_syscall");
+ }
features
}
mode: "incremental",
suite: "incremental-fulldeps",
},
- Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" },
Test { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" },
Test { path: "src/test/pretty", mode: "pretty", suite: "pretty" },
Test { path: "src/test/run-pass-valgrind/pretty", mode: "pretty", suite: "run-pass-valgrind" },
Test { path: "src/test/run-pass-fulldeps/pretty", mode: "pretty", suite: "run-pass-fulldeps" },
Test { path: "src/test/run-fail-fulldeps/pretty", mode: "pretty", suite: "run-fail-fulldeps" },
+ Test { path: "src/test/run-make", mode: "run-make", suite: "run-make" },
];
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)),
build.config.nodejs.as_ref().expect("nodejs not configured"));
} else if target.starts_with("wasm32") {
+ // Warn about running tests without the `wasm_syscall` feature enabled.
+ // The javascript shim implements the syscall interface so that test
+ // output can be correctly reported.
+ if !build.config.wasm_syscall {
+ println!("Libstd was built without `wasm_syscall` feature enabled: \
+ test output may not be visible.");
+ }
+
// On the wasm32-unknown-unknown target we're using LTO which is
// incompatible with `-C prefer-dynamic`, so disable that here
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");
# If this PR is intended to update one of these tools, do not let the build pass
# when they do not test-pass.
-for TOOL in rls rustfmt miri clippy; do
+for TOOL in rls rustfmt clippy; do
echo "Verifying status of $TOOL..."
if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]src/tools/$TOOL$"; then
echo "This PR updated 'src/tools/$TOOL', verifying if status is 'test-pass'..."
if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-thinlto"
if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
-Subproject commit 194eb8d5f1753fb5f4501011cebdc1b585712474
+Subproject commit a645960fe48946153936dd5628df4a90bd837981
-Subproject commit 1d791b55b23ec5389fbd5b3cee80db3f8bbdd162
+Subproject commit e6a5d5d10aa2fde0baed7b29bf672bd9f3af8962
p
}
-#[lang = "exchange_free"]
-unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
- libc::free(ptr as *mut libc::c_void)
-}
-
#[lang = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
- deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
+ libc::free(ptr as *mut libc::c_void)
}
#[start]
-fn main(argc: isize, argv: *const *const u8) -> isize {
- let x = box 1;
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+ let _x = box 1;
0
}
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
-# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
+#[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
+#[no_mangle] pub extern fn rust_eh_register_frames () {}
+#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
```
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
Lang items are loaded lazily by the compiler; e.g. if one never uses
`Box` then there is no need to define functions for `exchange_malloc`
-and `exchange_free`. `rustc` will emit an error when an item is needed
+and `box_free`. `rustc` will emit an error when an item is needed
but not found in the current crate or any that it depends on.
Most lang items are defined by `libcore`, but if you're trying to build
- `phantom_data`: `libcore/marker.rs`
- `freeze`: `libcore/marker.rs`
- `debug_trait`: `libcore/fmt/mod.rs`
- - `non_zero`: `libcore/nonzero.rs`
\ No newline at end of file
+ - `non_zero`: `libcore/nonzero.rs`
+++ /dev/null
-# `match_beginning_vert`
-
-The tracking issue for this feature is [#44101].
-
-With this feature enabled, you are allowed to add a '|' to the beginning of a
-match arm:
-
-```rust
-#![feature(match_beginning_vert)]
-
-enum Foo { A, B, C }
-
-fn main() {
- let x = Foo::A;
- match x {
- | Foo::A
- | Foo::B => println!("AB"),
- | Foo::C => println!("C"),
- }
-}
-```
-
-[#44101]: https://github.com/rust-lang/rust/issues/44101
\ No newline at end of file
+++ /dev/null
-# `use_nested_groups`
-
-The tracking issue for this feature is: [#44494]
-
-[#44494]: https://github.com/rust-lang/rust/issues/44494
-
-------------------------
-
-The `use_nested_groups` feature allows you to import multiple items from a
-complex module tree easily, by nesting different imports in the same
-declaration. For example:
-
-```rust
-#![feature(use_nested_groups)]
-# #![allow(unused_imports, dead_code)]
-#
-# mod foo {
-# pub mod bar {
-# pub type Foo = ();
-# }
-# pub mod baz {
-# pub mod quux {
-# pub type Bar = ();
-# }
-# }
-# }
-
-use foo::{
- bar::{self, Foo},
- baz::{*, quux::Bar},
-};
-#
-# fn main() {}
-```
-
-## Snippet for the book's new features appendix
-
-When stabilizing, add this to
-`src/doc/book/second-edition/src/appendix-07-newest-features.md`:
-
-### Nested groups in `use` declarations
-
-If you have a complex module tree with many different submodules and you need
-to import a few items from each one, it might be useful to group all the
-imports in the same declaration to keep your code clean and avoid repeating the
-base modules' name.
-
-The `use` declaration supports nesting to help you in those cases, both with
-simple imports and glob ones. For example this snippets imports `bar`, `Foo`,
-all the items in `baz` and `Bar`:
-
-```rust
-# #![feature(use_nested_groups)]
-# #![allow(unused_imports, dead_code)]
-#
-# mod foo {
-# pub mod bar {
-# pub type Foo = ();
-# }
-# pub mod baz {
-# pub mod quux {
-# pub type Bar = ();
-# }
-# }
-# }
-#
-use foo::{
- bar::{self, Foo},
- baz::{*, quux::Bar},
-};
-#
-# fn main() {}
-```
-
-## Updated reference
-
-When stabilizing, replace the shortcut list in
-`src/doc/reference/src/items/use-declarations.md` with this updated one:
-
-* Simultaneously binding a list of paths with a common prefix, using the
- glob-like brace syntax `use a::b::{c, d, e::f, g::h::i};`
-* Simultaneously binding a list of paths with a common prefix and their common
- parent module, using the `self` keyword, such as `use a::b::{self, c, d::e};`
-* Rebinding the target name as a new local name, using the syntax `use p::q::r
- as x;`. This can also be used with the last two features:
- `use a::b::{self as ab, c as abc}`.
-* Binding all paths matching a given prefix, using the asterisk wildcard syntax
- `use a::b::*;`.
-* Nesting groups of the previous features multiple times, such as
- `use a::b::{self as ab, c d::{*, e::f}};`
let memory = null;
+function viewstruct(data, fields) {
+ return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
+}
+
function copystr(a, b) {
- if (memory === null) {
- return null
- }
- let view = new Uint8Array(memory.buffer).slice(a, a + b);
+ let view = new Uint8Array(memory.buffer).subarray(a, a + b);
return String.fromCharCode.apply(null, view);
}
+function syscall_write([fd, ptr, len]) {
+ let s = copystr(ptr, len);
+ switch (fd) {
+ case 1: process.stdout.write(s); break;
+ case 2: process.stderr.write(s); break;
+ }
+}
+
+function syscall_exit([code]) {
+ process.exit(code);
+}
+
+function syscall_args(params) {
+ let [ptr, len] = params;
+
+ // Calculate total required buffer size
+ let totalLen = -1;
+ for (let i = 2; i < process.argv.length; ++i) {
+ totalLen += Buffer.byteLength(process.argv[i]) + 1;
+ }
+ if (totalLen < 0) { totalLen = 0; }
+ params[2] = totalLen;
+
+ // If buffer is large enough, copy data
+ if (len >= totalLen) {
+ let view = new Uint8Array(memory.buffer);
+ for (let i = 2; i < process.argv.length; ++i) {
+ let value = process.argv[i];
+ Buffer.from(value).copy(view, ptr);
+ ptr += Buffer.byteLength(process.argv[i]) + 1;
+ }
+ }
+}
+
+function syscall_getenv(params) {
+ let [keyPtr, keyLen, valuePtr, valueLen] = params;
+
+ let key = copystr(keyPtr, keyLen);
+ let value = process.env[key];
+
+ if (value == null) {
+ params[4] = 0xFFFFFFFF;
+ } else {
+ let view = new Uint8Array(memory.buffer);
+ let totalLen = Buffer.byteLength(value);
+ params[4] = totalLen;
+ if (valueLen >= totalLen) {
+ Buffer.from(value).copy(view, valuePtr);
+ }
+ }
+}
+
+function syscall_time(params) {
+ let t = Date.now();
+ let secs = Math.floor(t / 1000);
+ let millis = t % 1000;
+ params[1] = Math.floor(secs / 0x100000000);
+ params[2] = secs % 0x100000000;
+ params[3] = Math.floor(millis * 1000000);
+}
+
let imports = {};
imports.env = {
// These are generated by LLVM itself for various intrinsic calls. Hopefully
log10: Math.log10,
log10f: Math.log10,
- // These are called in src/libstd/sys/wasm/stdio.rs and are used when
- // debugging is enabled.
- rust_wasm_write_stdout: function(a, b) {
- let s = copystr(a, b);
- if (s !== null) {
- process.stdout.write(s);
- }
- },
- rust_wasm_write_stderr: function(a, b) {
- let s = copystr(a, b);
- if (s !== null) {
- process.stderr.write(s);
- }
- },
-
- // These are called in src/libstd/sys/wasm/args.rs and are used when
- // debugging is enabled.
- rust_wasm_args_count: function() {
- if (memory === null)
- return 0;
- return process.argv.length - 2;
- },
- rust_wasm_args_arg_size: function(i) {
- return Buffer.byteLength(process.argv[i + 2]);
- },
- rust_wasm_args_arg_fill: function(idx, ptr) {
- let arg = process.argv[idx + 2];
- let view = new Uint8Array(memory.buffer);
- Buffer.from(arg).copy(view, ptr);
- },
-
- // These are called in src/libstd/sys/wasm/os.rs and are used when
- // debugging is enabled.
- rust_wasm_getenv_len: function(a, b) {
- let key = copystr(a, b);
- if (key === null) {
- return -1;
+ rust_wasm_syscall: function(index, data) {
+ switch (index) {
+ case 1: syscall_write(viewstruct(data, 3)); return true;
+ case 2: syscall_exit(viewstruct(data, 1)); return true;
+ case 3: syscall_args(viewstruct(data, 3)); return true;
+ case 4: syscall_getenv(viewstruct(data, 5)); return true;
+ case 6: syscall_time(viewstruct(data, 4)); return true;
+ default:
+ console.log("Unsupported syscall: " + index);
+ return false;
}
- if (!(key in process.env)) {
- return -1;
- }
- return Buffer.byteLength(process.env[key]);
- },
- rust_wasm_getenv_data: function(a, b, ptr) {
- let key = copystr(a, b);
- let value = process.env[key];
- let view = new Uint8Array(memory.buffer);
- Buffer.from(value).copy(view, ptr);
- },
-};
-
-let module_imports = WebAssembly.Module.imports(m);
-
-for (var i = 0; i < module_imports.length; i++) {
- let imp = module_imports[i];
- if (imp.module != 'env') {
- continue
}
- if (imp.name == 'memory' && imp.kind == 'memory') {
- memory = new WebAssembly.Memory({initial: 20});
- imports.env.memory = memory;
- }
-}
+};
let instance = new WebAssembly.Instance(m, imports);
+memory = instance.exports.memory;
+try {
+ instance.exports.main();
+} catch (e) {
+ console.error(e);
+ process.exit(101);
+}
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg(stage0)]
pub fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}
+
+ /// Returns the `TypeId` of the type this generic function has been
+ /// instantiated with.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::any::{Any, TypeId};
+ ///
+ /// fn is_string<T: ?Sized + Any>(_s: &T) -> bool {
+ /// TypeId::of::<String>() == TypeId::of::<T>()
+ /// }
+ ///
+ /// fn main() {
+ /// assert_eq!(is_string(&0), false);
+ /// assert_eq!(is_string(&"cookie monster".to_string()), true);
+ /// }
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature="const_type_id")]
+ #[cfg(not(stage0))]
+ pub const fn of<T: ?Sized + 'static>() -> TypeId {
+ TypeId {
+ t: unsafe { intrinsics::type_id::<T>() },
+ }
+ }
}
///
/// # Generic Implementations
///
-/// - `AsMut` auto-dereferences if the inner type is a reference or a mutable
-/// reference (e.g.: `foo.as_ref()` will work the same if `foo` has type
-/// `&mut Foo` or `&&mut Foo`)
+/// - `AsMut` auto-dereferences if the inner type is a mutable reference
+/// (e.g.: `foo.as_mut()` will work the same if `foo` has type `&mut Foo`
+/// or `&mut &mut Foo`)
///
/// # Examples
///
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "`{Self}` cannot be formatted using `:?`; if it is \
- defined in your crate, add `#[derive(Debug)]` or \
- manually implement it"]
+#[rustc_on_unimplemented(
+ on(crate_local, label="`{Self}` cannot be formatted using `:?`; \
+ add `#[derive(Debug)]` or manually implement `{Debug}`"),
+ message="`{Self}` doesn't implement `{Debug}`",
+ label="`{Self}` cannot be formatted using `:?` because it doesn't implement `{Debug}`",
+)]
#[lang = "debug_trait"]
pub trait Debug {
/// Formats the value using the given formatter.
///
/// println!("The origin is: {}", origin);
/// ```
-#[rustc_on_unimplemented = "`{Self}` cannot be formatted with the default \
- formatter; try using `:?` instead if you are using \
- a format string"]
+#[rustc_on_unimplemented(
+ message="`{Self}` doesn't implement `{Display}`",
+ label="`{Self}` cannot be formatted with the default formatter; \
+ try using `:?` instead if you are using a format string",
+)]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Display {
/// Formats the value using the given formatter.
/// ptr::copy_nonoverlapping(y, x, 1);
/// ptr::copy_nonoverlapping(&t, y, 1);
///
- /// // y and t now point to the same thing, but we need to completely forget `tmp`
+ /// // y and t now point to the same thing, but we need to completely forget `t`
/// // because it's no longer relevant.
/// mem::forget(t);
/// }
/// [module-level documentation]: index.html
/// [impl]: index.html#implementing-iterator
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \
- `.iter()` or a similar method"]
+#[rustc_on_unimplemented(
+ on(
+ _Self="&str",
+ label="`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`"
+ ),
+ label="`{Self}` is not an iterator; maybe try calling `.iter()` or a similar method"
+)]
#[doc(spotlight)]
pub trait Iterator {
/// The type of the elements being iterated over.
use convert::TryFrom;
use mem;
-use ops::{self, Add, Sub};
+use ops::{self, Add, Sub, Try};
use usize;
use super::{FusedIterator, TrustedLen};
fn max(mut self) -> Option<A> {
self.next_back()
}
+
+ #[inline]
+ fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where
+ Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+ {
+ let mut accum = init;
+ if self.start <= self.end {
+ loop {
+ let (x, done) =
+ if self.start < self.end {
+ let n = self.start.add_one();
+ (mem::replace(&mut self.start, n), false)
+ } else {
+ self.end.replace_zero();
+ (self.start.replace_one(), true)
+ };
+ accum = f(accum, x)?;
+ if done { break }
+ }
+ }
+ Try::from_ok(accum)
+ }
}
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
_ => None,
}
}
+
+ #[inline]
+ fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where
+ Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try<Ok=B>
+ {
+ let mut accum = init;
+ if self.start <= self.end {
+ loop {
+ let (x, done) =
+ if self.start < self.end {
+ let n = self.end.sub_one();
+ (mem::replace(&mut self.end, n), false)
+ } else {
+ self.start.replace_one();
+ (self.end.replace_zero(), true)
+ };
+ accum = f(accum, x)?;
+ if done { break }
+ }
+ }
+ Try::from_ok(accum)
+ }
}
#[unstable(feature = "fused", issue = "35602")]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(doc_spotlight)]
+#![feature(rustc_const_unstable)]
#[prelude_import]
#[allow(unused)]
/// Type | size_of::\<Type>()
/// ---- | ---------------
/// () | 0
+/// bool | 1
/// u8 | 1
/// u16 | 2
/// u32 | 4
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f32 {
- self * (180.0f32 / consts::PI)
+ // Use a constant for better precision.
+ const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32;
+ self * PIS_IN_180
}
/// Converts to radians, assuming the number is in degrees.
/// Converts to degrees, assuming the number is in radians.
#[inline]
fn to_degrees(self) -> f64 {
+ // The division here is correctly rounded with respect to the true
+ // value of 180/π. (This differs from f32, where a constant must be
+ // used to ensure a correctly rounded result.)
self * (180.0f64 / consts::PI)
}
/// ```
#[lang = "add"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} + {RHS}`"]
+#[rustc_on_unimplemented(
+ on(
+ all(_Self="{integer}", RHS="{float}"),
+ message="cannot add a float to an integer",
+ ),
+ on(
+ all(_Self="{float}", RHS="{integer}"),
+ message="cannot add an integer to a float",
+ ),
+ message="cannot add `{RHS}` to `{Self}`",
+ label="no implementation for `{Self} + {RHS}`",
+)]
pub trait Add<RHS=Self> {
/// The resulting type after applying the `+` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "sub"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} - {RHS}`"]
+#[rustc_on_unimplemented(message="cannot substract `{RHS}` from `{Self}`",
+ label="no implementation for `{Self} - {RHS}`")]
pub trait Sub<RHS=Self> {
/// The resulting type after applying the `-` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "mul"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} * {RHS}`"]
+#[rustc_on_unimplemented(message="cannot multiply `{RHS}` to `{Self}`",
+ label="no implementation for `{Self} * {RHS}`")]
pub trait Mul<RHS=Self> {
/// The resulting type after applying the `*` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "div"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} / {RHS}`"]
+#[rustc_on_unimplemented(message="cannot divide `{Self}` by `{RHS}`",
+ label="no implementation for `{Self} / {RHS}`")]
pub trait Div<RHS=Self> {
/// The resulting type after applying the `/` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "rem"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} % {RHS}`"]
+#[rustc_on_unimplemented(message="cannot mod `{Self}` by `{RHS}`",
+ label="no implementation for `{Self} % {RHS}`")]
pub trait Rem<RHS=Self> {
/// The resulting type after applying the `%` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "add_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} += {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot add-assign `{Rhs}` to `{Self}`",
+ label="no implementation for `{Self} += {Rhs}`")]
pub trait AddAssign<Rhs=Self> {
/// Performs the `+=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "sub_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} -= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot substract-assign `{Rhs}` from `{Self}`",
+ label="no implementation for `{Self} -= {Rhs}`")]
pub trait SubAssign<Rhs=Self> {
/// Performs the `-=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "mul_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} *= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot multiply-assign `{Rhs}` to `{Self}`",
+ label="no implementation for `{Self} *= {Rhs}`")]
pub trait MulAssign<Rhs=Self> {
/// Performs the `*=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "div_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} /= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot divide-assign `{Self}` by `{Rhs}`",
+ label="no implementation for `{Self} /= {Rhs}`")]
pub trait DivAssign<Rhs=Self> {
/// Performs the `/=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "rem_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} %= {Rhs}`"]
+#[rustc_on_unimplemented(message="cannot mod-assign `{Self}` by `{Rhs}``",
+ label="no implementation for `{Self} %= {Rhs}`")]
pub trait RemAssign<Rhs=Self> {
/// Performs the `%=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "bitand"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} & {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} & {RHS}`",
+ label="no implementation for `{Self} & {RHS}`")]
pub trait BitAnd<RHS=Self> {
/// The resulting type after applying the `&` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "bitor"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} | {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} | {RHS}`",
+ label="no implementation for `{Self} | {RHS}`")]
pub trait BitOr<RHS=Self> {
/// The resulting type after applying the `|` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "bitxor"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} ^ {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} ^ {RHS}`",
+ label="no implementation for `{Self} ^ {RHS}`")]
pub trait BitXor<RHS=Self> {
/// The resulting type after applying the `^` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "shl"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} << {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} << {RHS}`",
+ label="no implementation for `{Self} << {RHS}`")]
pub trait Shl<RHS> {
/// The resulting type after applying the `<<` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "shr"]
#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} >> {RHS}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} >> {RHS}`",
+ label="no implementation for `{Self} >> {RHS}`")]
pub trait Shr<RHS> {
/// The resulting type after applying the `>>` operator.
#[stable(feature = "rust1", since = "1.0.0")]
/// ```
#[lang = "bitand_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} &= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} &= {Rhs}`",
+ label="no implementation for `{Self} &= {Rhs}`")]
pub trait BitAndAssign<Rhs=Self> {
/// Performs the `&=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "bitor_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} |= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} |= {Rhs}`",
+ label="no implementation for `{Self} |= {Rhs}`")]
pub trait BitOrAssign<Rhs=Self> {
/// Performs the `|=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "bitxor_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} ^= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} ^= {Rhs}`",
+ label="no implementation for `{Self} ^= {Rhs}`")]
pub trait BitXorAssign<Rhs=Self> {
/// Performs the `^=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "shl_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} <<= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} <<= {Rhs}`",
+ label="no implementation for `{Self} <<= {Rhs}`")]
pub trait ShlAssign<Rhs> {
/// Performs the `<<=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
/// ```
#[lang = "shr_assign"]
#[stable(feature = "op_assign_traits", since = "1.8.0")]
-#[rustc_on_unimplemented = "no implementation for `{Self} >>= {Rhs}`"]
+#[rustc_on_unimplemented(message="no implementation for `{Self} >>= {Rhs}`",
+ label="no implementation for `{Self} >>= {Rhs}`")]
pub trait ShrAssign<Rhs=Self> {
/// Performs the `>>=` operation.
#[stable(feature = "op_assign_traits", since = "1.8.0")]
}
/// Previous name of `NonNull`.
-#[rustc_deprecated(since = "1.24", reason = "renamed to `NonNull`")]
+#[rustc_deprecated(since = "1.25.0", reason = "renamed to `NonNull`")]
#[unstable(feature = "shared", issue = "27730")]
pub type Shared<T> = NonNull<T>;
/// Usually this won't be necessary; covariance is correct for most safe abstractions,
/// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they
/// provide a public API that follows the normal shared XOR mutable rules of Rust.
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
pub struct NonNull<T: ?Sized> {
pointer: NonZero<*const T>,
}
-#[stable(feature = "nonnull", since = "1.24.0")]
-impl<T: ?Sized> fmt::Debug for NonNull<T> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Pointer::fmt(&self.as_ptr(), f)
- }
-}
-
/// `NonNull` pointers are not `Send` because the data they reference may be aliased.
// NB: This impl is unnecessary, but should provide better error messages.
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> !Send for NonNull<T> { }
/// `NonNull` pointers are not `Sync` because the data they reference may be aliased.
// NB: This impl is unnecessary, but should provide better error messages.
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> !Sync for NonNull<T> { }
impl<T: Sized> NonNull<T> {
///
/// This is useful for initializing types which lazily allocate, like
/// `Vec::new` does.
- #[stable(feature = "nonnull", since = "1.24.0")]
+ #[stable(feature = "nonnull", since = "1.25.0")]
pub fn dangling() -> Self {
unsafe {
let ptr = mem::align_of::<T>() as *mut T;
/// # Safety
///
/// `ptr` must be non-null.
- #[stable(feature = "nonnull", since = "1.24.0")]
+ #[stable(feature = "nonnull", since = "1.25.0")]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
NonNull { pointer: NonZero::new_unchecked(ptr) }
}
/// Creates a new `NonNull` if `ptr` is non-null.
- #[stable(feature = "nonnull", since = "1.24.0")]
+ #[stable(feature = "nonnull", since = "1.25.0")]
pub fn new(ptr: *mut T) -> Option<Self> {
NonZero::new(ptr as *const T).map(|nz| NonNull { pointer: nz })
}
/// Acquires the underlying `*mut` pointer.
- #[stable(feature = "nonnull", since = "1.24.0")]
+ #[stable(feature = "nonnull", since = "1.25.0")]
pub fn as_ptr(self) -> *mut T {
self.pointer.get() as *mut T
}
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
/// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
- #[stable(feature = "nonnull", since = "1.24.0")]
+ #[stable(feature = "nonnull", since = "1.25.0")]
pub unsafe fn as_ref(&self) -> &T {
&*self.as_ptr()
}
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
/// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
- #[stable(feature = "nonnull", since = "1.24.0")]
+ #[stable(feature = "nonnull", since = "1.25.0")]
pub unsafe fn as_mut(&mut self) -> &mut T {
&mut *self.as_ptr()
}
+
+ /// Cast to a pointer of another type
+ #[unstable(feature = "nonnull_cast", issue = "47653")]
+ pub fn cast<U>(self) -> NonNull<U> {
+ unsafe {
+ NonNull::new_unchecked(self.as_ptr() as *mut U)
+ }
+ }
}
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> Clone for NonNull<T> {
fn clone(&self) -> Self {
*self
}
}
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> Copy for NonNull<T> { }
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> { }
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> fmt::Debug for NonNull<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Pointer::fmt(&self.as_ptr(), f)
+ }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> fmt::Pointer for NonNull<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Pointer::fmt(&self.as_ptr(), f)
}
}
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> Eq for NonNull<T> {}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> PartialEq for NonNull<T> {
+ fn eq(&self, other: &Self) -> bool {
+ self.as_ptr() == other.as_ptr()
+ }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> Ord for NonNull<T> {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.as_ptr().cmp(&other.as_ptr())
+ }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> PartialOrd for NonNull<T> {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.as_ptr().partial_cmp(&other.as_ptr())
+ }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
+impl<T: ?Sized> hash::Hash for NonNull<T> {
+ fn hash<H: hash::Hasher>(&self, state: &mut H) {
+ self.as_ptr().hash(state)
+ }
+}
+
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
fn from(unique: Unique<T>) -> Self {
NonNull { pointer: unique.pointer }
}
}
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> {
fn from(reference: &'a mut T) -> Self {
NonNull { pointer: NonZero::from(reference) }
}
}
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<'a, T: ?Sized> From<&'a T> for NonNull<T> {
fn from(reference: &'a T) -> Self {
NonNull { pointer: NonZero::from(reference) }
assert_eq!(r.min(), None);
}
+#[test]
+fn test_range_inclusive_folds() {
+ assert_eq!((1..=10).sum::<i32>(), 55);
+ assert_eq!((1..=10).rev().sum::<i32>(), 55);
+
+ let mut it = 40..=50;
+ assert_eq!(it.try_fold(0, i8::checked_add), None);
+ assert_eq!(it, 44..=50);
+ assert_eq!(it.try_rfold(0, i8::checked_add), None);
+ assert_eq!(it, 44..=47);
+
+ let mut it = 10..=20;
+ assert_eq!(it.try_fold(0, |a,b| Some(a+b)), Some(165));
+ assert_eq!(it, 1..=0);
+
+ let mut it = 10..=20;
+ assert_eq!(it.try_rfold(0, |a,b| Some(a+b)), Some(165));
+ assert_eq!(it, 1..=0);
+}
+
#[test]
fn test_repeat() {
let mut it = repeat(42);
})
}
- DotEq => unreachable!(),
+ DotEq => joint!('.', Eq),
OpenDelim(..) | CloseDelim(..) => unreachable!(),
Whitespace | Comment | Shebang(..) | Eof => unreachable!(),
};
}
```
+### The trait cannot contain associated constants
+
+Just like static functions, associated constants aren't stored on the method
+table. If the trait or any subtrait contain an associated constant, they cannot
+be made into an object.
+
+```compile_fail,E0038
+trait Foo {
+ const X: i32;
+}
+
+impl Foo {}
+```
+
+A simple workaround is to use a helper method instead:
+
+```
+trait Foo {
+ fn x(&self) -> i32;
+}
+```
+
### The trait cannot use `Self` as a type parameter in the supertrait listing
This is similar to the second sub-error, but subtler. It happens in situations
ty::ReEarlyBound(_) |
ty::ReFree(_) => {
let scope = region.free_region_binding_scope(self);
- let prefix = match *region {
- ty::ReEarlyBound(ref br) => {
- format!("the lifetime {} as defined on", br.name)
- }
- ty::ReFree(ref fr) => {
- match fr.bound_region {
- ty::BrAnon(idx) => {
- format!("the anonymous lifetime #{} defined on", idx + 1)
- }
- ty::BrFresh(_) => "an anonymous lifetime defined on".to_owned(),
- _ => {
- format!("the lifetime {} as defined on",
- fr.bound_region)
- }
- }
- }
- _ => bug!()
- };
-
let node = self.hir.as_local_node_id(scope)
.unwrap_or(DUMMY_NODE_ID);
let unknown;
&unknown
}
};
- let (msg, opt_span) = explain_span(self, tag, self.hir.span(node));
+ let (prefix, span) = match *region {
+ ty::ReEarlyBound(ref br) => {
+ (format!("the lifetime {} as defined on", br.name),
+ self.sess.codemap().def_span(self.hir.span(node)))
+ }
+ ty::ReFree(ref fr) => {
+ match fr.bound_region {
+ ty::BrAnon(idx) => {
+ (format!("the anonymous lifetime #{} defined on", idx + 1),
+ self.hir.span(node))
+ }
+ ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(),
+ self.hir.span(node)),
+ _ => (format!("the lifetime {} as defined on", fr.bound_region),
+ self.sess.codemap().def_span(self.hir.span(node))),
+ }
+ }
+ _ => bug!()
+ };
+ let (msg, opt_span) = explain_span(self, tag, span);
(format!("{} {}", prefix, msg), opt_span)
}
}
};
- let span = cause.span;
+ let span = cause.span(&self.tcx);
diag.span_label(span, terr.to_string());
if let Some((sp, msg)) = secondary_span {
"did you mean `{}(/* fields */)`?",
self.tcx.item_path_str(def_id)
);
- diag.span_label(cause.span, message);
+ diag.span_label(span, message);
}
}
}
trace,
terr);
- let span = trace.cause.span;
+ let span = trace.cause.span(&self.tcx);
let failure_code = trace.cause.as_failure_code(terr);
let mut diag = match failure_code {
FailureCode::Error0317(failure_str) => {
sup_region,
"...");
+ match (&sup_origin, &sub_origin) {
+ (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
+ if let (Some((sup_expected, sup_found)),
+ Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values),
+ self.values_str(&sub_trace.values)) {
+ if sub_expected == sup_expected && sub_found == sup_found {
+ self.tcx.note_and_explain_region(
+ region_scope_tree,
+ &mut err,
+ "...but the lifetime must also be valid for ",
+ sub_region,
+ "...",
+ );
+ err.note(&format!("...so that the {}:\nexpected {}\n found {}",
+ sup_trace.cause.as_requirement_str(),
+ sup_expected.content(),
+ sup_found.content()));
+ err.emit();
+ return;
+ }
+ }
+ }
+ _ => {}
+ }
+
self.note_region_origin(&mut err, &sup_origin);
self.tcx.note_and_explain_region(region_scope_tree, &mut err,
if let Some((expected, found)) = self.values_str(&trace.values) {
let expected = expected.content();
let found = found.content();
- // FIXME: do we want a "the" here?
- err.span_note(trace.cause.span,
- &format!("...so that {} (expected {}, found {})",
- trace.cause.as_requirement_str(),
- expected,
- found));
+ err.note(&format!("...so that the {}:\nexpected {}\n found {}",
+ trace.cause.as_requirement_str(),
+ expected,
+ found));
} else {
// FIXME: this really should be handled at some earlier stage. Our
// handling of region checking when type errors are present is
#![feature(specialization)]
#![feature(unboxed_closures)]
#![feature(underscore_lifetimes)]
+#![feature(universal_impl_trait)]
#![feature(trace_macros)]
#![feature(catch_expr)]
#![feature(test)]
"raw pointer to an inference variable"
}
+declare_lint! {
+ pub ELIDED_LIFETIME_IN_PATH,
+ Allow,
+ "hidden lifetime parameters are deprecated, try `Foo<'_>`"
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
UNUSED_MUT,
COERCE_NEVER,
SINGLE_USE_LIFETIME,
- TYVAR_BEHIND_RAW_POINTER
+ TYVAR_BEHIND_RAW_POINTER,
+ ELIDED_LIFETIME_IN_PATH
+
)
}
}
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- (self.tcx, self.param_env.reveal_all()).layout_of(ty)
+ self.tcx.layout_of(self.param_env.and(ty))
}
}
// Put the lint store levels and passes back in the session.
cx.lint_sess.restore(&sess.lint_store);
- // Emit all buffered lints from early on in the session now that we've
- // calculated the lint levels for all AST nodes.
- for (_id, lints) in cx.buffered.map {
- for early_lint in lints {
- span_bug!(early_lint.span, "failed to process buffered lint here");
+ // All of the buffered lints should have been emitted at this point.
+ // If not, that means that we somehow buffered a lint for a node id
+ // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
+ //
+ // Rustdoc runs everybody-loops before the early lints and removes
+ // function bodies, so it's totally possible for linted
+ // node ids to not exist (e.g. macros defined within functions for the
+ // unused_macro lint) anymore. So we only run this check
+ // when we're not in rustdoc mode. (see issue #47639)
+ if !sess.opts.actually_rustdoc {
+ for (_id, lints) in cx.buffered.map {
+ for early_lint in lints {
+ span_bug!(early_lint.span, "failed to process buffered lint here");
+ }
}
}
}
}
fn visit_pat(&mut self, pat: &'tcx Pat) {
+ intravisit::walk_pat(self, pat);
+
self.expr_and_pat_count += 1;
- intravisit::walk_pat(self, pat);
+ if pat.id == self.id {
+ self.result = Some(self.expr_and_pat_count);
+ }
}
fn visit_expr(&mut self, expr: &'tcx Expr) {
/// Checks whether the given scope contains a `yield`. If so,
/// returns `Some((span, expr_count))` with the span of a yield we found and
- /// the number of expressions appearing before the `yield` in the body.
+ /// the number of expressions and patterns appearing before the `yield` in the body + 1.
+ /// If there a are multiple yields in a scope, the one with the highest number is returned.
pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> {
self.yield_in_scope.get(&scope).cloned()
}
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
if lifetime_ref.is_elided() {
- self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref));
+ self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref), false);
return;
}
if lifetime_ref.is_static() {
}
if params.lifetimes.iter().all(|l| l.is_elided()) {
- self.resolve_elided_lifetimes(¶ms.lifetimes);
+ self.resolve_elided_lifetimes(¶ms.lifetimes, true);
} else {
for l in ¶ms.lifetimes {
self.visit_lifetime(l);
}
}
- fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime]) {
+ fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime], deprecated: bool) {
if lifetime_refs.is_empty() {
return;
}
let span = lifetime_refs[0].span;
+ let id = lifetime_refs[0].id;
let mut late_depth = 0;
let mut scope = self.scope;
+ if deprecated {
+ self.tcx
+ .struct_span_lint_node(
+ lint::builtin::ELIDED_LIFETIME_IN_PATH,
+ id,
+ span,
+ &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"))
+ .emit();
+ }
let error = loop {
match *scope {
// Do not assign any resolution, it will be inferred.
Array(Ty<'tcx>),
Tuple,
- /// The second field is variant number (discriminant), it's equal
- /// to 0 for struct and union expressions. The fourth field is
+ /// The second field is the variant index. It's equal to 0 for struct
+ /// and union expressions. The fourth field is
/// active field number and is present only for union expressions
/// -- e.g. for a union expression `SomeUnion { c: .. }`, the
/// active field index would identity the field `c`
/// the location is within this block
pub block: BasicBlock,
- /// the location is the start of the this statement; or, if `statement_index`
+ /// the location is the start of the statement; or, if `statement_index`
/// == num-statements, then the start of the terminator.
pub statement_index: usize,
}
pub fn filestem(&self) -> String {
format!("{}{}", self.out_filestem, self.extra)
}
-
- pub fn contains_path(&self, input_path: &PathBuf) -> bool {
- let input_path = input_path.canonicalize().ok();
- if input_path.is_none() {
- return false
- }
- match self.single_output_file {
- Some(ref output_path) => output_path.canonicalize().ok() == input_path,
- None => {
- for k in self.outputs.keys() {
- let output_path = self.path(k.to_owned());
- if output_path.canonicalize().ok() == input_path {
- return true;
- }
- }
- false
- }
- }
- }
}
pub fn host_triple() -> &'static str {
dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED],
"in dep-info output, omit targets for tracking dependencies of the dep-info files \
themselves"),
+ approximate_suggestions: bool = (false, parse_bool, [UNTRACKED],
+ "include machine-applicability of suggestions in JSON output"),
unpretty: Option<String> = (None, parse_unpretty, [UNTRACKED],
"Present the input source, unstable (and less-pretty) variants;
valid types are any of the types for `--pretty`, as well as:
Box::new(EmitterWriter::new(dst, Some(codemap.clone()), false, false))
}
(config::ErrorOutputType::Json(pretty), None) => {
- Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(), pretty))
+ Box::new(JsonEmitter::stderr(Some(registry), codemap.clone(),
+ pretty, sopts.debugging_opts.approximate_suggestions))
}
(config::ErrorOutputType::Json(pretty), Some(dst)) => {
- Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(), pretty))
+ Box::new(JsonEmitter::new(dst, Some(registry), codemap.clone(),
+ pretty, sopts.debugging_opts.approximate_suggestions))
}
(config::ErrorOutputType::Short(color_config), None) => {
Box::new(EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false))
use ty::fold::TypeFoldable;
use ty::subst::Subst;
-use infer::{InferCtxt, InferOk};
+use infer::{InferOk};
/// Whether we do the orphan check relative to this crate or
/// to some remote crate.
pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
}
-/// If there are types that satisfy both impls, returns a suitably-freshened
-/// `ImplHeader` with those types substituted
-pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
- impl1_def_id: DefId,
- impl2_def_id: DefId,
- intercrate_mode: IntercrateMode)
- -> Option<OverlapResult<'tcx>>
+/// If there are types that satisfy both impls, invokes `on_overlap`
+/// with a suitably-freshened `ImplHeader` with those types
+/// substituted. Otherwise, invokes `no_overlap`.
+pub fn overlapping_impls<'gcx, F1, F2, R>(
+ tcx: TyCtxt<'_, 'gcx, 'gcx>,
+ impl1_def_id: DefId,
+ impl2_def_id: DefId,
+ intercrate_mode: IntercrateMode,
+ on_overlap: F1,
+ no_overlap: F2,
+) -> R
+where
+ F1: FnOnce(OverlapResult<'_>) -> R,
+ F2: FnOnce() -> R,
{
debug!("impl_can_satisfy(\
impl1_def_id={:?}, \
impl2_def_id,
intercrate_mode);
- let selcx = &mut SelectionContext::intercrate(infcx, intercrate_mode);
- overlap(selcx, impl1_def_id, impl2_def_id)
+ let overlaps = tcx.infer_ctxt().enter(|infcx| {
+ let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+ overlap(selcx, impl1_def_id, impl2_def_id).is_some()
+ });
+
+ if !overlaps {
+ return no_overlap();
+ }
+
+ // In the case where we detect an error, run the check again, but
+ // this time tracking intercrate ambuiguity causes for better
+ // diagnostics. (These take time and can lead to false errors.)
+ tcx.infer_ctxt().enter(|infcx| {
+ let selcx = &mut SelectionContext::intercrate(&infcx, intercrate_mode);
+ selcx.enable_tracking_intercrate_ambiguity_causes();
+ on_overlap(overlap(selcx, impl1_def_id, impl2_def_id).unwrap())
+ })
}
fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
return None
}
- Some(OverlapResult {
- impl_header: selcx.infcx().resolve_type_vars_if_possible(&a_impl_header),
- intercrate_ambiguity_causes: selcx.intercrate_ambiguity_causes().to_vec(),
- })
+ let impl_header = selcx.infcx().resolve_type_vars_if_possible(&a_impl_header);
+ let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+ debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+ Some(OverlapResult { impl_header, intercrate_ambiguity_causes })
}
pub fn trait_ref_is_knowable<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
if direct {
// this is a "direct", user-specified, rather than derived,
// obligation.
- flags.push(("direct", None));
+ flags.push(("direct".to_string(), None));
}
if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code {
// Currently I'm leaving it for what I need for `try`.
if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) {
method = self.tcx.item_name(item);
- flags.push(("from_method", None));
- flags.push(("from_method", Some(&*method)));
+ flags.push(("from_method".to_string(), None));
+ flags.push(("from_method".to_string(), Some(method.to_string())));
}
}
if let Some(k) = obligation.cause.span.compiler_desugaring_kind() {
desugaring = k.as_symbol().as_str();
- flags.push(("from_desugaring", None));
- flags.push(("from_desugaring", Some(&*desugaring)));
+ flags.push(("from_desugaring".to_string(), None));
+ flags.push(("from_desugaring".to_string(), Some(desugaring.to_string())));
+ }
+ let generics = self.tcx.generics_of(def_id);
+ let self_ty = trait_ref.self_ty();
+ let self_ty_str = self_ty.to_string();
+ flags.push(("_Self".to_string(), Some(self_ty_str.clone())));
+
+ for param in generics.types.iter() {
+ let name = param.name.as_str().to_string();
+ let ty = trait_ref.substs.type_for_def(param);
+ let ty_str = ty.to_string();
+ flags.push((name.clone(),
+ Some(ty_str.clone())));
+ }
+
+ if let Some(true) = self_ty.ty_to_def_id().map(|def_id| def_id.is_local()) {
+ flags.push(("crate_local".to_string(), None));
}
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(
self.tcx, trait_ref.def_id, def_id
) {
- command.evaluate(self.tcx, trait_ref, &flags)
+ command.evaluate(self.tcx, trait_ref, &flags[..])
} else {
OnUnimplementedNote::empty()
}
.map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
.unwrap_or((String::new(), String::new()));
- let OnUnimplementedNote { message, label }
+ let OnUnimplementedNote { message, label, note }
= self.on_unimplemented_note(trait_ref, obligation);
let have_alt_message = message.is_some() || label.is_some();
trait_ref,
trait_ref.self_ty()));
}
+ if let Some(ref s) = note {
+ // If it has a custom "#[rustc_on_unimplemented]" note, let's display it
+ err.note(s.as_str());
+ }
self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err);
err.note("the return type of a function must have a \
statically known size");
}
+ ObligationCauseCode::SizedYieldType => {
+ err.note("the yield type of a generator must have a \
+ statically known size");
+ }
ObligationCauseCode::AssignmentLhsSized => {
err.note("the left-hand-side of an assignment must have a statically known size");
}
pub code: ObligationCauseCode<'tcx>
}
+impl<'tcx> ObligationCause<'tcx> {
+ pub fn span<'a, 'gcx>(&self, tcx: &TyCtxt<'a, 'gcx, 'tcx>) -> Span {
+ match self.code {
+ ObligationCauseCode::CompareImplMethodObligation { .. } |
+ ObligationCauseCode::MainFunctionType |
+ ObligationCauseCode::StartFunctionType => {
+ tcx.sess.codemap().def_span(self.span)
+ }
+ _ => self.span,
+ }
+ }
+}
+
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from span.
VariableType(ast::NodeId),
/// Return type must be Sized
SizedReturnType,
+ /// Yield type must be Sized
+ SizedYieldType,
/// [T,..n] --> T must be Copy
RepeatVec,
pub subcommands: Vec<OnUnimplementedDirective>,
pub message: Option<OnUnimplementedFormatString>,
pub label: Option<OnUnimplementedFormatString>,
+ pub note: Option<OnUnimplementedFormatString>,
}
pub struct OnUnimplementedNote {
pub message: Option<String>,
pub label: Option<String>,
+ pub note: Option<String>,
}
impl OnUnimplementedNote {
pub fn empty() -> Self {
- OnUnimplementedNote { message: None, label: None }
+ OnUnimplementedNote { message: None, label: None, note: None }
}
}
let mut message = None;
let mut label = None;
+ let mut note = None;
let mut subcommands = vec![];
for item in item_iter {
if item.check_name("message") && message.is_none() {
tcx, trait_def_id, label_.as_str(), span)?);
continue;
}
+ } else if item.check_name("note") && note.is_none() {
+ if let Some(note_) = item.value_str() {
+ note = Some(OnUnimplementedFormatString::try_parse(
+ tcx, trait_def_id, note_.as_str(), span)?);
+ continue;
+ }
} else if item.check_name("on") && is_root &&
- message.is_none() && label.is_none()
+ message.is_none() && label.is_none() && note.is_none()
{
if let Some(items) = item.meta_item_list() {
if let Ok(subcommand) =
if errored {
Err(ErrorReported)
} else {
- Ok(OnUnimplementedDirective { condition, message, label, subcommands })
+ Ok(OnUnimplementedDirective { condition, message, label, subcommands, note })
}
}
message: None,
subcommands: vec![],
label: Some(OnUnimplementedFormatString::try_parse(
- tcx, trait_def_id, value.as_str(), attr.span)?)
+ tcx, trait_def_id, value.as_str(), attr.span)?),
+ note: None,
}))
} else {
return Err(parse_error(tcx, attr.span,
pub fn evaluate(&self,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_ref: ty::TraitRef<'tcx>,
- options: &[(&str, Option<&str>)])
+ options: &[(String, Option<String>)])
-> OnUnimplementedNote
{
let mut message = None;
let mut label = None;
- info!("evaluate({:?}, trait_ref={:?}, options={:?})",
- self, trait_ref, options);
+ let mut note = None;
+ info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
for command in self.subcommands.iter().chain(Some(self)).rev() {
if let Some(ref condition) = command.condition {
if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| {
- options.contains(&(&c.name().as_str(),
- match c.value_str().map(|s| s.as_str()) {
- Some(ref s) => Some(s),
+ options.contains(&(c.name().as_str().to_string(),
+ match c.value_str().map(|s| s.as_str().to_string()) {
+ Some(s) => Some(s),
None => None
}))
}) {
if let Some(ref label_) = command.label {
label = Some(label_.clone());
}
+
+ if let Some(ref note_) = command.note {
+ note = Some(note_.clone());
+ }
}
OnUnimplementedNote {
label: label.map(|l| l.format(tcx, trait_ref)),
- message: message.map(|m| m.format(tcx, trait_ref))
+ message: message.map(|m| m.format(tcx, trait_ref)),
+ note: note.map(|n| n.format(tcx, trait_ref)),
}
}
}
inferred_obligations: SnapshotVec<InferredObligationsSnapshotVecDelegate<'tcx>>,
- intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>,
+ intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub enum IntercrateAmbiguityCause {
DownstreamCrate {
trait_desc: String,
freshener: infcx.freshener(),
intercrate: None,
inferred_obligations: SnapshotVec::new(),
- intercrate_ambiguity_causes: Vec::new(),
+ intercrate_ambiguity_causes: None,
}
}
freshener: infcx.freshener(),
intercrate: Some(mode),
inferred_obligations: SnapshotVec::new(),
- intercrate_ambiguity_causes: Vec::new(),
+ intercrate_ambiguity_causes: None,
}
}
+ /// Enables tracking of intercrate ambiguity causes. These are
+ /// used in coherence to give improved diagnostics. We don't do
+ /// this until we detect a coherence error because it can lead to
+ /// false overflow results (#47139) and because it costs
+ /// computation time.
+ pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) {
+ assert!(self.intercrate.is_some());
+ assert!(self.intercrate_ambiguity_causes.is_none());
+ self.intercrate_ambiguity_causes = Some(vec![]);
+ debug!("selcx: enable_tracking_intercrate_ambiguity_causes");
+ }
+
+ /// Gets the intercrate ambiguity causes collected since tracking
+ /// was enabled and disables tracking at the same time. If
+ /// tracking is not enabled, just returns an empty vector.
+ pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> {
+ assert!(self.intercrate.is_some());
+ self.intercrate_ambiguity_causes.take().unwrap_or(vec![])
+ }
+
pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
self.infcx
}
self.infcx
}
- pub fn intercrate_ambiguity_causes(&self) -> &[IntercrateAmbiguityCause] {
- &self.intercrate_ambiguity_causes
- }
-
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
/// context's self.
fn in_snapshot<R, F>(&mut self, f: F) -> R
debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
stack.fresh_trait_ref);
// Heuristics: show the diagnostics when there are no candidates in crate.
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
- if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let cause = IntercrateAmbiguityCause::DownstreamCrate {
- trait_desc: trait_ref.to_string(),
- self_desc: if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- },
- };
- self.intercrate_ambiguity_causes.push(cause);
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let cause = IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc: trait_ref.to_string(),
+ self_desc: if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ },
+ };
+ debug!("evaluate_stack: pushing cause = {:?}", cause);
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
}
return EvaluatedToAmbig;
None => {}
Some(conflict) => {
debug!("coherence stage: not knowable");
- // Heuristics: show the diagnostics when there are no candidates in crate.
- let candidate_set = self.assemble_candidates(stack)?;
- if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
- !self.evaluate_candidate(stack, &c).may_apply()
- }) {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let trait_desc = trait_ref.to_string();
- let self_desc = if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- };
- let cause = if let Conflict::Upstream = conflict {
- IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
- } else {
- IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
- };
- self.intercrate_ambiguity_causes.push(cause);
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ let candidate_set = self.assemble_candidates(stack)?;
+ if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
+ !self.evaluate_candidate(stack, &c).may_apply()
+ }) {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let trait_desc = trait_ref.to_string();
+ let self_desc = if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ };
+ let cause = if let Conflict::Upstream = conflict {
+ IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc }
+ } else {
+ IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc }
+ };
+ debug!("evaluate_stack: pushing cause = {:?}", cause);
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
return Ok(None);
}
};
let tcx = tcx.global_tcx();
- let (le, ge) = tcx.infer_ctxt().enter(|infcx| {
- let overlap = traits::overlapping_impls(&infcx,
- possible_sibling,
- impl_def_id,
- traits::IntercrateMode::Issue43355);
- if let Some(overlap) = overlap {
+ let (le, ge) = traits::overlapping_impls(
+ tcx,
+ possible_sibling,
+ impl_def_id,
+ traits::IntercrateMode::Issue43355,
+ |overlap| {
if tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
return Ok((false, false));
}
} else {
Ok((le, ge))
}
- } else {
- Ok((false, false))
- }
- })?;
+ },
+ || Ok((false, false)),
+ )?;
if le && !ge {
debug!("descending as child of TraitRef {:?}",
return Ok(Inserted::Replaced(possible_sibling));
} else {
if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) {
- tcx.infer_ctxt().enter(|infcx| {
- if let Some(overlap) = traits::overlapping_impls(
- &infcx,
- possible_sibling,
- impl_def_id,
- traits::IntercrateMode::Fixed)
- {
- last_lint = Some(overlap_error(overlap));
- }
- });
+ traits::overlapping_impls(
+ tcx,
+ possible_sibling,
+ impl_def_id,
+ traits::IntercrateMode::Fixed,
+ |overlap| last_lint = Some(overlap_error(overlap)),
+ || (),
+ );
}
// no overlap (error bailed already via ?)
super::VariableType(id) => Some(super::VariableType(id)),
super::ReturnType(id) => Some(super::ReturnType(id)),
super::SizedReturnType => Some(super::SizedReturnType),
+ super::SizedYieldType => Some(super::SizedYieldType),
super::RepeatVec => Some(super::RepeatVec),
super::FieldSized(item) => Some(super::FieldSized(item)),
super::ConstSized => Some(super::ConstSized),
super::VariableType(_) |
super::ReturnType(_) |
super::SizedReturnType |
+ super::SizedYieldType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized(_) |
super::VariableType(_) |
super::ReturnType(_) |
super::SizedReturnType |
+ super::SizedYieldType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized(_) |
}
tcx.layout_depth.set(depth+1);
- let layout = LayoutDetails::compute_uncached(tcx, param_env, ty);
+ let cx = LayoutCx { tcx, param_env };
+ let layout = cx.layout_raw_uncached(ty);
tcx.layout_depth.set(depth);
layout
};
}
-impl<'a, 'tcx> LayoutDetails {
- fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ty: Ty<'tcx>)
- -> Result<&'tcx Self, LayoutError<'tcx>> {
- let cx = (tcx, param_env);
- let dl = cx.data_layout();
+#[derive(Copy, Clone)]
+pub struct LayoutCx<'tcx, C> {
+ pub tcx: C,
+ pub param_env: ty::ParamEnv<'tcx>
+}
+
+impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
+ fn layout_raw_uncached(self, ty: Ty<'tcx>)
+ -> Result<&'tcx LayoutDetails, LayoutError<'tcx>> {
+ let tcx = self.tcx;
+ let param_env = self.param_env;
+ let dl = self.data_layout();
let scalar_unit = |value: Primitive| {
let bits = value.size(dl).bits();
assert!(bits <= 128);
}
};
let scalar = |value: Primitive| {
- tcx.intern_layout(LayoutDetails::scalar(cx, scalar_unit(value)))
+ tcx.intern_layout(LayoutDetails::scalar(self, scalar_unit(value)))
};
let scalar_pair = |a: Scalar, b: Scalar| {
let align = a.value.align(dl).max(b.value.align(dl)).max(dl.aggregate_align);
Ok(match ty.sty {
// Basic scalars.
ty::TyBool => {
- tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
+ tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
value: Int(I8, false),
valid_range: 0..=1
}))
}
ty::TyChar => {
- tcx.intern_layout(LayoutDetails::scalar(cx, Scalar {
+ tcx.intern_layout(LayoutDetails::scalar(self, Scalar {
value: Int(I32, false),
valid_range: 0..=0x10FFFF
}))
ty::TyFnPtr(_) => {
let mut ptr = scalar_unit(Pointer);
ptr.valid_range.start = 1;
- tcx.intern_layout(LayoutDetails::scalar(cx, ptr))
+ tcx.intern_layout(LayoutDetails::scalar(self, ptr))
}
// The never type.
let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
if pointee.is_sized(tcx, param_env, DUMMY_SP) {
- return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
}
let unsized_part = tcx.struct_tail(pointee);
let metadata = match unsized_part.sty {
ty::TyForeign(..) => {
- return Ok(tcx.intern_layout(LayoutDetails::scalar(cx, data_ptr)));
+ return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
}
ty::TySlice(_) | ty::TyStr => {
scalar_unit(Int(dl.ptr_sized_integer(), false))
}
}
- let element = cx.layout_of(element)?;
+ let element = self.layout_of(element)?;
let count = count.val.to_const_int().unwrap().to_u64().unwrap();
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
})
}
ty::TySlice(element) => {
- let element = cx.layout_of(element)?;
+ let element = self.layout_of(element)?;
tcx.intern_layout(LayoutDetails {
variants: Variants::Single { index: 0 },
fields: FieldPlacement::Array {
// Tuples, generators and closures.
ty::TyGenerator(def_id, ref substs, _) => {
let tys = substs.field_tys(def_id, tcx);
- univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
StructKind::AlwaysSized)?
}
ty::TyClosure(def_id, ref substs) => {
let tys = substs.upvar_tys(def_id, tcx);
- univariant(&tys.map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ univariant(&tys.map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
StructKind::AlwaysSized)?
}
StructKind::MaybeUnsized
};
- univariant(&tys.iter().map(|ty| cx.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
+ univariant(&tys.iter().map(|ty| self.layout_of(ty)).collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), kind)?
}
// SIMD vector types.
ty::TyAdt(def, ..) if def.repr.simd() => {
- let element = cx.layout_of(ty.simd_type(tcx))?;
+ let element = self.layout_of(ty.simd_type(tcx))?;
let count = ty.simd_size(tcx) as u64;
assert!(count > 0);
let scalar = match element.abi {
// Cache the field layouts.
let variants = def.variants.iter().map(|v| {
v.fields.iter().map(|field| {
- cx.layout_of(field.ty(tcx, substs))
+ self.layout_of(field.ty(tcx, substs))
}).collect::<Result<Vec<_>, _>>()
}).collect::<Result<Vec<_>, _>>()?;
let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?;
st.variants = Variants::Single { index: v };
// Exclude 0 from the range of a newtype ABI NonZero<T>.
- if Some(def.did) == cx.tcx().lang_items().non_zero() {
+ if Some(def.did) == self.tcx.lang_items().non_zero() {
match st.abi {
Abi::Scalar(ref mut scalar) |
Abi::ScalarPair(ref mut scalar, _) => {
let count = (niche_variants.end - niche_variants.start + 1) as u128;
for (field_index, field) in variants[i].iter().enumerate() {
let (offset, niche, niche_start) =
- match field.find_niche(cx, count)? {
+ match field.find_niche(self, count)? {
Some(niche) => niche,
None => continue
};
/// This is invoked by the `layout_raw` query to record the final
/// layout of each type.
#[inline]
- fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty: Ty<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- layout: TyLayout<'tcx>) {
+ fn record_layout_for_printing(self, layout: TyLayout<'tcx>) {
// If we are running with `-Zprint-type-sizes`, record layouts for
// dumping later. Ignore layouts that are done with non-empty
// environments or non-monomorphic layouts, as the user only wants
// to see the stuff resulting from the final trans session.
if
- !tcx.sess.opts.debugging_opts.print_type_sizes ||
- ty.has_param_types() ||
- ty.has_self_ty() ||
- !param_env.caller_bounds.is_empty()
+ !self.tcx.sess.opts.debugging_opts.print_type_sizes ||
+ layout.ty.has_param_types() ||
+ layout.ty.has_self_ty() ||
+ !self.param_env.caller_bounds.is_empty()
{
return;
}
- Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
+ self.record_layout_for_printing_outlined(layout)
}
- fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty: Ty<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- layout: TyLayout<'tcx>) {
- let cx = (tcx, param_env);
+ fn record_layout_for_printing_outlined(self, layout: TyLayout<'tcx>) {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
- let type_desc = format!("{:?}", ty);
- tcx.sess.code_stats.borrow_mut().record_type_size(kind,
- type_desc,
- layout.align,
- layout.size,
- opt_discr_size,
- variants);
+ let type_desc = format!("{:?}", layout.ty);
+ self.tcx.sess.code_stats.borrow_mut().record_type_size(kind,
+ type_desc,
+ layout.align,
+ layout.size,
+ opt_discr_size,
+ variants);
};
- let adt_def = match ty.sty {
+ let adt_def = match layout.ty.sty {
ty::TyAdt(ref adt_def, _) => {
- debug!("print-type-size t: `{:?}` process adt", ty);
+ debug!("print-type-size t: `{:?}` process adt", layout.ty);
adt_def
}
ty::TyClosure(..) => {
- debug!("print-type-size t: `{:?}` record closure", ty);
+ debug!("print-type-size t: `{:?}` record closure", layout.ty);
record(DataTypeKind::Closure, None, vec![]);
return;
}
_ => {
- debug!("print-type-size t: `{:?}` skip non-nominal", ty);
+ debug!("print-type-size t: `{:?}` skip non-nominal", layout.ty);
return;
}
};
layout: TyLayout<'tcx>| {
let mut min_size = Size::from_bytes(0);
let field_info: Vec<_> = flds.iter().enumerate().map(|(i, &name)| {
- match layout.field(cx, i) {
+ match layout.field(self, i) {
Err(err) => {
bug!("no layout found for field {}: `{:?}`", name, err);
}
Variants::NicheFilling { .. } |
Variants::Tagged { .. } => {
debug!("print-type-size `{:#?}` adt general variants def {}",
- ty, adt_def.variants.len());
+ layout.ty, adt_def.variants.len());
let variant_infos: Vec<_> =
adt_def.variants.iter().enumerate().map(|(i, variant_def)| {
let fields: Vec<_> =
variant_def.fields.iter().map(|f| f.name).collect();
build_variant_info(Some(variant_def.name),
&fields,
- layout.for_variant(cx, i))
+ layout.for_variant(self, i))
})
.collect();
record(adt_kind.into(), match layout.variants {
- Variants::Tagged { ref discr, .. } => Some(discr.value.size(tcx)),
+ Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)),
_ => None
}, variant_infos);
}
assert!(!ty.has_infer_types());
// First try computing a static layout.
- let err = match (tcx, param_env).layout_of(ty) {
+ let err = match tcx.layout_of(param_env.and(ty)) {
Ok(layout) => {
return Ok(SizeSkeleton::Known(layout.size));
}
}
}
-impl<'a, 'gcx, 'tcx, T: Copy> HasDataLayout for (TyCtxt<'a, 'gcx, 'tcx>, T) {
+impl<'tcx, T: HasDataLayout> HasDataLayout for LayoutCx<'tcx, T> {
fn data_layout(&self) -> &TargetDataLayout {
- self.0.data_layout()
+ self.tcx.data_layout()
}
}
-impl<'a, 'gcx, 'tcx, T: Copy> HasTyCtxt<'gcx> for (TyCtxt<'a, 'gcx, 'tcx>, T) {
+impl<'gcx, 'tcx, T: HasTyCtxt<'gcx>> HasTyCtxt<'gcx> for LayoutCx<'tcx, T> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
- self.0.tcx()
+ self.tcx.tcx()
}
}
fn layout_of(self, ty: T) -> Self::TyLayout;
}
-impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (TyCtxt<'a, 'tcx, 'tcx>, ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
- #[inline]
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- let (tcx, param_env) = self;
-
- let ty = tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
- let details = tcx.layout_raw(param_env.reveal_all().and(ty))?;
+ let param_env = self.param_env.reveal_all();
+ let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env);
+ let details = self.tcx.layout_raw(param_env.and(ty))?;
let layout = TyLayout {
ty,
details
// completed, to avoid problems around recursive structures
// and the like. (Admitedly, I wasn't able to reproduce a problem
// here, but it seems like the right thing to do. -nmatsakis)
- LayoutDetails::record_layout_for_printing(tcx, ty, param_env, layout);
+ self.record_layout_for_printing(layout);
Ok(layout)
}
}
-impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for (ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>,
- ty::ParamEnv<'tcx>) {
+impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
- #[inline]
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- let (tcx_at, param_env) = self;
-
- let ty = tcx_at.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
- let details = tcx_at.layout_raw(param_env.reveal_all().and(ty))?;
+ let param_env = self.param_env.reveal_all();
+ let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
+ let details = self.tcx.layout_raw(param_env.reveal_all().and(ty))?;
let layout = TyLayout {
ty,
details
// completed, to avoid problems around recursive structures
// and the like. (Admitedly, I wasn't able to reproduce a problem
// here, but it seems like the right thing to do. -nmatsakis)
- LayoutDetails::record_layout_for_printing(tcx_at.tcx, ty, param_env, layout);
+ let cx = LayoutCx {
+ tcx: *self.tcx,
+ param_env: self.param_env
+ };
+ cx.record_layout_for_printing(layout);
Ok(layout)
}
}
+// Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users.
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+ /// Computes the layout of a type. Note that this implicitly
+ /// executes in "reveal all" mode.
+ #[inline]
+ pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
+ let cx = LayoutCx {
+ tcx: self,
+ param_env: param_env_and_ty.param_env
+ };
+ cx.layout_of(param_env_and_ty.value)
+ }
+}
+
+impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> {
+ /// Computes the layout of a type. Note that this implicitly
+ /// executes in "reveal all" mode.
+ #[inline]
+ pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
+ -> Result<TyLayout<'tcx>, LayoutError<'tcx>> {
+ let cx = LayoutCx {
+ tcx: self,
+ param_env: param_env_and_ty.param_env
+ };
+ cx.layout_of(param_env_and_ty.value)
+ }
+}
+
impl<'a, 'tcx> TyLayout<'tcx> {
pub fn for_variant<C>(&self, cx: C, variant_index: usize) -> Self
where C: LayoutOf<Ty<'tcx>> + HasTyCtxt<'tcx>,
state.map(move |d| d.ty.subst(tcx, self.substs))
}
+ /// This is the types of the fields of a generate which
+ /// is available before the generator transformation.
+ /// It includes the upvars and the state discriminant which is u32.
+ pub fn pre_transforms_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
+ impl Iterator<Item=Ty<'tcx>> + 'a
+ {
+ self.upvar_tys(def_id, tcx).chain(iter::once(tcx.types.u32))
+ }
+
/// This is the types of all the fields stored in a generator.
/// It includes the upvars, state types and the state discriminant which is u32.
pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) ->
impl Iterator<Item=Ty<'tcx>> + 'a
{
- let upvars = self.upvar_tys(def_id, tcx);
- let state = self.state_tys(def_id, tcx);
- upvars.chain(iter::once(tcx.types.u32)).chain(state)
+ self.pre_transforms_tys(def_id, tcx).chain(self.state_tys(def_id, tcx))
}
}
#include <stdint.h>
#include <string>
+#include <sstream>
#include <stdlib.h>
#include "s2wasm.h"
struct BinaryenRustModule {
BufferWithRandomAccess buffer;
+ std::string sourceMapJSON;
};
struct BinaryenRustModuleOptions {
bool ignoreUnknownSymbols;
bool debugInfo;
std::string startFunction;
+ std::string sourceMapUrl;
BinaryenRustModuleOptions() :
globalBase(0),
importMemory(false),
ignoreUnknownSymbols(false),
debugInfo(false),
- startFunction("")
+ startFunction(""),
+ sourceMapUrl("")
{}
};
options->startFunction = start;
}
+extern "C" void
+BinaryenRustModuleOptionsSetSourceMapUrl(BinaryenRustModuleOptions *options,
+ char *sourceMapUrl) {
+ options->sourceMapUrl = sourceMapUrl;
+}
+
extern "C" void
BinaryenRustModuleOptionsSetStackAllocation(BinaryenRustModuleOptions *options,
uint64_t stack) {
{
WasmBinaryWriter writer(&linker.getOutput().wasm, ret->buffer, options->debug);
writer.setNamesSection(options->debugInfo);
- // FIXME: support source maps?
- // writer.setSourceMap(sourceMapStream.get(), sourceMapUrl);
+
+ std::unique_ptr<std::ostringstream> sourceMapStream = nullptr;
+ {
+ sourceMapStream = make_unique<std::ostringstream>();
+ writer.setSourceMap(sourceMapStream.get(), options->sourceMapUrl);
+ }
// FIXME: support symbol maps?
// writer.setSymbolMap(symbolMap);
writer.write();
+
+ if (sourceMapStream) {
+ ret->sourceMapJSON = sourceMapStream->str();
+ }
}
return ret.release();
}
return M->buffer.size();
}
+extern "C" const char*
+BinaryenRustModuleSourceMapPtr(const BinaryenRustModule *M) {
+ return M->sourceMapJSON.data();
+}
+
+extern "C" size_t
+BinaryenRustModuleSourceMapLen(const BinaryenRustModule *M) {
+ return M->sourceMapJSON.length();
+}
+
extern "C" void
BinaryenRustModuleFree(BinaryenRustModule *M) {
delete M;
slice::from_raw_parts(ptr, len)
}
}
+
+ /// Returns the data of the source map JSON.
+ pub fn source_map(&self) -> &[u8] {
+ unsafe {
+ let ptr = BinaryenRustModuleSourceMapPtr(self.ptr);
+ let len = BinaryenRustModuleSourceMapLen(self.ptr);
+ slice::from_raw_parts(ptr, len)
+ }
+ }
}
impl Drop for Module {
self
}
+ /// Configures a `sourceMappingURL` custom section value for the module.
+ pub fn source_map_url(&mut self, url: &str) -> &mut Self {
+ let url = CString::new(url).unwrap();
+ unsafe {
+ BinaryenRustModuleOptionsSetSourceMapUrl(self.ptr, url.as_ptr());
+ }
+ self
+ }
+
/// Configures how much stack is initially allocated for the module. 1MB is
/// probably good enough for now.
pub fn stack(&mut self, amt: u64) -> &mut Self {
-> *mut BinaryenRustModule;
fn BinaryenRustModulePtr(module: *const BinaryenRustModule) -> *const u8;
fn BinaryenRustModuleLen(module: *const BinaryenRustModule) -> usize;
+ fn BinaryenRustModuleSourceMapPtr(module: *const BinaryenRustModule) -> *const u8;
+ fn BinaryenRustModuleSourceMapLen(module: *const BinaryenRustModule) -> usize;
fn BinaryenRustModuleFree(module: *mut BinaryenRustModule);
fn BinaryenRustModuleOptionsCreate()
debuginfo: bool);
fn BinaryenRustModuleOptionsSetStart(module: *mut BinaryenRustModuleOptions,
start: *const libc::c_char);
+ fn BinaryenRustModuleOptionsSetSourceMapUrl(module: *mut BinaryenRustModuleOptions,
+ sourceMapUrl: *const libc::c_char);
fn BinaryenRustModuleOptionsSetStackAllocation(
module: *mut BinaryenRustModuleOptions,
stack: u64,
};
match cause {
- mc::AliasableStatic => {
- // This happens when we have an `&mut` or assignment to a
- // static. We should have already reported a mutability
- // violation first, but may have continued compiling.
- self.tcx.sess.delay_span_bug(
- span,
- &format!("aliasability violation for static `{}`", prefix)
- );
- return;
- }
mc::AliasableStaticMut => {
// This path cannot occur. `static mut X` is not checked
// for aliasability violations.
span_bug!(span, "aliasability violation for static mut `{}`", prefix)
}
- mc::AliasableBorrowed => {}
+ mc::AliasableStatic | mc::AliasableBorrowed => {}
};
let blame = cmt.immutability_blame();
let mut err = match blame {
continue
}
- let mut_span = tcx.sess.codemap().span_until_char(ids[0].2, ' ');
+ let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2);
// Ok, every name wasn't used mutably, so issue a warning that this
// didn't need to be mutable.
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::LayoutOf;
use rustc::ty::util::IntTypeExt;
use rustc::ty::subst::{Substs, Subst};
use rustc::util::common::ErrorReported;
if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic {
let layout_of = |ty: Ty<'tcx>| {
let ty = tcx.erase_regions(&ty);
- (tcx.at(e.span), cx.param_env).layout_of(ty).map_err(|err| {
+ tcx.at(e.span).layout_of(cx.param_env.and(ty)).map_err(|err| {
ConstEvalErr { span: e.span, kind: LayoutError(err) }
})
};
return Ok(mk_const(Integral(Usize(ConstUsize::new(align,
tcx.sess.target.usize_ty).unwrap()))));
}
+ "type_id" => {
+ let type_id = tcx.type_id_hash(substs.type_at(0));
+ return Ok(mk_const(Integral(U64(type_id))));
+ }
_ => signal!(e, TypeckError)
}
}
};
let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
-
- // Ensure the source file isn't accidentally overwritten during compilation.
- match *input_path {
- Some(ref input_path) => {
- if outputs.contains_path(input_path) && sess.opts.will_create_output_file() {
- sess.err(&format!(
- "the input file \"{}\" would be overwritten by the generated executable",
- input_path.display()));
- return Err(CompileIncomplete::Stopped);
- }
- },
- None => {}
- }
-
let crate_name =
::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input);
-
let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
phase_2_configure_and_expand(
sess,
)?
};
- write_out_deps(sess, &outputs, &crate_name);
+ let output_paths = generated_output_paths(sess, &outputs, output.is_some(), &crate_name);
+
+ // Ensure the source file isn't accidentally overwritten during compilation.
+ if let Some(ref input_path) = *input_path {
+ if sess.opts.will_create_output_file() {
+ if output_contains_path(&output_paths, input_path) {
+ sess.err(&format!(
+ "the input file \"{}\" would be overwritten by the generated \
+ executable",
+ input_path.display()));
+ return Err(CompileIncomplete::Stopped);
+ }
+ if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
+ sess.err(&format!(
+ "the generated executable for the input file \"{}\" conflicts with the \
+ existing directory \"{}\"",
+ input_path.display(), dir_path.display()));
+ return Err(CompileIncomplete::Stopped);
+ }
+ }
+ }
+
+ write_out_deps(sess, &outputs, &output_paths);
if sess.opts.output_types.contains_key(&OutputType::DepInfo) &&
sess.opts.output_types.keys().count() == 1 {
return Ok(())
filename.to_string().replace(" ", "\\ ")
}
-fn write_out_deps(sess: &Session, outputs: &OutputFilenames, crate_name: &str) {
+// Returns all the paths that correspond to generated files.
+fn generated_output_paths(sess: &Session,
+ outputs: &OutputFilenames,
+ exact_name: bool,
+ crate_name: &str) -> Vec<PathBuf> {
let mut out_filenames = Vec::new();
for output_type in sess.opts.output_types.keys() {
let file = outputs.path(*output_type);
match *output_type {
- OutputType::Exe => {
- for output in sess.crate_types.borrow().iter() {
+ // If the filename has been overridden using `-o`, it will not be modified
+ // by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
+ OutputType::Exe if !exact_name => {
+ for crate_type in sess.crate_types.borrow().iter() {
let p = ::rustc_trans_utils::link::filename_for_input(
sess,
- *output,
+ *crate_type,
crate_name,
outputs
);
}
}
}
+ out_filenames
+}
+
+// Runs `f` on every output file path and returns the first non-None result, or None if `f`
+// returns None for every file path.
+fn check_output<F, T>(output_paths: &Vec<PathBuf>, f: F) -> Option<T>
+ where F: Fn(&PathBuf) -> Option<T> {
+ for output_path in output_paths {
+ if let Some(result) = f(output_path) {
+ return Some(result);
+ }
+ }
+ None
+}
+pub fn output_contains_path(output_paths: &Vec<PathBuf>, input_path: &PathBuf) -> bool {
+ let input_path = input_path.canonicalize().ok();
+ if input_path.is_none() {
+ return false
+ }
+ let check = |output_path: &PathBuf| {
+ if output_path.canonicalize().ok() == input_path {
+ Some(())
+ } else { None }
+ };
+ check_output(output_paths, check).is_some()
+}
+
+pub fn output_conflicts_with_dir(output_paths: &Vec<PathBuf>) -> Option<PathBuf> {
+ let check = |output_path: &PathBuf| {
+ if output_path.is_dir() {
+ Some(output_path.clone())
+ } else { None }
+ };
+ check_output(output_paths, check)
+}
+
+fn write_out_deps(sess: &Session,
+ outputs: &OutputFilenames,
+ out_filenames: &Vec<PathBuf>) {
// Write out dependency rules to the dep-info file if requested
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
return;
.map(|fmap| escape_dep_filename(&fmap.name))
.collect();
let mut file = fs::File::create(&deps_filename)?;
- for path in &out_filenames {
+ for path in out_filenames {
write!(file, "{}: {}\n\n", path.display(), files.join(" "))?;
}
Some(out_file.clone())
};
if *odir != None {
- sess.warn("ignoring --out-dir flag due to -o flag.");
+ sess.warn("ignoring --out-dir flag due to -o flag");
+ }
+ if !sess.opts.cg.extra_filename.is_empty() {
+ sess.warn("ignoring -C extra-filename flag due to -o flag");
}
let cur_dir = Path::new("");
}],
msg: msg.to_owned(),
show_code_when_inline: false,
+ approximate: false,
});
self
}
}],
msg: msg.to_owned(),
show_code_when_inline: true,
+ approximate: false,
});
self
}
}).collect(),
msg: msg.to_owned(),
show_code_when_inline: true,
+ approximate: false,
+ });
+ self
+ }
+
+ /// This is a suggestion that may contain mistakes or fillers and should
+ /// be read and understood by a human.
+ pub fn span_approximate_suggestion(&mut self, sp: Span, msg: &str,
+ suggestion: String) -> &mut Self {
+ self.suggestions.push(CodeSuggestion {
+ substitutions: vec![Substitution {
+ parts: vec![SubstitutionPart {
+ snippet: suggestion,
+ span: sp,
+ }],
+ }],
+ msg: msg.to_owned(),
+ show_code_when_inline: true,
+ approximate: true,
+ });
+ self
+ }
+
+ pub fn span_approximate_suggestions(&mut self, sp: Span, msg: &str,
+ suggestions: Vec<String>) -> &mut Self {
+ self.suggestions.push(CodeSuggestion {
+ substitutions: suggestions.into_iter().map(|snippet| Substitution {
+ parts: vec![SubstitutionPart {
+ snippet,
+ span: sp,
+ }],
+ }).collect(),
+ msg: msg.to_owned(),
+ show_code_when_inline: true,
+ approximate: true,
});
self
}
msg: &str,
suggestions: Vec<String>)
-> &mut Self);
+ forward!(pub fn span_approximate_suggestion(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestion: String)
+ -> &mut Self);
+ forward!(pub fn span_approximate_suggestions(&mut self,
+ sp: Span,
+ msg: &str,
+ suggestions: Vec<String>)
+ -> &mut Self);
forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self);
forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
pub substitutions: Vec<Substitution>,
pub msg: String,
pub show_code_when_inline: bool,
+ /// Whether or not the suggestion is approximate
+ ///
+ /// Sometimes we may show suggestions with placeholders,
+ /// which are useful for users but not useful for
+ /// tools like rustfix
+ pub approximate: bool,
}
#[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
// Code for annotating snippets.
-use syntax_pos::{Span, FileMap};
-use CodeMapper;
-use std::rc::Rc;
use Level;
-#[derive(Clone)]
-pub struct SnippetData {
- codemap: Rc<CodeMapper>,
- files: Vec<FileInfo>,
-}
-
-#[derive(Clone)]
-pub struct FileInfo {
- file: Rc<FileMap>,
-
- /// The "primary file", if any, gets a `-->` marker instead of
- /// `>>>`, and has a line-number/column printed and not just a
- /// filename (other files are not guaranteed to have line numbers
- /// or columns). It appears first in the listing. It is known to
- /// contain at least one primary span, though primary spans (which
- /// are designated with `^^^`) may also occur in other files.
- primary_span: Option<Span>,
-
- lines: Vec<Line>,
-}
-
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line {
pub line_index: usize,
// repr(transparent) types are allowed to have arbitrary ZSTs, not just
// PhantomData -- skip checking all ZST fields
if def.repr.transparent() {
- let is_zst = (cx, cx.param_env(field.did))
- .layout_of(field_ty)
+ let is_zst = cx
+ .layout_of(cx.param_env(field.did).and(field_ty))
.map(|layout| layout.is_zst())
.unwrap_or(false);
if is_zst {
Assign(_, ref value) => (value, "assigned value", false),
AssignOp(.., ref value) => (value, "assigned value", false),
InPlace(_, ref value) => (value, "emplacement value", false),
- Call(_, ref args) => {
- for arg in args {
- self.check_unused_parens_core(cx, arg, "function argument", false)
+ // either function/method call, or something this lint doesn't care about
+ ref call_or_other => {
+ let args_to_check;
+ let call_kind;
+ match *call_or_other {
+ Call(_, ref args) => {
+ call_kind = "function";
+ args_to_check = &args[..];
+ },
+ MethodCall(_, ref args) => {
+ call_kind = "method";
+ // first "argument" is self (which sometimes needs parens)
+ args_to_check = &args[1..];
+ }
+ // actual catch-all arm
+ _ => { return; }
}
- return;
- },
- MethodCall(_, ref args) => {
- for arg in &args[1..] { // first "argument" is self (which sometimes needs parens)
- self.check_unused_parens_core(cx, arg, "method argument", false)
+ // Don't lint if this is a nested macro expansion: otherwise, the lint could
+ // trigger in situations that macro authors shouldn't have to care about, e.g.,
+ // when a parenthesized token tree matched in one macro expansion is matched as
+ // an expression in another and used as a fn/method argument (Issue #47775)
+ if e.span.ctxt().outer().expn_info()
+ .map_or(false, |info| info.call_site.ctxt().outer()
+ .expn_info().is_some()) {
+ return;
+ }
+ let msg = format!("{} argument", call_kind);
+ for arg in args_to_check {
+ self.check_unused_parens_core(cx, arg, &msg, false);
}
return;
}
- _ => return,
};
self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
}
let scope_tree = borrows.0.scope_tree();
let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All).last().unwrap();
- match root_place {
- &Place::Local(local) => {
- if let Some(_) = self.storage_dead_or_drop_error_reported_l.replace(local) {
- debug!("report_does_not_live_long_enough({:?}): <suppressed>",
- (borrow, drop_span));
- return
- }
- }
- &Place::Static(ref statik) => {
- if let Some(_) = self.storage_dead_or_drop_error_reported_s
- .replace(statik.def_id)
- {
- debug!("report_does_not_live_long_enough({:?}): <suppressed>",
- (borrow, drop_span));
- return
- }
- },
- &Place::Projection(_) =>
- unreachable!("root_place is an unreachable???")
- };
-
let borrow_span = self.mir.source_info(borrow.location).span;
let proper_span = match *root_place {
Place::Local(local) => self.mir.local_decls[local].source_info.span,
_ => drop_span,
};
+ if self.access_place_error_reported.contains(&(root_place.clone(), borrow_span)) {
+ debug!("suppressing access_place error when borrow doesn't live long enough for {:?}",
+ borrow_span);
+ return;
+ }
+
+ self.access_place_error_reported.insert((root_place.clone(), borrow_span));
+
match (borrow.region, &self.describe_place(&borrow.borrowed_place)) {
(RegionKind::ReScope(_), Some(name)) => {
self.report_scoped_local_value_does_not_live_long_enough(
self.describe_field_from_ty(&tnm.ty, field)
}
ty::TyArray(ty, _) | ty::TySlice(ty) => self.describe_field_from_ty(&ty, field),
- ty::TyClosure(closure_def_id, _) => {
+ ty::TyClosure(def_id, _) | ty::TyGenerator(def_id, _, _) => {
// Convert the def-id into a node-id. node-ids are only valid for
// the local code in the current crate, so this returns an `Option` in case
// the closure comes from another crate. But in that case we wouldn't
// be borrowck'ing it, so we can just unwrap:
- let node_id = self.tcx.hir.as_local_node_id(closure_def_id).unwrap();
+ let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
let freevar = self.tcx.with_freevars(node_id, |fv| fv[field.index()]);
self.tcx.hir.name(freevar.var_id()).to_string()
use rustc::infer::InferCtxt;
use rustc::ty::{self, ParamEnv, TyCtxt};
use rustc::ty::maps::Providers;
-use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Local, Location, Place};
+use rustc::mir::{AssertMessage, BasicBlock, BorrowKind, Location, Place};
use rustc::mir::{Mir, Mutability, Operand, Projection, ProjectionElem, Rvalue};
use rustc::mir::{Field, Statement, StatementKind, Terminator, TerminatorKind};
use rustc::mir::ClosureRegionRequirements;
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => false,
hir::BodyOwnerKind::Fn => true,
},
- storage_dead_or_drop_error_reported_l: FxHashSet(),
- storage_dead_or_drop_error_reported_s: FxHashSet(),
+ access_place_error_reported: FxHashSet(),
reservation_error_reported: FxHashSet(),
nonlexical_regioncx: opt_regioncx.clone(),
};
/// I'm not sure this is the right approach - @eddyb could you try and
/// figure this out?
locals_are_invalidated_at_exit: bool,
- /// This field keeps track of when storage dead or drop errors are reported
- /// in order to stop duplicate error reporting and identify the conditions required
- /// for a "temporary value dropped here while still borrowed" error. See #45360.
- storage_dead_or_drop_error_reported_l: FxHashSet<Local>,
- /// Same as the above, but for statics (thread-locals)
- storage_dead_or_drop_error_reported_s: FxHashSet<DefId>,
+ /// This field keeps track of when borrow errors are reported in the access_place function
+ /// so that there is no duplicate reporting. This field cannot also be used for the conflicting
+ /// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
+ /// of the `Span` type (while required to mute some errors) stops the muting of the reservation
+ /// errors.
+ access_place_error_reported: FxHashSet<(Place<'tcx>, Span)>,
/// This field keeps track of when borrow conflict errors are reported
/// for reservations, so that we don't report seemingly duplicate
/// errors for corresponding activations
match stmt.kind {
StatementKind::Assign(ref lhs, ref rhs) => {
+ self.consume_rvalue(
+ ContextKind::AssignRhs.new(location),
+ (rhs, span),
+ location,
+ flow_state,
+ );
+
self.mutate_place(
ContextKind::AssignLhs.new(location),
(lhs, span),
JustWrite,
flow_state,
);
-
- self.consume_rvalue(
- ContextKind::AssignRhs.new(location),
- (rhs, span),
- location,
- flow_state,
- );
}
StatementKind::SetDiscriminant {
ref place,
if let Activation(_, borrow_index) = rw {
if self.reservation_error_reported.contains(&place_span.0) {
- debug!(
- "skipping access_place for activation of invalid reservation \
- place: {:?} borrow_index: {:?}",
- place_span.0,
- borrow_index
- );
+ debug!("skipping access_place for activation of invalid reservation \
+ place: {:?} borrow_index: {:?}", place_span.0, borrow_index);
return AccessErrorsReported {
mutability_error: false,
conflict_error: true,
}
}
+ if self.access_place_error_reported.contains(&(place_span.0.clone(), place_span.1)) {
+ debug!("access_place: suppressing error place_span=`{:?}` kind=`{:?}`",
+ place_span, kind);
+ return AccessErrorsReported {
+ mutability_error: false,
+ conflict_error: true,
+ };
+ }
+
let mutability_error =
self.check_access_permissions(place_span, rw, is_local_mutation_allowed);
let conflict_error =
self.check_access_for_conflict(context, place_span, sd, rw, flow_state);
+ if conflict_error || mutability_error {
+ debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`",
+ place_span, kind);
+ self.access_place_error_reported.insert((place_span.0.clone(), place_span.1));
+ }
+
AccessErrorsReported {
mutability_error,
conflict_error,
place_span.0
);
this.reservation_error_reported.insert(place_span.0.clone());
- }
+ },
Activation(_, activating) => {
debug!(
"observing check_place for activation of \
borrow_index: {:?}",
activating
);
- }
- Read(..) | Write(..) => {}
+ },
+ Read(..) | Write(..) => {},
}
match kind {
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::mir::Local;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc::traits;
+use rustc::infer::InferOk;
use rustc::util::common::ErrorReported;
+use borrow_check::nll::type_check::AtLocation;
use rustc_data_structures::fx::FxHashSet;
use syntax::codemap::DUMMY_SP;
use util::liveness::LivenessResults;
location
);
- let tcx = self.cx.infcx.tcx;
- let mut types = vec![(dropped_ty, 0)];
- let mut known = FxHashSet();
- while let Some((ty, depth)) = types.pop() {
- let span = DUMMY_SP; // FIXME
- let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
- Ok(result) => result,
- Err(ErrorReported) => {
- continue;
- }
- };
-
- let ty::DtorckConstraint {
- outlives,
- dtorck_types,
- } = result;
-
- // All things in the `outlives` array may be touched by
- // the destructor and must be live at this point.
- for outlive in outlives {
- let cause = Cause::DropVar(dropped_local, location);
- self.push_type_live_constraint(outlive, location, cause);
- }
+ // If we end visiting the same type twice (usually due to a cycle involving
+ // associated types), we need to ensure that its region types match up with the type
+ // we added to the 'known' map the first time around. For this reason, we need
+ // our infcx to hold onto its calculated region constraints after each call
+ // to dtorck_constraint_for_ty. Otherwise, normalizing the corresponding associated
+ // type will end up instantiating the type with a new set of inference variables
+ // Since this new type will never be in 'known', we end up looping forever.
+ //
+ // For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
+ // ourselves in one large 'fully_perform_op' callback.
+ let (type_constraints, kind_constraints) = self.cx.fully_perform_op(location.at_self(),
+ |cx| {
+
+ let tcx = cx.infcx.tcx;
+ let mut selcx = traits::SelectionContext::new(cx.infcx);
+ let cause = cx.misc(cx.last_span);
+
+ let mut types = vec![(dropped_ty, 0)];
+ let mut final_obligations = Vec::new();
+ let mut type_constraints = Vec::new();
+ let mut kind_constraints = Vec::new();
- // However, there may also be some types that
- // `dtorck_constraint_for_ty` could not resolve (e.g.,
- // associated types and parameters). We need to normalize
- // associated types here and possibly recursively process.
- for ty in dtorck_types {
- let ty = self.cx.normalize(&ty, location);
- let ty = self.cx.infcx.resolve_type_and_region_vars_if_possible(&ty);
- match ty.sty {
- ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
- let cause = Cause::DropVar(dropped_local, location);
- self.push_type_live_constraint(ty, location, cause);
+ let mut known = FxHashSet();
+
+ while let Some((ty, depth)) = types.pop() {
+ let span = DUMMY_SP; // FIXME
+ let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
+ Ok(result) => result,
+ Err(ErrorReported) => {
+ continue;
}
+ };
+
+ let ty::DtorckConstraint {
+ outlives,
+ dtorck_types,
+ } = result;
+
+ // All things in the `outlives` array may be touched by
+ // the destructor and must be live at this point.
+ for outlive in outlives {
+ let cause = Cause::DropVar(dropped_local, location);
+ kind_constraints.push((outlive, location, cause));
+ }
- _ => if known.insert(ty) {
- types.push((ty, depth + 1));
- },
+ // However, there may also be some types that
+ // `dtorck_constraint_for_ty` could not resolve (e.g.,
+ // associated types and parameters). We need to normalize
+ // associated types here and possibly recursively process.
+ for ty in dtorck_types {
+ let traits::Normalized { value: ty, obligations } =
+ traits::normalize(&mut selcx, cx.param_env, cause.clone(), &ty);
+
+ final_obligations.extend(obligations);
+
+ let ty = cx.infcx.resolve_type_and_region_vars_if_possible(&ty);
+ match ty.sty {
+ ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
+ let cause = Cause::DropVar(dropped_local, location);
+ type_constraints.push((ty, location, cause));
+ }
+
+ _ => if known.insert(ty) {
+ types.push((ty, depth + 1));
+ },
+ }
}
}
+
+ Ok(InferOk {
+ value: (type_constraints, kind_constraints), obligations: final_obligations
+ })
+ }).unwrap();
+
+ for (ty, location, cause) in type_constraints {
+ self.push_type_live_constraint(ty, location, cause);
+ }
+
+ for (kind, location, cause) in kind_constraints {
+ self.push_type_live_constraint(kind, location, cause);
}
}
}
}
};
if let PlaceContext::Copy = context {
- let ty = place_ty.to_ty(self.tcx());
- if self.cx
- .infcx
- .type_moves_by_default(self.cx.param_env, ty, DUMMY_SP)
- {
- span_mirbug!(self, place, "attempted copy of non-Copy type ({:?})", ty);
- }
+ let tcx = self.tcx();
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.lang_items().copy_trait().unwrap(),
+ substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]),
+ };
+
+ // In order to have a Copy operand, the type T of the value must be Copy. Note that we
+ // prove that T: Copy, rather than using the type_moves_by_default test. This is
+ // important because type_moves_by_default ignores the resulting region obligations and
+ // assumes they pass. This can result in bounds from Copy impls being unsoundly ignored
+ // (e.g., #29149). Note that we decide to use Copy before knowing whether the bounds
+ // fully apply: in effect, the rule is that if a value of some type could implement
+ // Copy, then it must.
+ self.cx.prove_trait_ref(trait_ref, location);
}
place_ty
}
}
}
ty::TyGenerator(def_id, substs, _) => {
- // Try upvars first. `field_tys` requires final optimized MIR.
- if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) {
+ // Try pre-transform fields first (upvars and current state)
+ if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field.index()) {
return Ok(ty);
}
+ // Then try `field_tys` which contains all the fields, but it
+ // requires the final optimized MIR.
return match substs.field_tys(def_id, tcx).nth(field.index()) {
Some(ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
- field_count: substs.field_tys(def_id, tcx).count() + 1,
+ field_count: substs.field_tys(def_id, tcx).count(),
}),
};
}
}
}
AggregateKind::Generator(def_id, substs, _) => {
- if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field_index) {
+ // Try pre-transform fields first (upvars and current state)
+ if let Some(ty) = substs.pre_transforms_tys(def_id, tcx).nth(field_index) {
Ok(ty)
} else {
+ // Then try `field_tys` which contains all the fields, but it
+ // requires the final optimized MIR.
match substs.field_tys(def_id, tcx).nth(field_index) {
Some(ty) => Ok(ty),
None => Err(FieldAccessError::OutOfRange {
- field_count: substs.field_tys(def_id, tcx).count() + 1,
+ field_count: substs.field_tys(def_id, tcx).count(),
}),
}
}
--- /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.
+
+pub use super::*;
+
+use rustc::mir::*;
+use rustc::mir::visit::Visitor;
+use dataflow::BitDenotation;
+
+/// This calculates if any part of a MIR local could have previously been borrowed.
+/// This means that once a local has been borrowed, its bit will always be set
+/// from that point and onwards, even if the borrow ends. You could also think of this
+/// as computing the lifetimes of infinite borrows.
+/// This is used to compute which locals are live during a yield expression for
+/// immovable generators.
+#[derive(Copy, Clone)]
+pub struct HaveBeenBorrowedLocals<'a, 'tcx: 'a> {
+ mir: &'a Mir<'tcx>,
+}
+
+impl<'a, 'tcx: 'a> HaveBeenBorrowedLocals<'a, 'tcx> {
+ pub fn new(mir: &'a Mir<'tcx>)
+ -> Self {
+ HaveBeenBorrowedLocals { mir: mir }
+ }
+
+ pub fn mir(&self) -> &Mir<'tcx> {
+ self.mir
+ }
+}
+
+impl<'a, 'tcx> BitDenotation for HaveBeenBorrowedLocals<'a, 'tcx> {
+ type Idx = Local;
+ fn name() -> &'static str { "has_been_borrowed_locals" }
+ fn bits_per_block(&self) -> usize {
+ self.mir.local_decls.len()
+ }
+
+ fn start_block_effect(&self, _sets: &mut IdxSet<Local>) {
+ // Nothing is borrowed on function entry
+ }
+
+ fn statement_effect(&self,
+ sets: &mut BlockSets<Local>,
+ loc: Location) {
+ BorrowedLocalsVisitor {
+ sets,
+ }.visit_statement(loc.block, &self.mir[loc.block].statements[loc.statement_index], loc);
+ }
+
+ fn terminator_effect(&self,
+ sets: &mut BlockSets<Local>,
+ loc: Location) {
+ BorrowedLocalsVisitor {
+ sets,
+ }.visit_terminator(loc.block, self.mir[loc.block].terminator(), loc);
+ }
+
+ fn propagate_call_return(&self,
+ _in_out: &mut IdxSet<Local>,
+ _call_bb: mir::BasicBlock,
+ _dest_bb: mir::BasicBlock,
+ _dest_place: &mir::Place) {
+ // Nothing to do when a call returns successfully
+ }
+}
+
+impl<'a, 'tcx> BitwiseOperator for HaveBeenBorrowedLocals<'a, 'tcx> {
+ #[inline]
+ fn join(&self, pred1: usize, pred2: usize) -> usize {
+ pred1 | pred2 // "maybe" means we union effects of both preds
+ }
+}
+
+impl<'a, 'tcx> InitialFlow for HaveBeenBorrowedLocals<'a, 'tcx> {
+ #[inline]
+ fn bottom_value() -> bool {
+ false // bottom = unborrowed
+ }
+}
+
+struct BorrowedLocalsVisitor<'b, 'c: 'b> {
+ sets: &'b mut BlockSets<'c, Local>,
+}
+
+fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
+ match *place {
+ Place::Local(l) => Some(l),
+ Place::Static(..) => None,
+ Place::Projection(ref proj) => {
+ match proj.elem {
+ ProjectionElem::Deref => None,
+ _ => find_local(&proj.base)
+ }
+ }
+ }
+}
+
+impl<'tcx, 'b, 'c> Visitor<'tcx> for BorrowedLocalsVisitor<'b, 'c> {
+ fn visit_rvalue(&mut self,
+ rvalue: &Rvalue<'tcx>,
+ location: Location) {
+ if let Rvalue::Ref(_, _, ref place) = *rvalue {
+ if let Some(local) = find_local(place) {
+ self.sets.gen(&local);
+ }
+ }
+
+ self.super_rvalue(rvalue, location)
+ }
+}
// Issue #46746: Two-phase borrows handles
// stmts of form `Tmp = &mut Borrow` ...
match lhs {
- Place::Local(..) => {} // okay
- Place::Static(..) => unreachable!(), // (filtered by is_unsafe_place)
+ Place::Local(..) | Place::Static(..) => {} // okay
Place::Projection(..) => {
// ... can assign into projections,
// e.g. `box (&mut _)`. Current
pub use self::storage_liveness::*;
+mod borrowed_locals;
+
+pub use self::borrowed_locals::*;
+
#[allow(dead_code)]
pub(super) mod borrows;
pub use self::impls::{DefinitelyInitializedPlaces, MovingOutStatements};
pub use self::impls::EverInitializedPlaces;
pub use self::impls::borrows::{Borrows, BorrowData};
+pub use self::impls::HaveBeenBorrowedLocals;
pub(crate) use self::impls::borrows::{ActiveBorrows, Reservations, ReserveOrActivateIndex};
pub use self::at_location::{FlowAtLocation, FlowsAtLocation};
pub(crate) use self::drop_flag_effects::*;
arg: expr.to_ref(),
},
};
- ExprKind::Cast { source: expr.to_ref() }
+ let cast_expr = Expr {
+ temp_lifetime,
+ ty: adjustment.target,
+ span,
+ kind: ExprKind::Cast { source: expr.to_ref() }
+ };
+
+ // To ensure that both implicit and explicit coercions are
+ // handled the same way, we insert an extra layer of indirection here.
+ // For explicit casts (e.g. 'foo as *const T'), the source of the 'Use'
+ // will be an ExprKind::Hair with the appropriate cast expression. Here,
+ // we make our Use source the generated Cast from the original coercion.
+ //
+ // In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by
+ // as_operand, not by as_rvalue - causing the cast result to be stored in a temporary.
+ // Ordinary, this is identical to using the cast directly as an rvalue. However, if the
+ // source of the cast was previously borrowed as mutable, storing the cast in a
+ // temporary gives the source a chance to expire before the cast is used. For
+ // structs with a self-referential *mut ptr, this allows assignment to work as
+ // expected.
+ //
+ // For example, consider the type 'struct Foo { field: *mut Foo }',
+ // The method 'fn bar(&mut self) { self.field = self }'
+ // triggers a coercion from '&mut self' to '*mut self'. In order
+ // for the assignment to be valid, the implicit borrow
+ // of 'self' involved in the coercion needs to end before the local
+ // containing the '*mut T' is assigned to 'self.field' - otherwise,
+ // we end up trying to assign to 'self.field' while we have another mutable borrow
+ // active.
+ //
+ // We only need to worry about this kind of thing for coercions from refs to ptrs,
+ // since they get rid of a borrow implicitly.
+ ExprKind::Use { source: cast_expr.to_ref() }
}
Adjust::Unsize => {
ExprKind::Unsize { source: expr.to_ref() }
ecx.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?;
}
+ "type_id" => {
+ let ty = substs.type_at(0);
+ let type_id = ecx.tcx.type_id_hash(ty) as u128;
+ ecx.write_primval(dest, PrimVal::from_u128(type_id), dest_layout.ty)?;
+ }
+
name => return Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()),
}
type TyLayout = EvalResult<'tcx, TyLayout<'tcx>>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- (self.tcx, self.param_env).layout_of(ty)
+ self.tcx.layout_of(self.param_env.and(ty))
.map_err(|layout| EvalErrorKind::Layout(layout).into())
}
}
{
debug!("build_clone_shim(def_id={:?})", def_id);
- let mut builder = CloneShimBuilder::new(tcx, def_id);
+ let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
let is_copy = !self_ty.moves_by_default(tcx, tcx.param_env(def_id), builder.span);
+ let dest = Place::Local(RETURN_PLACE);
+ let src = Place::Local(Local::new(1+0)).deref();
+
match self_ty.sty {
_ if is_copy => builder.copy_shim(),
ty::TyArray(ty, len) => {
let len = len.val.to_const_int().unwrap().to_u64().unwrap();
- builder.array_shim(ty, len)
+ builder.array_shim(dest, src, ty, len)
}
ty::TyClosure(def_id, substs) => {
builder.tuple_like_shim(
- &substs.upvar_tys(def_id, tcx).collect::<Vec<_>>(),
- AggregateKind::Closure(def_id, substs)
+ dest, src,
+ substs.upvar_tys(def_id, tcx)
)
}
- ty::TyTuple(tys, _) => builder.tuple_like_shim(&**tys, AggregateKind::Tuple),
+ ty::TyTuple(tys, _) => builder.tuple_like_shim(dest, src, tys.iter().cloned()),
_ => {
bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty)
}
}
impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
- fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Self {
- let sig = tcx.fn_sig(def_id);
+ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
+ self_ty: Ty<'tcx>) -> Self {
+ // we must subst the self_ty because it's
+ // otherwise going to be TySelf and we can't index
+ // or access fields of a Place of type TySelf.
+ let substs = tcx.mk_substs_trait(self_ty, &[]);
+ let sig = tcx.fn_sig(def_id).subst(tcx, substs);
let sig = tcx.erase_late_bound_regions(&sig);
let span = tcx.def_span(def_id);
})
}
+ /// Gives the index of an upcoming BasicBlock, with an offset.
+ /// offset=0 will give you the index of the next BasicBlock,
+ /// offset=1 will give the index of the next-to-next block,
+ /// offset=-1 will give you the index of the last-created block
+ fn block_index_offset(&mut self, offset: usize) -> BasicBlock {
+ BasicBlock::new(self.blocks.len() + offset)
+ }
+
fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
Statement {
source_info: self.source_info(),
fn make_clone_call(
&mut self,
+ dest: Place<'tcx>,
+ src: Place<'tcx>,
ty: Ty<'tcx>,
- rcvr_field: Place<'tcx>,
next: BasicBlock,
cleanup: BasicBlock
- ) -> Place<'tcx> {
+ ) {
let tcx = self.tcx;
let substs = Substs::for_item(
})
);
- let loc = self.make_place(Mutability::Not, ty);
-
- // `let ref_loc: &ty = &rcvr_field;`
+ // `let ref_loc: &ty = &src;`
let statement = self.make_statement(
StatementKind::Assign(
ref_loc.clone(),
- Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, rcvr_field)
+ Rvalue::Ref(tcx.types.re_erased, BorrowKind::Shared, src)
)
);
self.block(vec![statement], TerminatorKind::Call {
func,
args: vec![Operand::Move(ref_loc)],
- destination: Some((loc.clone(), next)),
+ destination: Some((dest, next)),
cleanup: Some(cleanup),
}, false);
-
- loc
}
fn loop_header(
}
}
- fn array_shim(&mut self, ty: Ty<'tcx>, len: u64) {
+ fn array_shim(&mut self, dest: Place<'tcx>, src: Place<'tcx>, ty: Ty<'tcx>, len: u64) {
let tcx = self.tcx;
let span = self.span;
- let rcvr = Place::Local(Local::new(1+0)).deref();
let beg = self.local_decls.push(temp_decl(Mutability::Mut, tcx.types.usize, span));
let end = self.make_place(Mutability::Not, tcx.types.usize);
- let ret = self.make_place(Mutability::Mut, tcx.mk_array(ty, len));
// BB #0
// `let mut beg = 0;`
self.loop_header(Place::Local(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
// BB #2
- // `let cloned = Clone::clone(rcvr[beg])`;
+ // `dest[i] = Clone::clone(src[beg])`;
// Goto #3 if ok, #5 if unwinding happens.
- let rcvr_field = rcvr.clone().index(beg);
- let cloned = self.make_clone_call(ty, rcvr_field, BasicBlock::new(3), BasicBlock::new(5));
+ let dest_field = dest.clone().index(beg);
+ let src_field = src.clone().index(beg);
+ self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3),
+ BasicBlock::new(5));
// BB #3
- // `ret[beg] = cloned;`
// `beg = beg + 1;`
// `goto #1`;
- let ret_field = ret.clone().index(beg);
let statements = vec![
- self.make_statement(
- StatementKind::Assign(
- ret_field,
- Rvalue::Use(Operand::Move(cloned))
- )
- ),
self.make_statement(
StatementKind::Assign(
Place::Local(beg),
self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
// BB #4
- // `return ret;`
- let ret_statement = self.make_statement(
- StatementKind::Assign(
- Place::Local(RETURN_PLACE),
- Rvalue::Use(Operand::Move(ret.clone())),
- )
- );
- self.block(vec![ret_statement], TerminatorKind::Return, false);
+ // `return dest;`
+ self.block(vec![], TerminatorKind::Return, false);
// BB #5 (cleanup)
// `let end = beg;`
BasicBlock::new(7), BasicBlock::new(9), true);
// BB #7 (cleanup)
- // `drop(ret[beg])`;
+ // `drop(dest[beg])`;
self.block(vec![], TerminatorKind::Drop {
- location: ret.index(beg),
+ location: dest.index(beg),
target: BasicBlock::new(8),
unwind: None,
}, true);
self.block(vec![], TerminatorKind::Resume, true);
}
- fn tuple_like_shim(&mut self, tys: &[ty::Ty<'tcx>], kind: AggregateKind<'tcx>) {
- match kind {
- AggregateKind::Tuple | AggregateKind::Closure(..) => (),
- _ => bug!("only tuples and closures are accepted"),
- };
+ fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>,
+ src: Place<'tcx>, tys: I)
+ where I: Iterator<Item = ty::Ty<'tcx>> {
+ let mut previous_field = None;
+ for (i, ity) in tys.enumerate() {
+ let field = Field::new(i);
+ let src_field = src.clone().field(field, ity);
- let rcvr = Place::Local(Local::new(1+0)).deref();
+ let dest_field = dest.clone().field(field, ity);
- let mut returns = Vec::new();
- for (i, ity) in tys.iter().enumerate() {
- let rcvr_field = rcvr.clone().field(Field::new(i), *ity);
+ // #(2i + 1) is the cleanup block for the previous clone operation
+ let cleanup_block = self.block_index_offset(1);
+ // #(2i + 2) is the next cloning block
+ // (or the Return terminator if this is the last block)
+ let next_block = self.block_index_offset(2);
// BB #(2i)
- // `returns[i] = Clone::clone(&rcvr.i);`
+ // `dest.i = Clone::clone(&src.i);`
// Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
- returns.push(
- self.make_clone_call(
- *ity,
- rcvr_field,
- BasicBlock::new(2 * i + 2),
- BasicBlock::new(2 * i + 1),
- )
+ self.make_clone_call(
+ dest_field.clone(),
+ src_field,
+ ity,
+ next_block,
+ cleanup_block,
);
// BB #(2i + 1) (cleanup)
- if i == 0 {
- // Nothing to drop, just resume.
- self.block(vec![], TerminatorKind::Resume, true);
- } else {
+ if let Some((previous_field, previous_cleanup)) = previous_field.take() {
// Drop previous field and goto previous cleanup block.
self.block(vec![], TerminatorKind::Drop {
- location: returns[i - 1].clone(),
- target: BasicBlock::new(2 * i - 1),
+ location: previous_field,
+ target: previous_cleanup,
unwind: None,
}, true);
+ } else {
+ // Nothing to drop, just resume.
+ self.block(vec![], TerminatorKind::Resume, true);
}
+
+ previous_field = Some((dest_field, cleanup_block));
}
- // `return kind(returns[0], returns[1], ..., returns[tys.len() - 1]);`
- let ret_statement = self.make_statement(
- StatementKind::Assign(
- Place::Local(RETURN_PLACE),
- Rvalue::Aggregate(
- box kind,
- returns.into_iter().map(Operand::Move).collect()
- )
- )
- );
- self.block(vec![ret_statement], TerminatorKind::Return, false);
+ self.block(vec![], TerminatorKind::Return, false);
}
}
use transform::{MirPass, MirSource};
use transform::simplify;
use transform::no_landing_pads::no_landing_pads;
-use dataflow::{do_dataflow, DebugFormatted, MaybeStorageLive, state_for_location};
+use dataflow::{do_dataflow, DebugFormatted, state_for_location};
+use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
pub struct StateTransform;
HashMap<BasicBlock, liveness::LocalSet>) {
let dead_unwinds = IdxSetBuf::new_empty(mir.basic_blocks().len());
let node_id = tcx.hir.as_local_node_id(source.def_id).unwrap();
- let analysis = MaybeStorageLive::new(mir);
+
+ // Calculate when MIR locals have live storage. This gives us an upper bound of their
+ // lifetimes.
+ let storage_live_analysis = MaybeStorageLive::new(mir);
let storage_live =
- do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+ do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, storage_live_analysis,
|bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
+ // Find the MIR locals which do not use StorageLive/StorageDead statements.
+ // The storage of these locals are always live.
let mut ignored = StorageIgnored(IdxSetBuf::new_filled(mir.local_decls.len()));
ignored.visit_mir(mir);
- let mut borrowed_locals = BorrowedLocals(IdxSetBuf::new_empty(mir.local_decls.len()));
- borrowed_locals.visit_mir(mir);
+ // Calculate the MIR locals which have been previously
+ // borrowed (even if they are still active).
+ // This is only used for immovable generators.
+ let borrowed_locals = if !movable {
+ let analysis = HaveBeenBorrowedLocals::new(mir);
+ let result =
+ do_dataflow(tcx, mir, node_id, &[], &dead_unwinds, analysis,
+ |bd, p| DebugFormatted::new(&bd.mir().local_decls[p]));
+ Some((analysis, result))
+ } else {
+ None
+ };
+ // Calculate the liveness of MIR locals ignoring borrows.
let mut set = liveness::LocalSet::new_empty(mir.local_decls.len());
let mut liveness = liveness::liveness_of_locals(mir, LivenessMode {
include_regular_use: true,
statement_index: data.statements.len(),
};
- let storage_liveness = state_for_location(loc, &analysis, &storage_live, mir);
+ if let Some((ref analysis, ref result)) = borrowed_locals {
+ let borrowed_locals = state_for_location(loc,
+ analysis,
+ result,
+ mir);
+ // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
+ // This is correct for movable generators since borrows cannot live across
+ // suspension points. However for immovable generators we need to account for
+ // borrows, so we conseratively assume that all borrowed locals live forever.
+ // To do this we just union our `liveness` result with `borrowed_locals`, which
+ // contains all the locals which has been borrowed before this suspension point.
+ // If a borrow is converted to a raw reference, we must also assume that it lives
+ // forever. Note that the final liveness is still bounded by the storage liveness
+ // of the local, which happens using the `intersect` operation below.
+ liveness.outs[block].union(&borrowed_locals);
+ }
+
+ let mut storage_liveness = state_for_location(loc,
+ &storage_live_analysis,
+ &storage_live,
+ mir);
+ // Store the storage liveness for later use so we can restore the state
+ // after a suspension point
storage_liveness_map.insert(block, storage_liveness.clone());
- let mut live_locals = storage_liveness;
-
// Mark locals without storage statements as always having live storage
- live_locals.union(&ignored.0);
+ storage_liveness.union(&ignored.0);
- if !movable {
- // For immovable generators we consider borrowed locals to always be live.
- // This effectively makes those locals use just the storage liveness.
- liveness.outs[block].union(&borrowed_locals.0);
- }
+ // Locals live are live at this point only if they are used across
+ // suspension points (the `liveness` variable)
+ // and their storage is live (the `storage_liveness` variable)
+ storage_liveness.intersect(&liveness.outs[block]);
- // Locals live are live at this point only if they are used across suspension points
- // and their storage is live
- live_locals.intersect(&liveness.outs[block]);
+ let live_locals = storage_liveness;
// Add the locals life at this suspension point to the set of locals which live across
// any suspension points
use rustc::mir::*;
use rustc::mir::visit::*;
use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::layout::LayoutOf;
use rustc::ty::subst::{Subst,Substs};
use std::collections::VecDeque;
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> Option<u64> {
- (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes())
+ tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
}
fn subst_and_normalize<'a, 'tcx: 'a>(
Abi::PlatformIntrinsic => {
assert!(!self.tcx.is_const_fn(def_id));
match &self.tcx.item_name(def_id)[..] {
- "size_of" | "min_align_of" => is_const_fn = Some(def_id),
+ "size_of" | "min_align_of" | "type_id" => is_const_fn = Some(def_id),
name if name.starts_with("simd_shuffle") => {
is_shuffle = true;
kind.name())
.span_label(e.span,
"can only break with a value inside `loop`")
+ .span_suggestion(e.span,
+ &format!("instead, use `break` on its own \
+ without a value inside this `{}` loop",
+ kind.name()),
+ "break".to_string())
.emit();
}
}
field_ref: &ast::Field,
variant: &ty::VariantDef,
) -> Option<Ref> {
- let f = variant.field_named(field_ref.ident.node.name);
+ let f = variant.find_field_named(field_ref.ident.node.name)?;
// We don't really need a sub-span here, but no harm done
let sub_span = self.span_utils.span_for_last_ident(field_ref.ident.span);
filter!(self.span_utils, sub_span, field_ref.ident.span, None);
result.push_str(&val.as_str());
}
result.push('\n');
+ } else if let Some(meta_list) = attr.meta_item_list() {
+ meta_list.into_iter()
+ .filter(|it| it.check_name("include"))
+ .filter_map(|it| it.meta_item_list().map(|l| l.to_owned()))
+ .flat_map(|it| it)
+ .filter(|meta| meta.check_name("contents"))
+ .filter_map(|meta| meta.value_str())
+ .for_each(|val| {
+ result.push_str(&val.as_str());
+ result.push('\n');
+ });
}
}
}
if asm2wasm && config.emit_obj {
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
- binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out);
+ let suffix = ".wasm.map"; // FIXME use target suffix
+ let map = cgcx.output_filenames.path(OutputType::Exe)
+ .with_extension(&suffix[1..]);
+ binaryen_assemble(cgcx, diag_handler, &assembly, &obj_out, &map);
timeline.record("binaryen");
if !config.emit_asm {
fn binaryen_assemble(cgcx: &CodegenContext,
handler: &Handler,
assembly: &Path,
- object: &Path) {
+ object: &Path,
+ map: &Path) {
use rustc_binaryen::{Module, ModuleOptions};
let input = fs::read(&assembly).and_then(|contents| {
let mut options = ModuleOptions::new();
if cgcx.debuginfo != config::NoDebugInfo {
options.debuginfo(true);
+ let map_file_name = map.file_name().unwrap();
+ options.source_map_url(map_file_name.to_str().unwrap());
}
- if cgcx.crate_types.contains(&config::CrateTypeExecutable) {
- options.start("main");
- }
+
options.stack(1024 * 1024);
options.import_memory(cgcx.wasm_import_memory);
let assembled = input.and_then(|input| {
.map_err(|e| io::Error::new(io::ErrorKind::Other, e))
});
let err = assembled.and_then(|binary| {
- fs::write(&object, binary.data())
+ fs::write(&object, binary.data()).and_then(|()| {
+ if cgcx.debuginfo != config::NoDebugInfo {
+ fs::write(map, binary.source_map())
+ } else {
+ Ok(())
+ }
+ })
});
if let Err(e) = err {
handler.err(&format!("failed to run binaryen assembler: {}", e));
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
debuginfo: tcx.sess.opts.debuginfo,
- wasm_import_memory: wasm_import_memory,
+ wasm_import_memory,
assembler_cmd,
};
type TyLayout = TyLayout<'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
- (self.tcx, ty::ParamEnv::empty(traits::Reveal::All))
- .layout_of(ty)
+ self.tcx.layout_of(ty::ParamEnv::empty(traits::Reveal::All).and(ty))
.unwrap_or_else(|e| match e {
LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
_ => bug!("failed to get layout for `{}`: {}", ty, e)
self.cx.align_of(substs.type_at(0)).abi());
Ok(Const::new(llval, tcx.types.usize))
}
+ "type_id" => {
+ let llval = C_u64(self.cx,
+ self.cx.tcx.type_id_hash(substs.type_at(0)));
+ Ok(Const::new(llval, tcx.types.u64))
+ }
_ => span_bug!(span, "{:?} in constant", terminator.kind)
}
} else if let Some((op, is_checked)) = self.is_binop_lang_item(def_id) {
debug!("compare_impl_method(impl_trait_ref={:?})",
impl_trait_ref);
+ let impl_m_span = tcx.sess.codemap().def_span(impl_m_span);
+
if let Err(ErrorReported) = compare_self_type(tcx,
impl_m,
impl_m_span,
check_region_bounds_on_impl_method(tcx,
impl_m_span,
impl_m,
+ trait_m,
&trait_m_generics,
&impl_m_generics,
trait_to_skol_substs)?;
};
let mut diag = struct_span_err!(tcx.sess,
- cause.span,
+ cause.span(&tcx),
E0053,
"method `{}` has an incompatible type for trait",
trait_m.name);
fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
span: Span,
impl_m: &ty::AssociatedItem,
+ trait_m: &ty::AssociatedItem,
trait_generics: &ty::Generics,
impl_generics: &ty::Generics,
trait_to_skol_substs: &Substs<'tcx>)
-> Result<(), ErrorReported> {
+ let span = tcx.sess.codemap().def_span(span);
let trait_params = &trait_generics.regions[..];
let impl_params = &impl_generics.regions[..];
// are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message.
if trait_params.len() != impl_params.len() {
- struct_span_err!(tcx.sess,
- span,
- E0195,
- "lifetime parameters or bounds on method `{}` do not match the \
- trait declaration",
- impl_m.name)
- .span_label(span, "lifetimes do not match trait")
- .emit();
+ let mut err = struct_span_err!(tcx.sess,
+ span,
+ E0195,
+ "lifetime parameters or bounds on method `{}` do not match \
+ the trait declaration",
+ impl_m.name);
+ err.span_label(span, "lifetimes do not match method in trait");
+ if let Some(sp) = tcx.hir.span_if_local(trait_m.def_id) {
+ err.span_label(tcx.sess.codemap().def_span(sp),
+ "lifetimes in impl do not match this method in trait");
+ }
+ err.emit();
return Err(ErrorReported);
}
}).map(|(ref impl_arg, ref trait_arg)| {
(impl_arg.span, Some(trait_arg.span))
})
- .unwrap_or_else(|| (cause.span, tcx.hir.span_if_local(trait_m.def_id)))
+ .unwrap_or_else(|| (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)))
} else {
- (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+ (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
}
}
TypeError::Sorts(ExpectedFound { .. }) => {
{
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
- (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+ (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
}
})
} else {
- (cause.span, tcx.hir.span_if_local(trait_m.def_id))
+ (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id))
}
}
- _ => (cause.span, tcx.hir.span_if_local(trait_m.def_id)),
+ _ => (cause.span(&tcx), tcx.hir.span_if_local(trait_m.def_id)),
}
}
}
fn visit_pat(&mut self, pat: &'tcx Pat) {
+ intravisit::walk_pat(self, pat);
+
+ self.expr_count += 1;
+
if let PatKind::Binding(..) = pat.node {
let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
let ty = self.fcx.tables.borrow().pat_ty(pat);
self.record(ty, Some(scope), None, pat.span);
}
-
- self.expr_count += 1;
-
- intravisit::walk_pat(self, pat);
}
fn visit_expr(&mut self, expr: &'tcx Expr) {
use rustc::ty::fold::TypeFoldable;
use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt};
-use rustc::ty::layout::LayoutOf;
use errors::{DiagnosticBuilder, DiagnosticId};
use require_c_abi_if_variadic;
let span = body.value.span;
if body.is_generator && can_be_generator.is_some() {
- fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)));
+ let yield_ty = fcx.next_ty_var(TypeVariableOrigin::TypeInference(span));
+ fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
+ fcx.yield_ty = Some(yield_ty);
}
GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
let field_infos: Vec<_> = adt.non_enum_variant().fields.iter().map(|field| {
let ty = field.ty(tcx, Substs::identity_for_item(tcx, field.did));
let param_env = tcx.param_env(field.did);
- let layout = (tcx, param_env).layout_of(ty);
+ let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir.span_if_local(field.did).unwrap();
let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false);
for (i, &impl1_def_id) in impls.iter().enumerate() {
for &impl2_def_id in &impls[(i + 1)..] {
- let used_to_be_allowed = self.tcx.infer_ctxt().enter(|infcx| {
- if let Some(overlap) =
- traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
- IntercrateMode::Issue43355)
- {
+ let used_to_be_allowed = traits::overlapping_impls(
+ self.tcx,
+ impl1_def_id,
+ impl2_def_id,
+ IntercrateMode::Issue43355,
+ |overlap| {
self.check_for_common_items_in_impls(
- impl1_def_id, impl2_def_id, overlap, false);
+ impl1_def_id,
+ impl2_def_id,
+ overlap,
+ false,
+ );
false
- } else {
- true
- }
- });
+ },
+ || true,
+ );
if used_to_be_allowed {
- self.tcx.infer_ctxt().enter(|infcx| {
- if let Some(overlap) =
- traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id,
- IntercrateMode::Fixed)
- {
- self.check_for_common_items_in_impls(
- impl1_def_id, impl2_def_id, overlap, true);
- }
- });
+ traits::overlapping_impls(
+ self.tcx,
+ impl1_def_id,
+ impl2_def_id,
+ IntercrateMode::Fixed,
+ |overlap| self.check_for_common_items_in_impls(
+ impl1_def_id,
+ impl2_def_id,
+ overlap,
+ true,
+ ),
+ || (),
+ );
}
}
}
let def_id = cx.tcx.hir.body_owner_def_id(n);
let param_env = cx.tcx.param_env(def_id);
let substs = Substs::identity_for_item(cx.tcx, def_id);
- let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap();
+ let n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap_or_else(|_| {
+ cx.tcx.mk_const(ty::Const {
+ val: ConstVal::Unevaluated(def_id, substs),
+ ty: cx.tcx.types.usize
+ })
+ });
let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
n.to_string()
} else if let ConstVal::Unevaluated(def_id, _) = n.val {
let mut n = cx.tcx.lift(&n).unwrap();
if let ConstVal::Unevaluated(def_id, substs) = n.val {
let param_env = cx.tcx.param_env(def_id);
- n = cx.tcx.const_eval(param_env.and((def_id, substs))).unwrap()
+ if let Ok(new_n) = cx.tcx.const_eval(param_env.and((def_id, substs))) {
+ n = new_n;
+ }
};
let n = if let ConstVal::Integral(ConstInt::Usize(n)) = n.val {
n.to_string()
// 2 for "In Return Types"
var currentTab = 0;
+ var themesWidth = null;
+
function hasClass(elem, className) {
if (elem && className && elem.className) {
var elemClass = elem.className;
sidebar.appendChild(div);
}
}
+ var themeChoices = document.getElementById("theme-choices");
+ if (themeChoices) {
+ if (!themesWidth) {
+ var savedState = themeChoices.style.display;
+ themeChoices.style.display = 'block';
+ themesWidth = themeChoices.offsetWidth + 'px';
+ themeChoices.style.display = savedState;
+ }
+ themeChoices.style.position = "fixed";
+ themeChoices.style.width = themesWidth;
+ themeChoices.style.top = '78px';
+ themeChoices.style.left = '250px';
+ }
document.getElementsByTagName("body")[0].style.marginTop = '45px';
var themePicker = document.getElementById("theme-picker");
if (themePicker) {
themePicker.style.position = "fixed";
+ themePicker.style.top = "50px";
+ themePicker.style.left = "250px";
}
}
var themePicker = document.getElementById("theme-picker");
if (themePicker) {
themePicker.style.position = "absolute";
+ themePicker.style.top = null;
+ themePicker.style.left = null;
+ }
+ var themeChoices = document.getElementById("theme-choices");
+ if (themeChoices) {
+ themeChoices.style.position = 'absolute';
+ themeChoices.style.width = null;
+ themeChoices.style.top = null;
+ themeChoices.style.left = null;
}
}
overflow: auto;
}
-.sidebar .current {
+.sidebar .block > ul > li {
margin-right: -20px;
}
-.content, nav { max-width: 960px; }
+.content, nav {
+ max-width: 960px;
+}
/* Everything else */
-.js-only, .hidden { display: none !important; }
+.js-only, .hidden {
+ display: none !important;
+}
.sidebar img {
margin: 20px auto;
border: none;
}
-.location a:first-child { font-weight: 500; }
+.location a:first-child {
+ font-weight: 500;
+}
.block {
padding: 0;
-ms-user-select: none;
user-select: none;
}
-.line-numbers span { cursor: pointer; }
+.line-numbers span {
+ cursor: pointer;
+}
.docblock-short p {
display: inline;
text-overflow: ellipsis;
margin: 0;
}
-.docblock-short code { white-space: nowrap; }
+.docblock-short code {
+ white-space: nowrap;
+}
.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
border-bottom: 1px solid;
display: inline-block;
}
-#main { position: relative; }
+#main {
+ position: relative;
+}
#main > .since {
top: inherit;
font-family: "Fira Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 0;
}
-.content .item-list li { margin-bottom: 1em; }
+.content .item-list li {
+ margin-bottom: 1em;
+}
.content .multi-column {
-moz-column-count: 5;
display: block;
border-bottom: 1px solid;
border-right: 1px solid;
+ height: 45px;
}
.sidebar-elems {
}
nav.sub {
- margin: 0 auto;
+ width: calc(100% - 32px);
+ float: right;
}
.content {
margin-left: 0px;
}
+ #main {
+ margin-top: 50px;
+ padding: 0;
+ }
+
.content .in-band {
width: 100%;
}
.show-it {
display: block;
+ width: 246px;
+ }
+
+ .show-it > .block.items {
+ margin: 8px 0;
+ }
+
+ .show-it > .block.items > ul {
+ margin: 0;
+ }
+
+ .show-it > .block.items > ul > li {
+ text-align: center;
+ margin: 2px 0;
+ }
+
+ .show-it > .block.items > ul > li > a {
+ font-size: 21px;
}
/* Because of ios, we need to actually have a full height sidebar title so the
@media (max-width: 700px) {
.theme-picker {
- left: 109px;
- top: 7px;
+ left: 10px;
+ top: 54px;
z-index: 1;
}
}
@media (max-width: 700px) {
#theme-picker {
- background: #353535;
+ background: #f0f0f0;
}
}
force_alloc_system = []
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
+wasm_syscall = []
assert!(nan.to_degrees().is_nan());
assert_eq!(inf.to_degrees(), inf);
assert_eq!(neg_inf.to_degrees(), neg_inf);
+ assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703);
}
#[test]
/// The returned slice will **not** contain the trailing nul terminator that this C
/// string has.
///
- /// > **Note**: This method is currently implemented as a 0-cost cast, but
- /// > it is planned to alter its definition in the future to perform the
- /// > length calculation whenever this method is called.
+ /// > **Note**: This method is currently implemented as a constant-time
+ /// > cast, but it is planned to alter its definition in the future to
+ /// > perform the length calculation whenever this method is called.
///
/// # Examples
///
/// it will return an error with details of where UTF-8 validation failed.
///
/// > **Note**: This method is currently implemented to check for validity
- /// > after a 0-cost cast, but it is planned to alter its definition in the
- /// > future to perform the length calculation in addition to the UTF-8
- /// > check whenever this method is called.
+ /// > after a constant-time cast, but it is planned to alter its definition
+ /// > in the future to perform the length calculation in addition to the
+ /// > UTF-8 check whenever this method is called.
///
/// [`&str`]: ../primitive.str.html
///
/// with the result.
///
/// > **Note**: This method is currently implemented to check for validity
- /// > after a 0-cost cast, but it is planned to alter its definition in the
- /// > future to perform the length calculation in addition to the UTF-8
- /// > check whenever this method is called.
+ /// > after a constant-time cast, but it is planned to alter its definition
+ /// > in the future to perform the length calculation in addition to the
+ /// > UTF-8 check whenever this method is called.
///
/// [`Cow`]: ../borrow/enum.Cow.html
/// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
self.inner.file_attr().map(Metadata)
}
- /// Creates a new independently owned handle to the underlying file.
- ///
- /// The returned `File` is a reference to the same state that this object
- /// references. Both handles will read and write with the same cursor
- /// position.
+ /// Create a new `File` instance that shares the same underlying file handle
+ /// as the existing `File` instance. Reads, writes, and seeks will affect
+ /// both `File` instances simultaneously.
///
/// # Examples
///
+ /// Create two handles for a file named `foo.txt`:
+ ///
/// ```no_run
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = File::open("foo.txt")?;
- /// let file_copy = f.try_clone()?;
+ /// let mut file = File::open("foo.txt")?;
+ /// let file_copy = file.try_clone()?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ ///
+ /// Assuming there’s a file named `foo.txt` with contents `abcdef\n`, create
+ /// two handles, seek one of them, and read the remaining bytes from the
+ /// other handle:
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::io::SeekFrom;
+ /// use std::io::prelude::*;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ /// let mut file_copy = file.try_clone()?;
+ ///
+ /// file.seek(SeekFrom::Start(3))?;
+ ///
+ /// let mut contents = vec![];
+ /// file_copy.read_to_end(&mut contents)?;
+ /// assert_eq!(contents, b"def\n");
/// # Ok(())
/// # }
/// ```
self.0.accessed().map(FromInner::from_inner)
}
- /// Returns the creation time listed in the this metadata.
+ /// Returns the creation time listed in this metadata.
///
/// The returned value corresponds to the `birthtime` field of `stat` on
/// Unix platforms and the `ftCreationTime` field on Windows platforms.
#![feature(core_intrinsics)]
#![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)]
+#![feature(external_doc)]
#![feature(fs_read_write)]
#![feature(fixed_size_array)]
#![feature(float_from_str_radix)]
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Raw OS-specific types for the current platform/architecture
-
-#![stable(feature = "raw_os", since = "1.1.0")]
-
-use fmt;
-
-#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "s390x")),
- all(target_os = "android", any(target_arch = "aarch64",
- target_arch = "arm")),
- all(target_os = "l4re", target_arch = "x86_64"),
- all(target_os = "openbsd", target_arch = "aarch64"),
- all(target_os = "fuchsia", target_arch = "aarch64")))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
-#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
- target_arch = "arm",
- target_arch = "powerpc",
- target_arch = "powerpc64",
- target_arch = "s390x")),
- all(target_os = "android", any(target_arch = "aarch64",
- target_arch = "arm")),
- all(target_os = "l4re", target_arch = "x86_64"),
- all(target_os = "openbsd", target_arch = "aarch64"),
- all(target_os = "fuchsia", target_arch = "aarch64"))))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
-#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
-
-/// Type used to construct void pointers for use with C.
-///
-/// This type is only useful as a pointer target. Do not use it as a
-/// return type for FFI functions which have the `void` return type in
-/// C. Use the unit type `()` or omit the return type instead.
-// NB: For LLVM to recognize the void pointer type and by extension
-// functions like malloc(), we need to have it represented as i8* in
-// LLVM bitcode. The enum used here ensures this and prevents misuse
-// of the "raw" type by only having private variants.. We need two
-// variants, because the compiler complains about the repr attribute
-// otherwise.
-#[repr(u8)]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub enum c_void {
- #[unstable(feature = "c_void_variant", reason = "should not have to exist",
- issue = "0")]
- #[doc(hidden)] __variant1,
- #[unstable(feature = "c_void_variant", reason = "should not have to exist",
- issue = "0")]
- #[doc(hidden)] __variant2,
-}
-
-#[stable(feature = "std_debug", since = "1.16.0")]
-impl fmt::Debug for c_void {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.pad("c_void")
- }
-}
-
-#[cfg(test)]
-#[allow(unused_imports)]
-mod tests {
- use any::TypeId;
- use libc;
- use mem;
-
- macro_rules! ok {
- ($($t:ident)*) => {$(
- assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
- "{} is wrong", stringify!($t));
- )*}
- }
-
- #[test]
- fn same() {
- use os::raw;
- ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
- c_longlong c_ulonglong c_float c_double);
- }
-}
--- /dev/null
+Equivalent to C's `char` type.
+
+[C's `char` type] is completely unlike [Rust's `char` type]; while Rust's type represents a unicode scalar value, C's `char` type is just an ordinary integer. This type will always be either [`i8`] or [`u8`], as the type is defined as being one byte long.
+
+C chars are most commonly used to make C strings. Unlike Rust, where the length of a string is included alongside the string, C strings mark the end of a string with the character `'\0'`. See [`CStr`] for more information.
+
+[C's `char` type]: https://en.wikipedia.org/wiki/C_data_types#Basic_types
+[Rust's `char` type]: ../../primitive.char.html
+[`CStr`]: ../../ffi/struct.CStr.html
+[`i8`]: ../../primitive.i8.html
+[`u8`]: ../../primitive.u8.html
--- /dev/null
+Equivalent to C's `double` type.
+
+This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard.
+
+[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[`float`]: type.c_float.html
+[`f64`]: ../../primitive.f64.html
--- /dev/null
+Equivalent to C's `float` type.
+
+This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all.
+
+[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[`f32`]: ../../primitive.f32.html
--- /dev/null
+Equivalent to C's `signed int` (`int`) type.
+
+This type will almost always be [`i32`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer that is at least the size of a [`short`]; some systems define it as an [`i16`], for example.
+
+[`short`]: type.c_short.html
+[`i32`]: ../../primitive.i32.html
+[`i16`]: ../../primitive.i16.html
--- /dev/null
+Equivalent to C's `signed long` (`long`) type.
+
+This type will always be [`i32`] or [`i64`]. Most notably, many Linux-based systems assume an `i64`, but Windows assumes `i32`. The C standard technically only requires that this type be a signed integer that is at least 32 bits and at least the size of an [`int`], although in practice, no system would have a `long` that is neither an `i32` nor `i64`.
+
+[`int`]: type.c_int.html
+[`i32`]: ../../primitive.i32.html
+[`i64`]: ../../primitive.i64.html
--- /dev/null
+Equivalent to C's `signed long long` (`long long`) type.
+
+This type will almost always be [`i64`], but may differ on some systems. The C standard technically only requires that this type be a signed integer that is at least 64 bits and at least the size of a [`long`], although in practice, no system would have a `long long` that is not an `i64`, as most systems do not have a standardised [`i128`] type.
+
+[`long`]: type.c_int.html
+[`i64`]: ../../primitive.i64.html
+[`i128`]: ../../primitive.i128.html
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Platform-specific types, as defined by C.
+//!
+//! Code that interacts via FFI will almost certainly be using the
+//! base types provided by C, which aren't nearly as nicely defined
+//! as Rust's primitive types. This module provides types which will
+//! match those defined by C, so that code that interacts with C will
+//! refer to the correct types.
+
+#![stable(feature = "raw_os", since = "1.1.0")]
+
+use fmt;
+
+#[doc(include = "os/raw/char.md")]
+#[cfg(any(all(target_os = "linux", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x")),
+ all(target_os = "android", any(target_arch = "aarch64",
+ target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
+ all(target_os = "openbsd", target_arch = "aarch64"),
+ all(target_os = "fuchsia", target_arch = "aarch64")))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
+#[doc(include = "os/raw/char.md")]
+#[cfg(not(any(all(target_os = "linux", any(target_arch = "aarch64",
+ target_arch = "arm",
+ target_arch = "powerpc",
+ target_arch = "powerpc64",
+ target_arch = "s390x")),
+ all(target_os = "android", any(target_arch = "aarch64",
+ target_arch = "arm")),
+ all(target_os = "l4re", target_arch = "x86_64"),
+ all(target_os = "openbsd", target_arch = "aarch64"),
+ all(target_os = "fuchsia", target_arch = "aarch64"))))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
+#[doc(include = "os/raw/schar.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
+#[doc(include = "os/raw/uchar.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;
+#[doc(include = "os/raw/short.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_short = i16;
+#[doc(include = "os/raw/ushort.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ushort = u16;
+#[doc(include = "os/raw/int.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_int = i32;
+#[doc(include = "os/raw/uint.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uint = u32;
+#[doc(include = "os/raw/long.md")]
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i32;
+#[doc(include = "os/raw/ulong.md")]
+#[cfg(any(target_pointer_width = "32", windows))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u32;
+#[doc(include = "os/raw/long.md")]
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_long = i64;
+#[doc(include = "os/raw/ulong.md")]
+#[cfg(all(target_pointer_width = "64", not(windows)))]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulong = u64;
+#[doc(include = "os/raw/longlong.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_longlong = i64;
+#[doc(include = "os/raw/ulonglong.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_ulonglong = u64;
+#[doc(include = "os/raw/float.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_float = f32;
+#[doc(include = "os/raw/double.md")]
+#[stable(feature = "raw_os", since = "1.1.0")] pub type c_double = f64;
+
+/// Equivalent to C's `void` type when used as a [pointer].
+///
+/// In essence, `*const c_void` is equivalent to C's `const void*`
+/// and `*mut c_void` is equivalent to C's `void*`. That said, this is
+/// *not* the same as C's `void` return type, which is Rust's `()` type.
+///
+/// Ideally, this type would be equivalent to [`!`], but currently it may
+/// be more ideal to use `c_void` for FFI purposes.
+///
+/// [`!`]: ../../primitive.never.html
+/// [pointer]: ../../primitive.pointer.html
+// NB: For LLVM to recognize the void pointer type and by extension
+// functions like malloc(), we need to have it represented as i8* in
+// LLVM bitcode. The enum used here ensures this and prevents misuse
+// of the "raw" type by only having private variants.. We need two
+// variants, because the compiler complains about the repr attribute
+// otherwise.
+#[repr(u8)]
+#[stable(feature = "raw_os", since = "1.1.0")]
+pub enum c_void {
+ #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+ issue = "0")]
+ #[doc(hidden)] __variant1,
+ #[unstable(feature = "c_void_variant", reason = "should not have to exist",
+ issue = "0")]
+ #[doc(hidden)] __variant2,
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for c_void {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("c_void")
+ }
+}
+
+#[cfg(test)]
+#[allow(unused_imports)]
+mod tests {
+ use any::TypeId;
+ use libc;
+ use mem;
+
+ macro_rules! ok {
+ ($($t:ident)*) => {$(
+ assert!(TypeId::of::<libc::$t>() == TypeId::of::<raw::$t>(),
+ "{} is wrong", stringify!($t));
+ )*}
+ }
+
+ #[test]
+ fn same() {
+ use os::raw;
+ ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong
+ c_longlong c_ulonglong c_float c_double);
+ }
+}
--- /dev/null
+Equivalent to C's `signed char` type.
+
+This type will always be [`i8`], but is included for completeness. It is defined as being a signed integer the same size as a C [`char`].
+
+[`char`]: type.c_char.html
+[`i8`]: ../../primitive.i8.html
--- /dev/null
+Equivalent to C's `signed short` (`short`) type.
+
+This type will almost always be [`i16`], but may differ on some esoteric systems. The C standard technically only requires that this type be a signed integer with at least 16 bits; some systems may define it as `i32`, for example.
+
+[`char`]: type.c_char.html
+[`i16`]: ../../primitive.i16.html
--- /dev/null
+Equivalent to C's `unsigned char` type.
+
+This type will always be [`u8`], but is included for completeness. It is defined as being an unsigned integer the same size as a C [`char`].
+
+[`char`]: type.c_char.html
+[`u8`]: ../../primitive.u8.html
--- /dev/null
+Equivalent to C's `unsigned int` type.
+
+This type will almost always be [`u32`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as an [`int`]; some systems define it as a [`u16`], for example.
+
+[`int`]: type.c_int.html
+[`u32`]: ../../primitive.u32.html
+[`u16`]: ../../primitive.u16.html
--- /dev/null
+Equivalent to C's `unsigned long` type.
+
+This type will always be [`u32`] or [`u64`]. Most notably, many Linux-based systems assume an `u64`, but Windows assumes `u32`. The C standard technically only requires that this type be an unsigned integer with the size of a [`long`], although in practice, no system would have a `ulong` that is neither a `u32` nor `u64`.
+
+[`long`]: type.c_long.html
+[`u32`]: ../../primitive.u32.html
+[`u64`]: ../../primitive.u64.html
--- /dev/null
+Equivalent to C's `unsigned long long` type.
+
+This type will almost always be [`u64`], but may differ on some systems. The C standard technically only requires that this type be an unsigned integer with the size of a [`long long`], although in practice, no system would have a `long long` that is not a `u64`, as most systems do not have a standardised [`u128`] type.
+
+[`long long`]: type.c_longlong.html
+[`u64`]: ../../primitive.u64.html
+[`u128`]: ../../primitive.u128.html
--- /dev/null
+Equivalent to C's `unsigned short` type.
+
+This type will almost always be [`u16`], but may differ on some esoteric systems. The C standard technically only requires that this type be an unsigned integer with the same size as a [`short`].
+
+[`short`]: type.c_short.html
+[`u16`]: ../../primitive.u16.html
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
#[unstable(feature = "ptr_internals", issue = "0")]
impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
-#[stable(feature = "nonnull", since = "1.24.0")]
+#[stable(feature = "nonnull", since = "1.25.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for NonNull<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: ?Sized> UnwindSafe for Mutex<T> {}
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- pub unsafe fn current() -> Option<usize> {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> {
None
}
- pub unsafe fn init() -> Option<usize> {
+ pub unsafe fn init() -> Option<Guard> {
None
}
}
}
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
use sys_common::thread_info;
- // This is initialized in init() and only read from after
- static mut PAGE_SIZE: usize = 0;
-
#[cfg(any(target_os = "linux", target_os = "android"))]
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
#[repr(C)]
_data: *mut libc::c_void) {
use sys_common::util::report_overflow;
- let guard = thread_info::stack_guard().unwrap_or(0);
+ let guard = thread_info::stack_guard().unwrap_or(0..0);
let addr = siginfo_si_addr(info);
// If the faulting address is within the guard page, then we print a
// message saying so and abort.
- if guard != 0 && guard - PAGE_SIZE <= addr && addr < guard {
+ if guard.start <= addr && addr < guard.end {
report_overflow();
rtabort!("stack overflow");
} else {
static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
pub unsafe fn init() {
- PAGE_SIZE = ::sys::os::page_size();
-
let mut action: sigaction = mem::zeroed();
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
action.sa_sigaction = signal_handler as sighandler_t;
not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ use ops::Range;
+ pub type Guard = Range<usize>;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
use libc;
use libc::mmap;
use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
+ use ops::Range;
use sys::os;
- #[cfg(any(target_os = "macos",
- target_os = "bitrig",
- target_os = "openbsd",
- target_os = "solaris"))]
+ // This is initialized in init() and only read from after
+ static mut PAGE_SIZE: usize = 0;
+
+ pub type Guard = Range<usize>;
+
+ #[cfg(target_os = "solaris")]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let mut current_stack: libc::stack_t = ::mem::zeroed();
+ assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
+ Some(current_stack.ss_sp)
+ }
+
+ #[cfg(target_os = "macos")]
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
- current().map(|s| s as *mut libc::c_void)
+ let stackaddr = libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
+ libc::pthread_get_stacksize_np(libc::pthread_self());
+ Some(stackaddr as *mut libc::c_void)
+ }
+
+ #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
+ unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
+ let mut current_stack: libc::stack_t = ::mem::zeroed();
+ assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
+ &mut current_stack), 0);
+
+ let extra = if cfg!(target_os = "bitrig") {3} else {1} * PAGE_SIZE;
+ let stackaddr = if libc::pthread_main_np() == 1 {
+ // main thread
+ current_stack.ss_sp as usize - current_stack.ss_size + extra
+ } else {
+ // new thread
+ current_stack.ss_sp as usize - current_stack.ss_size
+ };
+ Some(stackaddr as *mut libc::c_void)
}
#[cfg(any(target_os = "android", target_os = "freebsd",
ret
}
- pub unsafe fn init() -> Option<usize> {
- let psize = os::page_size();
+ pub unsafe fn init() -> Option<Guard> {
+ PAGE_SIZE = os::page_size();
+
let mut stackaddr = get_stack_start()?;
// Ensure stackaddr is page aligned! A parent process might
// stackaddr < stackaddr + stacksize, so if stackaddr is not
// page-aligned, calculate the fix such that stackaddr <
// new_page_aligned_stackaddr < stackaddr + stacksize
- let remainder = (stackaddr as usize) % psize;
+ let remainder = (stackaddr as usize) % PAGE_SIZE;
if remainder != 0 {
- stackaddr = ((stackaddr as usize) + psize - remainder)
+ stackaddr = ((stackaddr as usize) + PAGE_SIZE - remainder)
as *mut libc::c_void;
}
// Instead, we'll just note where we expect rlimit to start
// faulting, so our handler can report "stack overflow", and
// trust that the kernel's own stack guard will work.
- Some(stackaddr as usize)
+ let stackaddr = stackaddr as usize;
+ Some(stackaddr - PAGE_SIZE..stackaddr)
} else {
// Reallocate the last page of the stack.
// This ensures SIGBUS will be raised on
// stack overflow.
- let result = mmap(stackaddr, psize, PROT_NONE,
+ let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
if result != stackaddr || result == MAP_FAILED {
panic!("failed to allocate a guard page");
}
+ let guardaddr = stackaddr as usize;
let offset = if cfg!(target_os = "freebsd") {
2
} else {
1
};
- Some(stackaddr as usize + offset * psize)
+ Some(guardaddr..guardaddr + offset * PAGE_SIZE)
}
}
- #[cfg(target_os = "solaris")]
- pub unsafe fn current() -> Option<usize> {
- let mut current_stack: libc::stack_t = ::mem::zeroed();
- assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
- Some(current_stack.ss_sp as usize)
- }
-
- #[cfg(target_os = "macos")]
- pub unsafe fn current() -> Option<usize> {
- Some(libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize -
- libc::pthread_get_stacksize_np(libc::pthread_self()))
- }
-
- #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
- pub unsafe fn current() -> Option<usize> {
- let mut current_stack: libc::stack_t = ::mem::zeroed();
- assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
- &mut current_stack), 0);
-
- let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
- Some(if libc::pthread_main_np() == 1 {
- // main thread
- current_stack.ss_sp as usize - current_stack.ss_size + extra
- } else {
- // new thread
- current_stack.ss_sp as usize - current_stack.ss_size
- })
+ #[cfg(any(target_os = "macos",
+ target_os = "bitrig",
+ target_os = "openbsd",
+ target_os = "solaris"))]
+ pub unsafe fn current() -> Option<Guard> {
+ let stackaddr = get_stack_start()? as usize;
+ Some(stackaddr - PAGE_SIZE..stackaddr)
}
#[cfg(any(target_os = "android", target_os = "freebsd",
target_os = "linux", target_os = "netbsd", target_os = "l4re"))]
- pub unsafe fn current() -> Option<usize> {
+ pub unsafe fn current() -> Option<Guard> {
let mut ret = None;
let mut attr: libc::pthread_attr_t = ::mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
&mut size), 0);
+ let stackaddr = stackaddr as usize;
ret = if cfg!(target_os = "freebsd") {
- Some(stackaddr as usize - guardsize)
+ // FIXME does freebsd really fault *below* the guard addr?
+ let guardaddr = stackaddr - guardsize;
+ Some(guardaddr - PAGE_SIZE..guardaddr)
} else if cfg!(target_os = "netbsd") {
- Some(stackaddr as usize)
+ Some(stackaddr - guardsize..stackaddr)
+ } else if cfg!(all(target_os = "linux", target_env = "gnu")) {
+ // glibc used to include the guard area within the stack, as noted in the BUGS
+ // section of `man pthread_attr_getguardsize`. This has been corrected starting
+ // with glibc 2.27, and in some distro backports, so the guard is now placed at the
+ // end (below) the stack. There's no easy way for us to know which we have at
+ // runtime, so we'll just match any fault in the range right above or below the
+ // stack base to call that fault a stack overflow.
+ Some(stackaddr - guardsize..stackaddr + guardsize)
} else {
- Some(stackaddr as usize + guardsize)
+ Some(stackaddr..stackaddr + guardsize)
};
}
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
use ffi::OsString;
use marker::PhantomData;
-use mem;
use vec;
+use sys::ArgsSysCall;
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
// On wasm these should always be null, so there's nothing for us to do here
}
pub fn args() -> Args {
- // When the runtime debugging is enabled we'll link to some extra runtime
- // functions to actually implement this. These are for now just implemented
- // in a node.js script but they're off by default as they're sort of weird
- // in a web-wasm world.
- if !super::DEBUG {
- return Args {
- iter: Vec::new().into_iter(),
- _dont_send_or_sync_me: PhantomData,
- }
- }
-
- // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These
- // are just meant for debugging and should not be relied on.
- extern {
- fn rust_wasm_args_count() -> usize;
- fn rust_wasm_args_arg_size(a: usize) -> usize;
- fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8);
- }
-
- unsafe {
- let cnt = rust_wasm_args_count();
- let mut v = Vec::with_capacity(cnt);
- for i in 0..cnt {
- let n = rust_wasm_args_arg_size(i);
- let mut data = vec![0; n];
- rust_wasm_args_arg_fill(i, data.as_mut_ptr());
- v.push(mem::transmute::<Vec<u8>, OsString>(data));
- }
- Args {
- iter: v.into_iter(),
- _dont_send_or_sync_me: PhantomData,
- }
+ let v = ArgsSysCall::perform();
+ Args {
+ iter: v.into_iter(),
+ _dont_send_or_sync_me: PhantomData,
}
}
use io;
use os::raw::c_char;
-
-// Right now the wasm backend doesn't even have the ability to print to the
-// console by default. Wasm can't import anything from JS! (you have to
-// explicitly provide it).
-//
-// Sometimes that's a real bummer, though, so this flag can be set to `true` to
-// enable calling various shims defined in `src/etc/wasm32-shim.js` which should
-// help receive debug output and see what's going on. In general this flag
-// currently controls "will we call out to our own defined shims in node.js",
-// and this flag should always be `false` for release builds.
-const DEBUG: bool = false;
+use ptr;
+use sys::os_str::Buf;
+use sys_common::{AsInner, FromInner};
+use ffi::{OsString, OsStr};
+use time::Duration;
pub mod args;
#[cfg(feature = "backtrace")]
}
pub unsafe fn abort_internal() -> ! {
- ::intrinsics::abort();
+ ExitSysCall::perform(1)
}
// We don't have randomness yet, but I totally used a random number generator to
pub fn hashmap_random_keys() -> (u64, u64) {
(1, 2)
}
+
+// Implement a minimal set of system calls to enable basic IO
+pub enum SysCallIndex {
+ Read = 0,
+ Write = 1,
+ Exit = 2,
+ Args = 3,
+ GetEnv = 4,
+ SetEnv = 5,
+ Time = 6,
+}
+
+#[repr(C)]
+pub struct ReadSysCall {
+ fd: usize,
+ ptr: *mut u8,
+ len: usize,
+ result: usize,
+}
+
+impl ReadSysCall {
+ pub fn perform(fd: usize, buffer: &mut [u8]) -> usize {
+ let mut call_record = ReadSysCall {
+ fd,
+ len: buffer.len(),
+ ptr: buffer.as_mut_ptr(),
+ result: 0
+ };
+ if unsafe { syscall(SysCallIndex::Read, &mut call_record) } {
+ call_record.result
+ } else {
+ 0
+ }
+ }
+}
+
+#[repr(C)]
+pub struct WriteSysCall {
+ fd: usize,
+ ptr: *const u8,
+ len: usize,
+}
+
+impl WriteSysCall {
+ pub fn perform(fd: usize, buffer: &[u8]) {
+ let mut call_record = WriteSysCall {
+ fd,
+ len: buffer.len(),
+ ptr: buffer.as_ptr()
+ };
+ unsafe { syscall(SysCallIndex::Write, &mut call_record); }
+ }
+}
+
+#[repr(C)]
+pub struct ExitSysCall {
+ code: usize,
+}
+
+impl ExitSysCall {
+ pub fn perform(code: usize) -> ! {
+ let mut call_record = ExitSysCall {
+ code
+ };
+ unsafe {
+ syscall(SysCallIndex::Exit, &mut call_record);
+ ::intrinsics::abort();
+ }
+ }
+}
+
+fn receive_buffer<E, F: FnMut(&mut [u8]) -> Result<usize, E>>(estimate: usize, mut f: F)
+ -> Result<Vec<u8>, E>
+{
+ let mut buffer = vec![0; estimate];
+ loop {
+ let result = f(&mut buffer)?;
+ if result <= buffer.len() {
+ buffer.truncate(result);
+ break;
+ }
+ buffer.resize(result, 0);
+ }
+ Ok(buffer)
+}
+
+#[repr(C)]
+pub struct ArgsSysCall {
+ ptr: *mut u8,
+ len: usize,
+ result: usize
+}
+
+impl ArgsSysCall {
+ pub fn perform() -> Vec<OsString> {
+ receive_buffer(1024, |buffer| -> Result<usize, !> {
+ let mut call_record = ArgsSysCall {
+ len: buffer.len(),
+ ptr: buffer.as_mut_ptr(),
+ result: 0
+ };
+ if unsafe { syscall(SysCallIndex::Args, &mut call_record) } {
+ Ok(call_record.result)
+ } else {
+ Ok(0)
+ }
+ })
+ .unwrap()
+ .split(|b| *b == 0)
+ .map(|s| FromInner::from_inner(Buf { inner: s.to_owned() }))
+ .collect()
+ }
+}
+
+#[repr(C)]
+pub struct GetEnvSysCall {
+ key_ptr: *const u8,
+ key_len: usize,
+ value_ptr: *mut u8,
+ value_len: usize,
+ result: usize
+}
+
+impl GetEnvSysCall {
+ pub fn perform(key: &OsStr) -> Option<OsString> {
+ let key_buf = &AsInner::as_inner(key).inner;
+ receive_buffer(64, |buffer| {
+ let mut call_record = GetEnvSysCall {
+ key_len: key_buf.len(),
+ key_ptr: key_buf.as_ptr(),
+ value_len: buffer.len(),
+ value_ptr: buffer.as_mut_ptr(),
+ result: !0usize
+ };
+ if unsafe { syscall(SysCallIndex::GetEnv, &mut call_record) } {
+ if call_record.result == !0usize {
+ Err(())
+ } else {
+ Ok(call_record.result)
+ }
+ } else {
+ Err(())
+ }
+ }).ok().map(|s| {
+ FromInner::from_inner(Buf { inner: s })
+ })
+ }
+}
+
+#[repr(C)]
+pub struct SetEnvSysCall {
+ key_ptr: *const u8,
+ key_len: usize,
+ value_ptr: *const u8,
+ value_len: usize
+}
+
+impl SetEnvSysCall {
+ pub fn perform(key: &OsStr, value: Option<&OsStr>) {
+ let key_buf = &AsInner::as_inner(key).inner;
+ let value_buf = value.map(|v| &AsInner::as_inner(v).inner);
+ let mut call_record = SetEnvSysCall {
+ key_len: key_buf.len(),
+ key_ptr: key_buf.as_ptr(),
+ value_len: value_buf.map(|v| v.len()).unwrap_or(!0usize),
+ value_ptr: value_buf.map(|v| v.as_ptr()).unwrap_or(ptr::null())
+ };
+ unsafe { syscall(SysCallIndex::SetEnv, &mut call_record); }
+ }
+}
+
+pub enum TimeClock {
+ Monotonic = 0,
+ System = 1,
+}
+
+#[repr(C)]
+pub struct TimeSysCall {
+ clock: usize,
+ secs_hi: usize,
+ secs_lo: usize,
+ nanos: usize
+}
+
+impl TimeSysCall {
+ pub fn perform(clock: TimeClock) -> Duration {
+ let mut call_record = TimeSysCall {
+ clock: clock as usize,
+ secs_hi: 0,
+ secs_lo: 0,
+ nanos: 0
+ };
+ if unsafe { syscall(SysCallIndex::Time, &mut call_record) } {
+ Duration::new(
+ ((call_record.secs_hi as u64) << 32) | (call_record.secs_lo as u64),
+ call_record.nanos as u32
+ )
+ } else {
+ panic!("Time system call is not implemented by WebAssembly host");
+ }
+ }
+}
+
+unsafe fn syscall<T>(index: SysCallIndex, data: &mut T) -> bool {
+ #[cfg(feature = "wasm_syscall")]
+ extern {
+ #[no_mangle]
+ fn rust_wasm_syscall(index: usize, data: *mut Void) -> usize;
+ }
+
+ #[cfg(not(feature = "wasm_syscall"))]
+ unsafe fn rust_wasm_syscall(_index: usize, _data: *mut Void) -> usize { 0 }
+
+ rust_wasm_syscall(index as usize, data as *mut T as *mut Void) != 0
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use core::intrinsics;
-
use error::Error as StdError;
use ffi::{OsString, OsStr};
use fmt;
use io;
-use mem;
use path::{self, PathBuf};
use str;
-use sys::{unsupported, Void};
+use sys::{unsupported, Void, ExitSysCall, GetEnvSysCall, SetEnvSysCall};
pub fn errno() -> i32 {
0
}
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
- // If we're debugging the runtime then we actually probe node.js to ask for
- // the value of environment variables to help provide inputs to programs.
- // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are
- // intended for debugging only, you should not rely on them.
- if !super::DEBUG {
- return Ok(None)
- }
-
- extern {
- fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize;
- fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8);
- }
- unsafe {
- let k: &[u8] = mem::transmute(k);
- let n = rust_wasm_getenv_len(k.as_ptr(), k.len());
- if n == -1 {
- return Ok(None)
- }
- let mut data = vec![0; n as usize];
- rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr());
- Ok(Some(mem::transmute(data)))
- }
+ Ok(GetEnvSysCall::perform(k))
}
-pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
- unsupported()
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+ Ok(SetEnvSysCall::perform(k, Some(v)))
}
-pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
- unsupported()
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+ Ok(SetEnvSysCall::perform(k, None))
}
pub fn temp_dir() -> PathBuf {
}
pub fn exit(_code: i32) -> ! {
- unsafe { intrinsics::abort() }
+ ExitSysCall::perform(_code as isize as usize)
}
pub fn getpid() -> u32 {
// except according to those terms.
use io;
-use sys::{Void, unsupported};
+use sys::{ReadSysCall, WriteSysCall};
-pub struct Stdin(Void);
+pub struct Stdin;
pub struct Stdout;
pub struct Stderr;
impl Stdin {
pub fn new() -> io::Result<Stdin> {
- unsupported()
+ Ok(Stdin)
}
- pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
+ pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+ Ok(ReadSysCall::perform(0, data))
}
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- // If runtime debugging is enabled at compile time we'll invoke some
- // runtime functions that are defined in our src/etc/wasm32-shim.js
- // debugging script. Note that this ffi function call is intended
- // *purely* for debugging only and should not be relied upon.
- if !super::DEBUG {
- return unsupported()
- }
- extern {
- fn rust_wasm_write_stdout(data: *const u8, len: usize);
- }
- unsafe {
- rust_wasm_write_stdout(data.as_ptr(), data.len())
- }
+ WriteSysCall::perform(1, data);
Ok(data.len())
}
}
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- // See comments in stdout for what's going on here.
- if !super::DEBUG {
- return unsupported()
- }
- extern {
- fn rust_wasm_write_stderr(data: *const u8, len: usize);
- }
- unsafe {
- rust_wasm_write_stderr(data.as_ptr(), data.len())
- }
+ WriteSysCall::perform(2, data);
Ok(data.len())
}
}
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use fmt;
use time::Duration;
+use sys::{TimeSysCall, TimeClock};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant;
+pub struct Instant(Duration);
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct SystemTime;
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
-pub const UNIX_EPOCH: SystemTime = SystemTime;
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
impl Instant {
pub fn now() -> Instant {
- panic!("not supported on web assembly");
+ Instant(TimeSysCall::perform(TimeClock::Monotonic))
}
- pub fn sub_instant(&self, _other: &Instant) -> Duration {
- panic!("can't sub yet");
+ pub fn sub_instant(&self, other: &Instant) -> Duration {
+ self.0 - other.0
}
- pub fn add_duration(&self, _other: &Duration) -> Instant {
- panic!("can't add yet");
+ pub fn add_duration(&self, other: &Duration) -> Instant {
+ Instant(self.0 + *other)
}
- pub fn sub_duration(&self, _other: &Duration) -> Instant {
- panic!("can't sub yet");
+ pub fn sub_duration(&self, other: &Duration) -> Instant {
+ Instant(self.0 - *other)
}
}
impl SystemTime {
pub fn now() -> SystemTime {
- panic!("not supported on web assembly");
+ SystemTime(TimeSysCall::perform(TimeClock::System))
}
- pub fn sub_time(&self, _other: &SystemTime)
+ pub fn sub_time(&self, other: &SystemTime)
-> Result<Duration, Duration> {
- panic!()
- }
-
- pub fn add_duration(&self, _other: &Duration) -> SystemTime {
- panic!()
+ self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
- pub fn sub_duration(&self, _other: &Duration) -> SystemTime {
- panic!()
+ pub fn add_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime(self.0 + *other)
}
-}
-impl fmt::Debug for SystemTime {
- fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
- panic!()
+ pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime(self.0 - *other)
}
}
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- pub unsafe fn current() -> Option<usize> { None }
- pub unsafe fn init() -> Option<usize> { None }
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
}
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
use cell::RefCell;
+use sys::thread::guard::Guard;
use thread::Thread;
struct ThreadInfo {
- stack_guard: Option<usize>,
+ stack_guard: Option<Guard>,
thread: Thread,
}
ThreadInfo::with(|info| info.thread.clone())
}
-pub fn stack_guard() -> Option<usize> {
- ThreadInfo::with(|info| info.stack_guard).and_then(|o| o)
+pub fn stack_guard() -> Option<Guard> {
+ ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
}
-pub fn set(stack_guard: Option<usize>, thread: Thread) {
+pub fn set(stack_guard: Option<Guard>, thread: Thread) {
THREAD_INFO.with(|c| assert!(c.borrow().is_none()));
THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{
stack_guard,
pub pats: Vec<P<Pat>>,
pub guard: Option<P<Expr>>,
pub body: P<Expr>,
- pub beginning_vert: Option<Span>, // For RFC 1925 feature gate
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
}
}
- /// Given a `Span`, try to get a shorter span ending just after the first
- /// occurrence of `char` `c`.
+ /// Given a `Span`, get a new `Span` covering the first token and all its trailing whitespace or
+ /// the original `Span`.
+ ///
+ /// If `sp` points to `"let mut x"`, then a span pointing at `"let "` will be returned.
+ pub fn span_until_non_whitespace(&self, sp: Span) -> Span {
+ if let Ok(snippet) = self.span_to_snippet(sp) {
+ let mut offset = 0;
+ // get the bytes width of all the non-whitespace characters
+ for c in snippet.chars().take_while(|c| !c.is_whitespace()) {
+ offset += c.len_utf8();
+ }
+ // get the bytes width of all the whitespace characters after that
+ for c in snippet[offset..].chars().take_while(|c| c.is_whitespace()) {
+ offset += c.len_utf8();
+ }
+ if offset > 1 {
+ return sp.with_hi(BytePos(sp.lo().0 + offset as u32));
+ }
+ }
+ sp
+ }
+
+ /// Given a `Span`, try to get a shorter span ending just after the first occurrence of `char`
+ /// `c`.
pub fn span_through_char(&self, sp: Span, c: char) -> Span {
if let Ok(snippet) = self.span_to_snippet(sp) {
if let Some(offset) = snippet.find(c) {
pats,
guard: None,
body: expr,
- beginning_vert: None,
}
}
// allow `#[must_use]` on functions and comparison operators (RFC 1940)
(active, fn_must_use, "1.21.0", Some(43302)),
- // allow '|' at beginning of match arms (RFC 1925)
- (active, match_beginning_vert, "1.21.0", Some(44101)),
-
// Future-proofing enums/structs with #[non_exhaustive] attribute (RFC 2008)
(active, non_exhaustive, "1.22.0", Some(44109)),
// In-band lifetime bindings (e.g. `fn foo(x: &'a u8) -> &'a u8`)
(active, in_band_lifetimes, "1.23.0", Some(44524)),
- // Nested groups in `use` (RFC 2128)
- (active, use_nested_groups, "1.23.0", Some(44494)),
-
// generic associated types (RFC 1598)
(active, generic_associated_types, "1.23.0", Some(44265)),
(accepted, abi_sysv64, "1.24.0", Some(36167)),
// Allows `repr(align(16))` struct attribute (RFC 1358)
(accepted, repr_align, "1.24.0", Some(33626)),
+ // allow '|' at beginning of match arms (RFC 1925)
+ (accepted, match_beginning_vert, "1.25.0", Some(44101)),
+ // Nested groups in `use` (RFC 2128)
+ (accepted, use_nested_groups, "1.25.0", Some(44494)),
);
// If you change this, please modify src/doc/unstable-book as well. You must
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
+ ("rustc_serialize_exclude_null", Normal, Gated(Stability::Unstable,
+ "rustc_attrs",
+ "the `#[rustc_serialize_exclude_null]` attribute \
+ is an internal-only feature",
+ cfg_fn!(rustc_attrs))),
("rustc_synthetic", Whitelisted, Gated(Stability::Unstable,
"rustc_attrs",
"this attribute \
}
fn visit_arm(&mut self, arm: &'a ast::Arm) {
- if let Some(span) = arm.beginning_vert {
- gate_feature_post!(&self, match_beginning_vert,
- span,
- "Use of a '|' at the beginning of a match arm is experimental")
- }
visit::walk_arm(self, arm)
}
visit::walk_path(self, path);
}
- fn visit_use_tree(&mut self, use_tree: &'a ast::UseTree, id: NodeId, nested: bool) {
- if nested {
- match use_tree.kind {
- ast::UseTreeKind::Simple(_) => {
- if use_tree.prefix.segments.len() != 1 {
- gate_feature_post!(&self, use_nested_groups, use_tree.span,
- "paths in `use` groups are experimental");
- }
- }
- ast::UseTreeKind::Glob => {
- gate_feature_post!(&self, use_nested_groups, use_tree.span,
- "glob imports in `use` groups are experimental");
- }
- ast::UseTreeKind::Nested(_) => {
- gate_feature_post!(&self, use_nested_groups, use_tree.span,
- "nested groups in `use` are experimental");
- }
- }
- }
-
- visit::walk_use_tree(self, use_tree, id);
- }
-
fn visit_vis(&mut self, vis: &'a ast::Visibility) {
if let ast::Visibility::Crate(span, ast::CrateSugar::JustCrate) = *vis {
gate_feature_post!(&self, crate_visibility_modifier, span,
fold_attrs(attrs.into(), fld).into()
}
-pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body, beginning_vert}: Arm,
+pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm,
fld: &mut T) -> Arm {
Arm {
attrs: fold_attrs(attrs, fld),
pats: pats.move_map(|x| fld.fold_pat(x)),
guard: guard.map(|x| fld.fold_expr(x)),
body: fld.fold_expr(body),
- beginning_vert,
}
}
registry: Option<Registry>,
cm: Rc<CodeMapper + 'static>,
pretty: bool,
+ /// Whether "approximate suggestions" are enabled in the config
+ approximate_suggestions: bool,
}
impl JsonEmitter {
pub fn stderr(registry: Option<Registry>,
code_map: Rc<CodeMap>,
- pretty: bool) -> JsonEmitter {
+ pretty: bool,
+ approximate_suggestions: bool) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::stderr()),
registry,
cm: code_map,
pretty,
+ approximate_suggestions,
}
}
pub fn basic(pretty: bool) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
- JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)), pretty)
+ JsonEmitter::stderr(None, Rc::new(CodeMap::new(file_path_mapping)),
+ pretty, false)
}
pub fn new(dst: Box<Write + Send>,
registry: Option<Registry>,
code_map: Rc<CodeMap>,
- pretty: bool) -> JsonEmitter {
+ pretty: bool,
+ approximate_suggestions: bool) -> JsonEmitter {
JsonEmitter {
dst,
registry,
cm: code_map,
pretty,
+ approximate_suggestions,
}
}
}
}
#[derive(RustcEncodable)]
+#[allow(unused_attributes)]
struct DiagnosticSpan {
file_name: String,
byte_start: u32,
/// If we are suggesting a replacement, this will contain text
/// that should be sliced in atop this span.
suggested_replacement: Option<String>,
+ /// If the suggestion is approximate
+ #[rustc_serialize_exclude_null]
+ suggestion_approximate: Option<bool>,
/// Macro invocations that created the code at this span, if any.
expansion: Option<Box<DiagnosticSpanMacroExpansion>>,
}
impl DiagnosticSpan {
fn from_span_label(span: SpanLabel,
- suggestion: Option<&String>,
+ suggestion: Option<(&String, bool)>,
je: &JsonEmitter)
-> DiagnosticSpan {
Self::from_span_etc(span.span,
fn from_span_etc(span: Span,
is_primary: bool,
label: Option<String>,
- suggestion: Option<&String>,
+ suggestion: Option<(&String, bool)>,
je: &JsonEmitter)
-> DiagnosticSpan {
// obtain the full backtrace from the `macro_backtrace`
fn from_span_full(span: Span,
is_primary: bool,
label: Option<String>,
- suggestion: Option<&String>,
+ suggestion: Option<(&String, bool)>,
mut backtrace: vec::IntoIter<MacroBacktrace>,
je: &JsonEmitter)
-> DiagnosticSpan {
def_site_span,
})
});
+
+ let suggestion_approximate = if je.approximate_suggestions {
+ suggestion.map(|x| x.1)
+ } else {
+ None
+ };
+
DiagnosticSpan {
file_name: start.file.name.to_string(),
byte_start: span.lo().0 - start.file.start_pos.0,
column_end: end.col.0 + 1,
is_primary,
text: DiagnosticSpanLine::from_span(span, je),
- suggested_replacement: suggestion.cloned(),
+ suggested_replacement: suggestion.map(|x| x.0.clone()),
+ suggestion_approximate,
expansion: backtrace_step,
label,
}
suggestion.substitutions
.iter()
.flat_map(|substitution| {
- substitution.parts.iter().map(move |suggestion| {
+ substitution.parts.iter().map(move |suggestion_inner| {
let span_label = SpanLabel {
- span: suggestion.span,
+ span: suggestion_inner.span,
is_primary: true,
label: None,
};
DiagnosticSpan::from_span_label(span_label,
- Some(&suggestion.snippet),
+ Some((&suggestion_inner.snippet,
+ suggestion.approximate)),
je)
})
})
#![feature(match_default_bindings)]
#![feature(i128_type)]
#![feature(const_atomic_usize_new)]
+#![feature(rustc_attrs)]
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
self.err_span(self.mk_sp(from_pos, to_pos), m)
}
+ /// Pushes a character to a message string for error reporting
+ fn push_escaped_char_for_msg(m: &mut String, c: char) {
+ match c {
+ '\u{20}'...'\u{7e}' => {
+ // Don't escape \, ' or " for user-facing messages
+ m.push(c);
+ }
+ _ => {
+ for c in c.escape_default() {
+ m.push(c);
+ }
+ }
+ }
+ }
+
/// Report a lexical error spanning [`from_pos`, `to_pos`), appending an
/// escaped character to the error message
fn fatal_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) -> FatalError {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.fatal_span_(from_pos, to_pos, &m[..])
}
fn struct_fatal_span_char(&self,
-> DiagnosticBuilder<'a> {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
}
fn err_span_char(&self, from_pos: BytePos, to_pos: BytePos, m: &str, c: char) {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.err_span_(from_pos, to_pos, &m[..]);
}
fn struct_err_span_char(&self,
-> DiagnosticBuilder<'a> {
let mut m = m.to_string();
m.push_str(": ");
- for c in c.escape_default() {
- m.push(c)
- }
+ Self::push_escaped_char_for_msg(&mut m, c);
self.sess.span_diagnostic.struct_span_err(self.mk_sp(from_pos, to_pos), &m[..])
}
})
}
+ fn expected_ident_found(&self) -> DiagnosticBuilder<'a> {
+ let mut err = self.struct_span_err(self.span,
+ &format!("expected identifier, found {}",
+ self.this_token_descr()));
+ if let Some(token_descr) = self.token_descr() {
+ err.span_label(self.span, format!("expected identifier, found {}", token_descr));
+ } else {
+ err.span_label(self.span, "expected identifier");
+ }
+ err
+ }
+
pub fn parse_ident(&mut self) -> PResult<'a, ast::Ident> {
self.parse_ident_common(true)
}
match self.token {
token::Ident(i) => {
if self.token.is_reserved_ident() {
- let mut err = self.struct_span_err(self.span,
- &format!("expected identifier, found {}",
- self.this_token_descr()));
- if let Some(token_descr) = self.token_descr() {
- err.span_label(self.span, format!("expected identifier, found {}",
- token_descr));
- } else {
- err.span_label(self.span, "expected identifier");
- }
+ let mut err = self.expected_ident_found();
if recover {
err.emit();
} else {
Err(if self.prev_token_kind == PrevTokenKind::DocComment {
self.span_fatal_err(self.prev_span, Error::UselessDocComment)
} else {
- let mut err = self.fatal(&format!("expected identifier, found `{}`",
- self.this_token_to_string()));
- if let Some(token_descr) = self.token_descr() {
- err.span_label(self.span, format!("expected identifier, found {}",
- token_descr));
- } else {
- err.span_label(self.span, "expected identifier");
- }
+ let mut err = self.expected_ident_found();
if self.token == token::Underscore {
err.note("`_` is a wildcard pattern, not an identifier");
}
let attrs = self.parse_outer_attributes()?;
// Allow a '|' before the pats (RFC 1925)
- let beginning_vert = if self.eat(&token::BinOp(token::Or)) {
- Some(self.prev_span)
- } else {
- None
- };
+ self.eat(&token::BinOp(token::Or));
let pats = self.parse_pats()?;
let guard = if self.eat_keyword(keywords::If) {
Some(self.parse_expr()?)
pats,
guard,
body: expr,
- beginning_vert,
})
}
keywords::Unsafe.name(),
keywords::While.name(),
keywords::Yield.name(),
+ keywords::Static.name(),
].contains(&ident.name)
}
}
}
+ // If there are no outputs, the inline assembly is executed just for its side effects,
+ // so ensure that it is volatile
+ if outputs.is_empty() {
+ volatile = true;
+ }
+
MacEager::expr(P(ast::Expr {
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::InlineAsm(P(ast::InlineAsm {
Struct(_, ref fields) => {
let emit_struct_field = cx.ident_of("emit_struct_field");
let mut stmts = Vec::new();
- for (i, &FieldInfo { name, ref self_, span, .. }) in fields.iter().enumerate() {
+ for (i, &FieldInfo { name, ref self_, span, attrs, .. }) in fields.iter().enumerate() {
let name = match name {
Some(id) => id.name,
None => Symbol::intern(&format!("_field{}", i)),
} else {
cx.expr(span, ExprKind::Ret(Some(call)))
};
- stmts.push(cx.stmt_expr(call));
+
+ // This exists for https://github.com/rust-lang/rust/pull/47540
+ //
+ // If we decide to stabilize that flag this can be removed
+ let expr = if attrs.iter().any(|a| a.check_name("rustc_serialize_exclude_null")) {
+ let is_some = cx.ident_of("is_some");
+ let condition = cx.expr_method_call(span, self_.clone(), is_some, vec![]);
+ cx.expr_if(span, condition, call, None)
+ } else {
+ call
+ };
+ let stmt = cx.stmt_expr(expr);
+ stmts.push(stmt);
}
// unit structs have no fields and need to return Ok()
/// Return a `Span` that would enclose both `self` and `end`.
pub fn to(self, end: Span) -> Span {
- let span = self.data();
- let end = end.data();
+ let span_data = self.data();
+ let end_data = end.data();
+ // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
+ // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
+ // have an incomplete span than a completely nonsensical one.
+ if span_data.ctxt != end_data.ctxt {
+ if span_data.ctxt == SyntaxContext::empty() {
+ return end;
+ } else if end_data.ctxt == SyntaxContext::empty() {
+ return self;
+ }
+ // both span fall within a macro
+ // FIXME(estebank) check if it is the *same* macro
+ }
Span::new(
- cmp::min(span.lo, end.lo),
- cmp::max(span.hi, end.hi),
- // FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
- if span.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
+ cmp::min(span_data.lo, end_data.lo),
+ cmp::max(span_data.hi, end_data.hi),
+ if span_data.ctxt == SyntaxContext::empty() { end_data.ctxt } else { span_data.ctxt },
)
}
use std::thread;
use std::time::{Instant, Duration};
use std::borrow::Cow;
+use std::process;
const TEST_WARN_TIMEOUT_S: u64 = 60;
const QUIET_MODE_MAX_COLUMN: usize = 100; // insert a '\n' after 100 tests in quiet mode
pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Options) {
let mut opts = match parse_opts(args) {
Some(Ok(o)) => o,
- Some(Err(msg)) => panic!("{:?}", msg),
+ Some(Err(msg)) => {
+ eprintln!("error: {}", msg);
+ process::exit(101);
+ },
None => return,
};
+
opts.options = options;
if opts.list {
if let Err(e) = list_tests_console(&opts, tests) {
- panic!("io error when listing tests: {:?}", e);
+ eprintln!("error: io error when listing tests: {:?}", e);
+ process::exit(101);
}
} else {
match run_tests_console(&opts, tests) {
Ok(true) => {}
- Ok(false) => std::process::exit(101),
- Err(e) => panic!("io error when running tests: {:?}", e),
+ Ok(false) => process::exit(101),
+ Err(e) => {
+ eprintln!("error: io error when listing tests: {:?}", e);
+ process::exit(101);
+ },
}
}
}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -O
+
+// ignore-asmjs
+
+#![feature(asm)]
+#![crate_type = "lib"]
+
+// Check that inline assembly expressions without any outputs
+// are marked as having side effects / being volatile
+
+// CHECK-LABEL: @assembly
+#[no_mangle]
+pub fn assembly() {
+ unsafe { asm!("") }
+// CHECK: tail call void asm sideeffect "", {{.*}}
+}
// ignore-wasm
// ignore-emscripten
// ignore-windows
-// no-system-llvm
+// min-system-llvm-version 5.0
// compile-flags: -C no-prepopulate-passes
#![crate_type = "lib"]
trait Trait {
fn bar<'a,'b:'a>(x: &'a str, y: &'b str);
+ //~^ NOTE lifetimes in impl do not match this method in trait
}
struct Foo;
impl Trait for Foo {
fn bar<'a,'b>(x: &'a str, y: &'b str) { //~ ERROR E0195
- //~^ lifetimes do not match trait
+ //~^ NOTE lifetimes do not match method in trait
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(use_nested_groups)]
#![allow(unused_imports)]
mod foo {}
: [u32; (i8::MAX as i8 + 1u8) as usize]
//~^ ERROR mismatched types
//~| expected i8, found u8
- //~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
+ //~| ERROR cannot add `u8` to `i8`
= [0; (i8::MAX as usize) + 1];
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::any::TypeId;
+
+struct A;
+
+fn main() {
+ const A_ID: TypeId = TypeId::of::<A>();
+ //~^ ERROR `std::any::TypeId::of` is not yet stable as a const fn
+}
trait NoLifetime {
fn get<'p, T : Test<'p>>(&self) -> T;
+ //~^ NOTE lifetimes in impl do not match this method in trait
}
trait Test<'p> {
impl<'a> NoLifetime for Foo<'a> {
fn get<'p, T : Test<'a>>(&self) -> T {
-//~^ ERROR E0195
-//~| lifetimes do not match trait
+ //~^ ERROR E0195
+ //~| NOTE lifetimes do not match method in trait
return *self as T;
}
}
--- /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.
+
+static TAB: [&mut [u8]; 0] = [];
+
+pub unsafe fn test() {
+ TAB[0].iter_mut(); //~ ERROR cannot borrow data mutably in a `&` reference [E0389]
+}
+
+pub fn main() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+#![feature(core_intrinsics)]
+
+use std::intrinsics;
+
+struct Foo {
+ bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
+ //~^ ERROR unsupported cyclic reference between types/traits detected
+ x: usize,
+}
+
+fn main() {}
fn main() {
write(&buf);
- buf[0]=2; //[mir]~ ERROR E0594
+ buf[0]=2; //[ast]~ ERROR E0389
+ //[mir]~^ ERROR E0594
}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the 'static bound from the Copy impl is respected. Regression test for #29149.
+
+#![feature(nll)]
+
+#[derive(Clone)] struct Foo<'a>(&'a u32);
+impl Copy for Foo<'static> {}
+
+fn main() {
+ let s = 2;
+ let a = Foo(&s); //~ ERROR `s` does not live long enough [E0597]
+ drop(a);
+ drop(a);
+}
let mut x = 22;
let wrapper = Wrap { w: &mut x };
x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506]
- //[mir]~^ ERROR cannot assign to `x` because it is borrowed [E0506]
- //[mir]~^^ ERROR cannot use `x` because it was mutably borrowed [E0503]
+ //[mir]~^ ERROR cannot use `x` because it was mutably borrowed [E0503]
*wrapper.w += 1;
}
+++ /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.
-
-// Check that explicit region bounds are allowed on the various
-// nominal types (but not on other types) and that they are type
-// checked.
-
-struct Inv<'a> { // invariant w/r/t 'a
- x: &'a mut &'a isize
-}
-
-pub trait Foo<'a, 't> {
- fn no_bound<'b>(self, b: Inv<'b>);
- fn has_bound<'b:'a>(self, b: Inv<'b>);
- fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
- fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
- fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
-}
-
-impl<'a, 't> Foo<'a, 't> for &'a isize {
- fn no_bound<'b:'a>(self, b: Inv<'b>) {
- //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
- }
-
- fn has_bound<'b>(self, b: Inv<'b>) {
- //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
- }
-
- fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
- //~^ ERROR method not compatible with trait
- //
- // Note: This is a terrible error message. It is caused
- // because, in the trait, 'b is early bound, and in the impl,
- // 'c is early bound, so -- after substitution -- the
- // lifetimes themselves look isomorphic. We fail because the
- // lifetimes that appear in the types are in the wrong
- // order. This should really be fixed by keeping more
- // information about the lifetime declarations in the trait so
- // that we can compare better to the impl, even in cross-crate
- // cases.
- }
-
- fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
- }
-
- fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
- //~^ ERROR E0276
- }
-}
-
-fn main() { }
fn main() {
<i32 as Add<u32>>::add(1, 2);
- //~^ ERROR `i32: std::ops::Add<u32>` is not satisfied
+ //~^ ERROR cannot add `u32` to `i32`
<i32 as Add<i32>>::add(1u32, 2);
//~^ ERROR mismatched types
<i32 as Add<i32>>::add(1, 2u32);
// Validate(Acquire, [_1: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId(0/1:9 ~ validate_5[317d]::main[0]::{{closure}}[0]), BrAnon(0)) mut i32]);
// StorageLive(_3);
// StorageLive(_4);
+// StorageLive(_5);
// Validate(Suspend(ReScope(Node(ItemLocalId(9)))), [(*_2): i32]);
-// _4 = &ReErased mut (*_2);
-// Validate(Acquire, [(*_4): i32/ReScope(Node(ItemLocalId(9)))]);
-// _3 = move _4 as *mut i32 (Misc);
+// _5 = &ReErased mut (*_2);
+// Validate(Acquire, [(*_5): i32/ReScope(Node(ItemLocalId(9)))]);
+// _4 = move _5 as *mut i32 (Misc);
+// _3 = move _4;
// EndRegion(ReScope(Node(ItemLocalId(9))));
// StorageDead(_4);
+// StorageDead(_5);
// Validate(Release, [_0: bool, _3: *mut i32]);
// _0 = const write_42(move _3) -> bb1;
// }
fn main() {
// these literals are just silly.
''';
- //~^ ERROR: character constant must be escaped: \'
+ //~^ ERROR: character constant must be escaped: '
// note that this is a literal "\n" byte
'
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+\ //~ ERROR: unknown start of token: \
--- /dev/null
+-include ../tools.mk
+
+all:
+ cp foo.rs $(TMPDIR)/foo.rs
+ mkdir $(TMPDIR)/foo
+ $(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo 2>&1 \
+ | $(CGREP) -e "the generated executable for the input file \".*foo\.rs\" conflicts with the existing directory \".*foo\""
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {}
all:
cp foo.rs $(TMPDIR)/foo
- $(RUSTC) $(TMPDIR)/foo 2>&1 \
+ $(RUSTC) $(TMPDIR)/foo -o $(TMPDIR)/foo 2>&1 \
| $(CGREP) -e "the input file \".*foo\" would be overwritten by the generated executable"
+ cp bar.rs $(TMPDIR)/bar.rlib
+ $(RUSTC) $(TMPDIR)/bar.rlib -o $(TMPDIR)/bar.rlib 2>&1 \
+ | $(CGREP) -e "the input file \".*bar.rlib\" would be overwritten by the generated executable"
$(RUSTC) foo.rs 2>&1 && $(RUSTC) -Z ls $(TMPDIR)/foo 2>&1
cp foo.rs $(TMPDIR)/foo.rs
$(RUSTC) $(TMPDIR)/foo.rs -o $(TMPDIR)/foo.rs 2>&1 \
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// 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.
//
static EXTERN_FOO: u8;
fn extern_foo(a: u8, b: i32) -> String;
}
+
+struct Rls699 {
+ f: u32,
+}
+
+fn new(f: u32) -> Rls699 {
+ Rls699 { fs }
+}
--- /dev/null
+Extra docs for this struct.
#![feature(box_syntax)]
#![feature(rustc_private)]
#![feature(associated_type_defaults)]
+#![feature(external_doc)]
extern crate graphviz;
// A simple rust project
trait Foo {
type Bar = FrameBuffer;
}
+
+#[doc(include="extra-docs.md")]
+struct StructWithDocs;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(core_intrinsics)]
+#![feature(const_type_id)]
+
+use std::any::TypeId;
+
+struct A;
+
+static ID_ISIZE: TypeId = TypeId::of::<isize>();
+
+pub fn main() {
+ assert_eq!(ID_ISIZE, TypeId::of::<isize>());
+
+ // sanity test of TypeId
+ const T: (TypeId, TypeId, TypeId) = (TypeId::of::<usize>(),
+ TypeId::of::<&'static str>(),
+ TypeId::of::<A>());
+ let (d, e, f) = (TypeId::of::<usize>(), TypeId::of::<&'static str>(),
+ TypeId::of::<A>());
+
+ assert!(T.0 != T.1);
+ assert!(T.0 != T.2);
+ assert!(T.1 != T.2);
+
+ assert_eq!(T.0, d);
+ assert_eq!(T.1, e);
+ assert_eq!(T.2, f);
+
+ // Check fn pointer against collisions
+ const F: (TypeId, TypeId) = (TypeId::of::<fn(fn(A) -> A) -> A>(),
+ TypeId::of::<fn(fn() -> A, A) -> A>());
+
+ assert!(F.0 != F.1);
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+fn main() {
+ unsafe {
+ static move || {
+ // Tests that the generator transformation finds out that `a` is not live
+ // during the yield expression. Type checking will also compute liveness
+ // and it should also find out that `a` is not live.
+ // The compiler will panic if the generator transformation finds that
+ // `a` is live and type checking finds it dead.
+ let a = {
+ yield ();
+ 4i32
+ };
+ &a;
+ };
+ }
+}
--- /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.
+
+// Regression test for issue #47139:
+//
+// Coherence was encountering an (unnecessary) overflow trying to
+// decide if the two impls of dummy overlap.
+//
+// The overflow went something like:
+//
+// - `&'a ?T: Insertable` ?
+// - let ?T = Option<?U> ?
+// - `Option<?U>: Insertable` ?
+// - `Option<&'a ?U>: Insertable` ?
+// - `&'a ?U: Insertable` ?
+//
+// While somewhere in the middle, a projection would occur, which
+// broke cycle detection.
+//
+// It turned out that this cycle was being kicked off due to some
+// extended diagnostic attempts in coherence, so removing those
+// sidestepped the issue for now.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+ type Values;
+
+ fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+ where
+ T: Insertable,
+ T::Values: Default,
+{
+ type Values = T::Values;
+
+ fn values(self) -> Self::Values {
+ self.map(Insertable::values).unwrap_or_default()
+ }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+ where
+ Option<&'a T>: Insertable,
+{
+ type Values = <Option<&'a T> as Insertable>::Values;
+
+ fn values(self) -> Self::Values {
+ self.as_ref().values()
+ }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+ type Values = Self;
+
+ fn values(self) -> Self::Values {
+ self
+ }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<'a, U> Dummy for Foo<&'a U>
+ where &'a U: Insertable
+{
+}
+
+impl<T> Dummy for T
+ where T: Unimplemented
+{ }
+
+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.
+
+// Regression test for issue #47139:
+//
+// Same as issue-47139-1.rs, but the impls of dummy are in the
+// opposite order. This influenced the way that coherence ran and in
+// some cases caused the overflow to occur when it wouldn't otherwise.
+// In an effort to make the regr test more robust, I am including both
+// orderings.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+ type Values;
+
+ fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+ where
+ T: Insertable,
+ T::Values: Default,
+{
+ type Values = T::Values;
+
+ fn values(self) -> Self::Values {
+ self.map(Insertable::values).unwrap_or_default()
+ }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+ where
+ Option<&'a T>: Insertable,
+{
+ type Values = <Option<&'a T> as Insertable>::Values;
+
+ fn values(self) -> Self::Values {
+ self.as_ref().values()
+ }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+ type Values = Self;
+
+ fn values(self) -> Self::Values {
+ self
+ }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<T> Dummy for T
+ where T: Unimplemented
+{ }
+
+impl<'a, U> Dummy for Foo<&'a U>
+ where &'a U: Insertable
+{
+}
+
+fn main() {
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(use_nested_groups)]
#![allow(unused_import)]
use {{}, {}};
--- /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 automatic coercions from &mut T to *mut T
+// allow borrows of T to expire immediately - essentially, that
+// they work identically to 'foo as *mut T'
+#![feature(nll)]
+
+struct SelfReference {
+ self_reference: *mut SelfReference,
+}
+
+impl SelfReference {
+ fn set_self_ref(&mut self) {
+ self.self_reference = self;
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+#![feature(nll)]
+
+static mut x: &'static u32 = &0;
+
+fn foo() {
+ unsafe { x = &1; }
+}
+
+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.
+
+enum Foo {
+ A,
+ B,
+ C,
+ D,
+ E,
+}
+use Foo::*;
+
+fn main() {
+ for foo in &[A, B, C, D, E] {
+ match *foo {
+ | A => println!("A"),
+ | B | C if 1 < 2 => println!("BC!"),
+ | _ => {},
+ }
+ }
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(nll)]
+
+pub struct DescriptorSet<'a> {
+ pub slots: Vec<AttachInfo<'a, Resources>>
+}
+
+pub trait ResourcesTrait<'r>: Sized {
+ type DescriptorSet: 'r;
+}
+
+pub struct Resources;
+
+impl<'a> ResourcesTrait<'a> for Resources {
+ type DescriptorSet = DescriptorSet<'a>;
+}
+
+pub enum AttachInfo<'a, R: ResourcesTrait<'a>> {
+ NextDescriptorSet(Box<R::DescriptorSet>)
+}
+
+fn main() {
+ let _x = DescriptorSet {slots: Vec::new()};
+}
// ignore-emscripten no processes
// ignore-musl FIXME #31506
// ignore-pretty
-// no-system-llvm
+// min-system-llvm-version 5.0
// compile-flags: -C lto
// no-prefer-dynamic
// ignore-cloudabi no processes
// ignore-emscripten no processes
// ignore-musl FIXME #31506
-// no-system-llvm
+// min-system-llvm-version 5.0
use std::mem;
use std::process::Command;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(use_nested_groups)]
-
mod a {
pub enum B {}
--- /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.
+
+// Just check if we don't get an ICE for the _S type.
+
+#![feature(const_size_of)]
+
+use std::cell::Cell;
+use std::mem;
+
+pub struct S {
+ s: Cell<usize>
+}
+
+pub type _S = [usize; 0 - (mem::size_of::<S>() != 4) as usize];
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This should not ICE
+pub fn test() {
+ macro_rules! foo {
+ () => ()
+ }
+}
note: the lifetime 'a as defined on the impl at 17:1...
--> $DIR/associated-const-impl-wrong-lifetime.rs:17:1
|
-17 | / impl<'a> Foo for &'a () {
-18 | | const NAME: &'a str = "unit";
-19 | | //~^ ERROR mismatched types [E0308]
-20 | | }
- | |_^
+17 | impl<'a> Foo for &'a () {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
= note: ...does not necessarily outlive the static lifetime
error: aborting due to previous error
--- /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.
+
+// Check that explicit region bounds are allowed on the various
+// nominal types (but not on other types) and that they are type
+// checked.
+
+struct Inv<'a> { // invariant w/r/t 'a
+ x: &'a mut &'a isize
+}
+
+pub trait Foo<'a, 't> {
+ fn no_bound<'b>(self, b: Inv<'b>);
+ fn has_bound<'b:'a>(self, b: Inv<'b>);
+ fn wrong_bound1<'b,'c,'d:'a+'b>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+ fn okay_bound<'b,'c,'d:'a+'b+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>);
+ fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+}
+
+impl<'a, 't> Foo<'a, 't> for &'a isize {
+ fn no_bound<'b:'a>(self, b: Inv<'b>) {
+ //~^ ERROR lifetime parameters or bounds on method `no_bound` do not match
+ }
+
+ fn has_bound<'b>(self, b: Inv<'b>) {
+ //~^ ERROR lifetime parameters or bounds on method `has_bound` do not match
+ }
+
+ fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ //~^ ERROR method not compatible with trait
+ //
+ // Note: This is a terrible error message. It is caused
+ // because, in the trait, 'b is early bound, and in the impl,
+ // 'c is early bound, so -- after substitution -- the
+ // lifetimes themselves look isomorphic. We fail because the
+ // lifetimes that appear in the types are in the wrong
+ // order. This should really be fixed by keeping more
+ // information about the lifetime declarations in the trait so
+ // that we can compare better to the impl, even in cross-crate
+ // cases.
+ }
+
+ fn okay_bound<'b,'c,'e:'b+'c>(self, b: Inv<'b>, c: Inv<'c>, e: Inv<'e>) {
+ }
+
+ fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+ //~^ ERROR E0276
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0195]: lifetime parameters or bounds on method `no_bound` do not match the trait declaration
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:28:5
+ |
+20 | fn no_bound<'b>(self, b: Inv<'b>);
+ | ---------------------------------- lifetimes in impl do not match this method in trait
+...
+28 | fn no_bound<'b:'a>(self, b: Inv<'b>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0195]: lifetime parameters or bounds on method `has_bound` do not match the trait declaration
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:32:5
+ |
+21 | fn has_bound<'b:'a>(self, b: Inv<'b>);
+ | -------------------------------------- lifetimes in impl do not match this method in trait
+...
+32 | fn has_bound<'b>(self, b: Inv<'b>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait
+
+error[E0308]: method not compatible with trait
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+ |
+36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+ |
+ = note: expected type `fn(&'a isize, Inv<'c>, Inv<'c>, Inv<'d>)`
+ found type `fn(&'a isize, Inv<'_>, Inv<'c>, Inv<'d>)`
+note: the lifetime 'c as defined on the method body at 36:5...
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+ |
+36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...does not necessarily outlive the lifetime 'c as defined on the method body at 36:5
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:36:5
+ |
+36 | fn wrong_bound1<'b,'c,'d:'a+'c>(self, b: Inv<'b>, c: Inv<'c>, d: Inv<'d>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0276]: impl has stricter requirements than trait
+ --> $DIR/regions-bound-missing-bound-in-impl.rs:53:5
+ |
+24 | fn another_bound<'x: 'a>(self, x: Inv<'x>, y: Inv<'t>);
+ | ------------------------------------------------------- definition of `another_bound` from trait
+...
+53 | fn another_bound<'x: 't>(self, x: Inv<'x>, y: Inv<'t>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `'x: 't`
+
+error: aborting due to 4 previous errors
+
note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
--> $DIR/expect-region-supply-region.rs:42:1
|
-42 | / fn expect_bound_supply_named<'x>() {
-43 | | let mut f: Option<&u32> = None;
-44 | |
-45 | | // Here we give a type annotation that `x` should be free. We get
-... |
-54 | | });
-55 | | }
- | |_^
+42 | fn expect_bound_supply_named<'x>() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/expect-region-supply-region.rs:47:33
note: the lifetime 'x as defined on the function body at 42:1...
--> $DIR/expect-region-supply-region.rs:42:1
|
-42 | / fn expect_bound_supply_named<'x>() {
-43 | | let mut f: Option<&u32> = None;
-44 | |
-45 | | // Here we give a type annotation that `x` should be free. We get
-... |
-54 | | });
-55 | | }
- | |_^
+42 | fn expect_bound_supply_named<'x>() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
--> $DIR/expect-region-supply-region.rs:47:29
|
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#[allow(dead_code)]
-enum Foo {
- A,
- B,
- C,
- D,
- E,
-}
-use Foo::*;
-
-fn main() {
- let x = Foo::A;
- match x {
- | A => println!("A"),
- //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
- | B | C => println!("BC!"),
- //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
- | _ => {},
- //~^ ERROR: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
- };
- match x {
- A | B | C => println!("ABC!"),
- _ => {},
- };
-}
-
+++ /dev/null
-error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
- --> $DIR/feature-gate-match_beginning_vert.rs:24:9
- |
-24 | | A => println!("A"),
- | ^
- |
- = help: add #![feature(match_beginning_vert)] to the crate attributes to enable
-
-error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
- --> $DIR/feature-gate-match_beginning_vert.rs:26:9
- |
-26 | | B | C => println!("BC!"),
- | ^
- |
- = help: add #![feature(match_beginning_vert)] to the crate attributes to enable
-
-error[E0658]: Use of a '|' at the beginning of a match arm is experimental (see issue #44101)
- --> $DIR/feature-gate-match_beginning_vert.rs:28:9
- |
-28 | | _ => {},
- | ^
- |
- = help: add #![feature(match_beginning_vert)] to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(unused_imports, dead_code)]
-
-mod a {
- pub enum B {}
- pub enum C {}
-
- pub mod d {
- pub enum E {}
- pub enum F {}
-
- pub mod g {
- pub enum H {}
- }
- }
-}
-
-use a::{B, d::{*, g::H}}; //~ ERROR glob imports in `use` groups are experimental
- //~^ ERROR nested groups in `use` are experimental
- //~^^ ERROR paths in `use` groups are experimental
-
-fn main() {}
+++ /dev/null
-error[E0658]: nested groups in `use` are experimental (see issue #44494)
- --> $DIR/feature-gate-use_nested_groups.rs:27:12
- |
-27 | use a::{B, d::{*, g::H}}; //~ ERROR glob imports in `use` groups are experimental
- | ^^^^^^^^^^^^
- |
- = help: add #![feature(use_nested_groups)] to the crate attributes to enable
-
-error[E0658]: glob imports in `use` groups are experimental (see issue #44494)
- --> $DIR/feature-gate-use_nested_groups.rs:27:16
- |
-27 | use a::{B, d::{*, g::H}}; //~ ERROR glob imports in `use` groups are experimental
- | ^
- |
- = help: add #![feature(use_nested_groups)] to the crate attributes to enable
-
-error[E0658]: paths in `use` groups are experimental (see issue #44494)
- --> $DIR/feature-gate-use_nested_groups.rs:27:19
- |
-27 | use a::{B, d::{*, g::H}}; //~ ERROR glob imports in `use` groups are experimental
- | ^^^^
- |
- = help: add #![feature(use_nested_groups)] to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-error[E0626]: borrow may still be in use when generator yields (Mir)
- --> $DIR/generator-with-nll.rs:20:17
- |
-20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
- | ^^^^^^^^^
-21 | //~^ borrow may still be in use when generator yields (Mir)
-22 | yield ();
- | -------- possible yield occurs here
-
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/generator-with-nll.rs:19:23
|
22 | yield ();
| -------- possible yield occurs here
+error[E0626]: borrow may still be in use when generator yields (Mir)
+ --> $DIR/generator-with-nll.rs:20:17
+ |
+20 | let b = &mut true; //~ ERROR borrow may still be in use when generator yields (Ast)
+ | ^^^^^^^^^
+21 | //~^ borrow may still be in use when generator yields (Mir)
+22 | yield ();
+ | -------- possible yield occurs here
+
error: aborting due to 3 previous errors
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators)]
+
+enum Test { A(i32), B, }
+
+fn main() { }
+
+fn fun(test: Test) {
+ move || {
+ if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
+ yield ();
+ }
+ };
+}
--- /dev/null
+error[E0626]: borrow may still be in use when generator yields
+ --> $DIR/pattern-borrow.rs:19:24
+ |
+19 | if let Test::A(ref _a) = test { //~ ERROR borrow may still be in use when generator yields
+ | ^^^^^^
+20 | yield ();
+ | -------- possible yield occurs here
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+
+fn main() {
+ let s = String::from("foo");
+ let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+ yield s[..];
+ };
+ gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ --> $DIR/sized-yield.rs:17:26
+ |
+17 | let mut gen = move || { //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+ | __________________________^
+18 | | yield s[..];
+19 | | };
+ | |____^ `str` does not have a constant size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+ = note: the yield type of a generator must have a statically known size
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ --> $DIR/sized-yield.rs:20:8
+ |
+20 | gen.resume(); //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+ | ^^^^^^ `str` does not have a constant size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+
+error: aborting due to 2 previous errors
+
-error[E0626]: borrow may still be in use when generator yields (Mir)
- --> $DIR/yield-while-local-borrowed.rs:24:17
- |
-24 | let a = &mut 3;
- | ^^^^^^
-...
-27 | yield();
- | ------- possible yield occurs here
-
error[E0626]: borrow may still be in use when generator yields (Ast)
--> $DIR/yield-while-local-borrowed.rs:24:22
|
55 | yield();
| ------- possible yield occurs here
+error[E0626]: borrow may still be in use when generator yields (Mir)
+ --> $DIR/yield-while-local-borrowed.rs:24:17
+ |
+24 | let a = &mut 3;
+ | ^^^^^^
+...
+27 | yield();
+ | ------- possible yield occurs here
+
error[E0626]: borrow may still be in use when generator yields (Mir)
--> $DIR/yield-while-local-borrowed.rs:52:21
|
0
} else {
n + sum_to(n - 1)
- //~^ ERROR the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
+ //~^ ERROR cannot add `impl Foo` to `u32`
}
}
= note: expected type `i32`
found type `u32`
-error[E0277]: the trait bound `u32: std::ops::Add<impl Foo>` is not satisfied
+error[E0277]: cannot add `impl Foo` to `u32`
--> $DIR/equality.rs:34:11
|
34 | n + sum_to(n - 1)
--> $DIR/trait_type.rs:17:4
|
17 | fn fmt(&self, x: &str) -> () { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability
|
= note: expected type `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>`
found type `fn(&MyType, &str)`
--> $DIR/trait_type.rs:27:4
|
27 | fn fmt() -> () { }
- | ^^^^^^^^^^^^^^^^^^ expected `&self` in impl
+ | ^^^^^^^^^^^^^^ expected `&self` in impl
|
= note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::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.
+#![allow(warnings)]
+#![allow(unused_variables, dead_code, unused, bad_style)]
+#![deny(elided_lifetime_in_path)]
+
+struct Foo<'a> { x: &'a u32 }
+fn foo(x: &Foo) {
+ //~^ ERROR: hidden lifetime parameters are deprecated, try `Foo<'_>`
+}
+
+fn main() {}
--- /dev/null
+error: hidden lifetime parameters are deprecated, try `Foo<'_>`
+ --> $DIR/ellided-lifetimes.rs:15:12
+ |
+15 | fn foo(x: &Foo) {
+ | ^^^
+ |
+note: lint level defined here
+ --> $DIR/ellided-lifetimes.rs:12:9
+ |
+12 | #![deny(elided_lifetime_in_path)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Deref;
+trait Trait {}
+
+struct Struct;
+
+impl Deref for Struct {
+ type Target = Trait;
+ fn deref(&self) -> &Trait {
+ unimplemented!();
+ }
+}
+//~^^^^ ERROR cannot infer an appropriate lifetime for lifetime parameter
--- /dev/null
+error[E0601]: main function not found
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in generic type due to conflicting requirements
+ --> $DIR/mismatched_trait_impl-2.rs:18:5
+ |
+18 | fn deref(&self) -> &Trait {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 18:5...
+ --> $DIR/mismatched_trait_impl-2.rs:18:5
+ |
+18 | / fn deref(&self) -> &Trait {
+19 | | unimplemented!();
+20 | | }
+ | |_____^
+ = note: ...but the lifetime must also be valid for the static lifetime...
+ = note: ...so that the method type is compatible with trait:
+ expected fn(&Struct) -> &Trait + 'static
+ found fn(&Struct) -> &Trait
+
+error: aborting due to 2 previous errors
+
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter 'a in generic type due to conflicting requirements
--> $DIR/mismatched_trait_impl.rs:19:5
|
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
+19 | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the method body at 19:5...
--> $DIR/mismatched_trait_impl.rs:19:5
20 | | x
21 | | }
| |_____^
-note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
- --> $DIR/mismatched_trait_impl.rs:19:5
- |
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
-note: but, the lifetime must be valid for the lifetime 'a as defined on the method body at 19:5...
+note: ...but the lifetime must also be valid for the lifetime 'a as defined on the method body at 19:5...
--> $DIR/mismatched_trait_impl.rs:19:5
|
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
-note: ...so that method type is compatible with trait (expected fn(&i32, &'a u32, &u32) -> &'a u32, found fn(&i32, &u32, &u32) -> &u32)
- --> $DIR/mismatched_trait_impl.rs:19:5
- |
-19 | / fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
-20 | | x
-21 | | }
- | |_____^
+19 | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 { //~ ERROR cannot infer
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...so that the method type is compatible with trait:
+ expected fn(&i32, &'a u32, &u32) -> &'a u32
+ found fn(&i32, &u32, &u32) -> &u32
error: aborting due to previous error
note: ...does not necessarily outlive the lifetime 'a as defined on the trait at 13:1
--> $DIR/issue-27942.rs:13:1
|
-13 | / pub trait Buffer<'a, R: Resources<'a>> {
-14 | |
-15 | | fn select(&self) -> BufferViewHandle<R>;
-16 | | //~^ ERROR mismatched types
-... |
-19 | | //~| lifetime mismatch
-20 | | }
- | |_^
+13 | pub trait Buffer<'a, R: Resources<'a>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/issue-27942.rs:15:5
note: the lifetime 'a as defined on the trait at 13:1...
--> $DIR/issue-27942.rs:13:1
|
-13 | / pub trait Buffer<'a, R: Resources<'a>> {
-14 | |
-15 | | fn select(&self) -> BufferViewHandle<R>;
-16 | | //~^ ERROR mismatched types
-... |
-19 | | //~| lifetime mismatch
-20 | | }
- | |_^
+13 | pub trait Buffer<'a, R: Resources<'a>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 15:5
--> $DIR/issue-27942.rs:15:5
|
note: ...does not necessarily outlive the lifetime 'a as defined on the impl at 13:1
--> $DIR/issue-37884.rs:13:1
|
-13 | / impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
-14 | |
-15 | | type Item = &'a mut T;
-16 | | fn next(&'a mut self) -> Option<Self::Item>
-... |
-21 | | }
-22 | | }
- | |_^
+13 | impl<'a, T: 'a> Iterator for RepeatMut<'a, T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+// compile-flags: -Z emit-end-regions -Z borrowck=compare -C overflow-checks=on
+
+struct S<'a> {
+ pointer: &'a mut isize
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+ S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+ let mut x = 1;
+
+ {
+ let mut y = S { pointer: &mut x };
+ let z = copy_borrowed_ptr(&mut y);
+ *y.pointer += 1;
+ //~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506]
+ //~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503]
+ *z.pointer += 1;
+ }
+}
--- /dev/null
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
+ --> $DIR/issue-45697-1.rs:30:9
+ |
+29 | let z = copy_borrowed_ptr(&mut y);
+ | - borrow of `*y.pointer` occurs here
+30 | *y.pointer += 1;
+ | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
+ --> $DIR/issue-45697-1.rs:30:9
+ |
+29 | let z = copy_borrowed_ptr(&mut y);
+ | ------ borrow of `y` occurs here
+30 | *y.pointer += 1;
+ | ^^^^^^^^^^^^^^^ use of borrowed `y`
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+// compile-flags: -Z emit-end-regions -Z borrowck=compare -C overflow-checks=off
+
+struct S<'a> {
+ pointer: &'a mut isize
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+ S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+ let mut x = 1;
+
+ {
+ let mut y = S { pointer: &mut x };
+ let z = copy_borrowed_ptr(&mut y);
+ *y.pointer += 1;
+ //~^ ERROR cannot assign to `*y.pointer` because it is borrowed (Ast) [E0506]
+ //~| ERROR cannot use `*y.pointer` because it was mutably borrowed (Mir) [E0503]
+ *z.pointer += 1;
+ }
+}
--- /dev/null
+error[E0506]: cannot assign to `*y.pointer` because it is borrowed (Ast)
+ --> $DIR/issue-45697.rs:30:9
+ |
+29 | let z = copy_borrowed_ptr(&mut y);
+ | - borrow of `*y.pointer` occurs here
+30 | *y.pointer += 1;
+ | ^^^^^^^^^^^^^^^ assignment to borrowed `*y.pointer` occurs here
+
+error[E0503]: cannot use `*y.pointer` because it was mutably borrowed (Mir)
+ --> $DIR/issue-45697.rs:30:9
+ |
+29 | let z = copy_borrowed_ptr(&mut y);
+ | ------ borrow of `y` occurs here
+30 | *y.pointer += 1;
+ | ^^^^^^^^^^^^^^^ use of borrowed `y`
+
+error: aborting due to 2 previous errors
+
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
--> $DIR/issue-46472.rs:13:1
|
-13 | / fn bar<'a>() -> &'a mut u32 {
-14 | | &mut 4
-15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
-16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597]
-17 | | }
- | |_^
+13 | fn bar<'a>() -> &'a mut u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0597]: borrowed value does not live long enough (Mir)
--> $DIR/issue-46472.rs:14:10
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 13:1...
--> $DIR/issue-46472.rs:13:1
|
-13 | / fn bar<'a>() -> &'a mut u32 {
-14 | | &mut 4
-15 | | //~^ ERROR borrowed value does not live long enough (Ast) [E0597]
-16 | | //~| ERROR borrowed value does not live long enough (Mir) [E0597]
-17 | | }
- | |_^
+13 | fn bar<'a>() -> &'a mut u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// must-compile-successfully
+
+#![warn(unused_parens)]
+
+macro_rules! the_worship_the_heart_lifts_above {
+ ( @as_expr, $e:expr) => { $e };
+ ( @generate_fn, $name:tt) => {
+ #[allow(dead_code)] fn the_moth_for_the_star<'a>() -> Option<&'a str> {
+ Some(the_worship_the_heart_lifts_above!( @as_expr, $name ))
+ }
+ };
+ ( $name:ident ) => { the_worship_the_heart_lifts_above!( @generate_fn, (stringify!($name))); }
+ // ↑ Notably, this does 𝘯𝘰𝘵 warn: we're declining to lint unused parens in
+ // function/method arguments inside of nested macros because of situations
+ // like those reported in Issue #47775
+}
+
+macro_rules! and_the_heavens_reject_not {
+ () => {
+ // ↓ But let's test that we still lint for unused parens around
+ // function args inside of simple, one-deep macros.
+ #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
+ //~^ WARN unnecessary parentheses around function argument
+ }
+}
+
+the_worship_the_heart_lifts_above!(rah);
+and_the_heavens_reject_not!();
+
+fn main() {}
--- /dev/null
+warning: unnecessary parentheses around function argument
+ --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:32:83
+ |
+32 | #[allow(dead_code)] fn the_night_for_the_morrow() -> Option<isize> { Some((2)) }
+ | ^^^ help: remove these parentheses
+...
+38 | and_the_heavens_reject_not!();
+ | ------------------------------ in this macro invocation
+ |
+note: lint level defined here
+ --> $DIR/issue-47775-nested-macro-unnecessary-parens-arg.rs:13:9
+ |
+13 | #![warn(unused_parens)]
+ | ^^^^^^^^^^^^^
+
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-tab
+
#![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
#![feature(no_debug)]
let mut a = (1); // should suggest no `mut`, no parens
//~^ WARN does not need to be mutable
//~| WARN unnecessary parentheses
+ // the line after `mut` has a `\t` at the beginning, this is on purpose
+ let mut
+ b = 1;
+ //~^^ WARN does not need to be mutable
let d = Equinox { warp_factor: 9.975 };
match d {
Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
//~^ WARN this pattern is redundant
}
- println!("{}", a);
+ println!("{} {}", a, b);
}
}
warning: unnecessary parentheses around assigned value
- --> $DIR/suggestions.rs:46:21
+ --> $DIR/suggestions.rs:48:21
|
-46 | let mut a = (1); // should suggest no `mut`, no parens
+48 | let mut a = (1); // should suggest no `mut`, no parens
| ^^^ help: remove these parentheses
|
note: lint level defined here
- --> $DIR/suggestions.rs:11:21
+ --> $DIR/suggestions.rs:13:21
|
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
| ^^^^^^^^^^^^^
warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721
- --> $DIR/suggestions.rs:41:1
+ --> $DIR/suggestions.rs:43:1
|
-41 | #[no_debug] // should suggest removal of deprecated attribute
+43 | #[no_debug] // should suggest removal of deprecated attribute
| ^^^^^^^^^^^ help: remove this attribute
|
= note: #[warn(deprecated)] on by default
warning: variable does not need to be mutable
- --> $DIR/suggestions.rs:46:13
+ --> $DIR/suggestions.rs:48:13
|
-46 | let mut a = (1); // should suggest no `mut`, no parens
- | ---^^
+48 | let mut a = (1); // should suggest no `mut`, no parens
+ | ----^
| |
| help: remove this `mut`
|
note: lint level defined here
- --> $DIR/suggestions.rs:11:9
+ --> $DIR/suggestions.rs:13:9
|
-11 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
+13 | #![warn(unused_mut, unused_parens)] // UI tests pass `-A unused`—see Issue #43896
| ^^^^^^^^^^
+warning: variable does not need to be mutable
+ --> $DIR/suggestions.rs:52:13
+ |
+52 | let mut
+ | _____________^
+ | |_____________|
+ | ||
+53 | || b = 1;
+ | ||____________-^
+ | |____________|
+ | help: remove this `mut`
+
warning: static is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:14:14
+ --> $DIR/suggestions.rs:16:14
|
-14 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+16 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
| -^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: try making it public: `pub`
= note: #[warn(private_no_mangle_statics)] on by default
error: const items should never be #[no_mangle]
- --> $DIR/suggestions.rs:16:14
+ --> $DIR/suggestions.rs:18:14
|
-16 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+18 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
| -----^^^^^^^^^^^^^^^^^^^^^^
| |
| help: try a static value: `pub static`
= note: #[deny(no_mangle_const_items)] on by default
warning: functions generic over types must be mangled
- --> $DIR/suggestions.rs:20:1
+ --> $DIR/suggestions.rs:22:1
|
-19 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
+21 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
| ------------ help: remove this attribute
-20 | pub fn defiant<T>(_t: T) {}
+22 | pub fn defiant<T>(_t: T) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(no_mangle_generic_items)] on by default
warning: function is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:24:1
+ --> $DIR/suggestions.rs:26:1
|
-24 | fn rio_grande() {} // should suggest `pub`
+26 | fn rio_grande() {} // should suggest `pub`
| -^^^^^^^^^^^^^^^^^
| |
| help: try making it public: `pub`
= note: #[warn(private_no_mangle_fns)] on by default
warning: static is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:31:18
+ --> $DIR/suggestions.rs:33:18
|
-31 | #[no_mangle] pub static DAUNTLESS: bool = true;
+33 | #[no_mangle] pub static DAUNTLESS: bool = true;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: function is marked #[no_mangle], but not exported
- --> $DIR/suggestions.rs:33:18
+ --> $DIR/suggestions.rs:35:18
|
-33 | #[no_mangle] pub fn val_jean() {}
+35 | #[no_mangle] pub fn val_jean() {}
| ^^^^^^^^^^^^^^^^^^^^
warning: denote infinite loops with `loop { ... }`
- --> $DIR/suggestions.rs:44:5
+ --> $DIR/suggestions.rs:46:5
|
-44 | while true { // should suggest `loop`
+46 | while true { // should suggest `loop`
| ^^^^^^^^^^ help: use `loop`
|
= note: #[warn(while_true)] on by default
warning: the `warp_factor:` in this pattern is redundant
- --> $DIR/suggestions.rs:51:23
+ --> $DIR/suggestions.rs:57:23
|
-51 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+57 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
| ------------^^^^^^^^^^^^
| |
| help: remove this
|
22 | break 22 //~ ERROR `break` with value from a `for` loop
| ^^^^^^^^ can only break with a value inside `loop`
+help: instead, use `break` on its own without a value inside this `for` loop
+ |
+22 | break //~ ERROR `break` with value from a `for` loop
+ | ^^^^^
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.
+
+macro_rules! bad {
+ ($s:ident whatever) => {
+ {
+ let $s = 0;
+ *&mut $s = 0;
+ //~^ ERROR cannot borrow immutable local variable `foo` as mutable [E0596]
+ }
+ }
+}
+
+fn main() {
+ bad!(foo whatever);
+}
--- /dev/null
+error[E0596]: cannot borrow immutable local variable `foo` as mutable
+ --> $DIR/span-covering-argument-1.rs:15:19
+ |
+14 | let $s = 0;
+ | -- consider changing this to `mut $s`
+15 | *&mut $s = 0;
+ | ^^ cannot borrow mutably
+...
+22 | bad!(foo whatever);
+ | ------------------- in this macro invocation
+
+error: aborting due to previous error
+
// except according to those terms.
fn main() {
- 1 + Some(1); //~ ERROR is not satisfied
- 2 as usize - Some(1); //~ ERROR is not satisfied
- 3 * (); //~ ERROR is not satisfied
- 4 / ""; //~ ERROR is not satisfied
+ 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}`
+ 2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize`
+ 3 * (); //~ ERROR cannot multiply `()` to `{integer}`
+ 4 / ""; //~ ERROR cannot divide `{integer}` by `&str`
5 < String::new(); //~ ERROR is not satisfied
6 == Ok(1); //~ ERROR is not satisfied
}
-error[E0277]: the trait bound `{integer}: std::ops::Add<std::option::Option<{integer}>>` is not satisfied
+error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}`
--> $DIR/binops.rs:12:7
|
-12 | 1 + Some(1); //~ ERROR is not satisfied
+12 | 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}`
| ^ no implementation for `{integer} + std::option::Option<{integer}>`
|
= help: the trait `std::ops::Add<std::option::Option<{integer}>>` is not implemented for `{integer}`
-error[E0277]: the trait bound `usize: std::ops::Sub<std::option::Option<{integer}>>` is not satisfied
+error[E0277]: cannot substract `std::option::Option<{integer}>` from `usize`
--> $DIR/binops.rs:13:16
|
-13 | 2 as usize - Some(1); //~ ERROR is not satisfied
+13 | 2 as usize - Some(1); //~ ERROR cannot substract `std::option::Option<{integer}>` from `usize`
| ^ no implementation for `usize - std::option::Option<{integer}>`
|
= help: the trait `std::ops::Sub<std::option::Option<{integer}>>` is not implemented for `usize`
-error[E0277]: the trait bound `{integer}: std::ops::Mul<()>` is not satisfied
+error[E0277]: cannot multiply `()` to `{integer}`
--> $DIR/binops.rs:14:7
|
-14 | 3 * (); //~ ERROR is not satisfied
+14 | 3 * (); //~ ERROR cannot multiply `()` to `{integer}`
| ^ no implementation for `{integer} * ()`
|
= help: the trait `std::ops::Mul<()>` is not implemented for `{integer}`
-error[E0277]: the trait bound `{integer}: std::ops::Div<&str>` is not satisfied
+error[E0277]: cannot divide `{integer}` by `&str`
--> $DIR/binops.rs:15:7
|
-15 | 4 / ""; //~ ERROR is not satisfied
+15 | 4 / ""; //~ ERROR cannot divide `{integer}` by `&str`
| ^ no implementation for `{integer} / &str`
|
= help: the trait `std::ops::Div<&str>` is not implemented for `{integer}`
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+// ignore-tidy-linelength
+
+#![crate_type = "lib"]
+
+pub struct Bar;
--- /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:no_debug.rs
+
+extern crate no_debug;
+
+use no_debug::Bar;
+
+struct Foo;
+
+fn main() {
+ println!("{:?} {:?}", Foo, Bar);
+ println!("{} {}", Foo, Bar);
+}
+//~^^^ ERROR `Foo` doesn't implement `std::fmt::Debug`
+//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Debug`
+//~^^^^ ERROR `Foo` doesn't implement `std::fmt::Display`
+//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Display`
+
--- /dev/null
+error[E0277]: `Foo` doesn't implement `std::fmt::Debug`
+ --> $DIR/no-debug.rs:20:27
+ |
+20 | println!("{:?} {:?}", Foo, Bar);
+ | ^^^ `Foo` cannot be formatted using `:?`; add `#[derive(Debug)]` or manually implement `std::fmt::Debug`
+ |
+ = help: the trait `std::fmt::Debug` is not implemented for `Foo`
+ = note: required by `std::fmt::Debug::fmt`
+
+error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug`
+ --> $DIR/no-debug.rs:20:32
+ |
+20 | println!("{:?} {:?}", Foo, Bar);
+ | ^^^ `no_debug::Bar` cannot be formatted using `:?` because it doesn't implement `std::fmt::Debug`
+ |
+ = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar`
+ = note: required by `std::fmt::Debug::fmt`
+
+error[E0277]: `Foo` doesn't implement `std::fmt::Display`
+ --> $DIR/no-debug.rs:21:23
+ |
+21 | println!("{} {}", Foo, Bar);
+ | ^^^ `Foo` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `Foo`
+ = note: required by `std::fmt::Display::fmt`
+
+error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display`
+ --> $DIR/no-debug.rs:21:28
+ |
+21 | println!("{} {}", Foo, Bar);
+ | ^^^ `no_debug::Bar` cannot be formatted with the default formatter; try using `:?` instead if you are using a format string
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar`
+ = note: required by `std::fmt::Display::fmt`
+
+error: aborting due to 4 previous errors
+
warning: struct is never used: `S`
- --> $DIR/macro-span-replacement.rs:17:9
+ --> $DIR/macro-span-replacement.rs:17:14
|
17 | $b $a; //~ WARN struct is never used
- | ^^^^^^
+ | ^
...
22 | m!(S struct);
| ------------- in this macro invocation
let x = 1;
let y = 2;
let z = 3;
- foo(1 as u32 + //~ ERROR not satisfied
+ foo(1 as u32 + //~ ERROR cannot add `()` to `u32`
bar(x,
-error[E0277]: the trait bound `u32: std::ops::Add<()>` is not satisfied
+error[E0277]: cannot add `()` to `u32`
--> $DIR/multiline-span-simple.rs:23:18
|
-23 | foo(1 as u32 + //~ ERROR not satisfied
+23 | foo(1 as u32 + //~ ERROR cannot add `()` to `u32`
| ^ no implementation for `u32 + ()`
|
= help: the trait `std::ops::Add<()>` is not implemented for `u32`
--> $DIR/static-lifetime.rs:13:1
|
13 | impl<'a, A: Clone> Arbitrary for ::std::borrow::Cow<'a, A> {} //~ ERROR lifetime bound
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: but lifetime parameter must outlive the static lifetime
error: aborting due to previous error
--> $DIR/for-c-in-str.rs:14:14
|
14 | for c in "asdf" {
- | ^^^^^^ `&str` is not an iterator; maybe try calling `.iter()` or a similar method
+ | ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()`
|
= help: the trait `std::iter::Iterator` is not implemented for `&str`
= note: required by `std::iter::IntoIterator::into_iter`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(use_nested_groups)]
-
mod a {
pub mod b1 {
pub enum C2 {}
error[E0432]: unresolved import `a::b1::C1`
- --> $DIR/use-nested-groups-error.rs:21:14
+ --> $DIR/use-nested-groups-error.rs:19:14
|
-21 | use a::{b1::{C1, C2}, B2};
+19 | use a::{b1::{C1, C2}, B2};
| ^^ no `C1` in `a::b1`. Did you mean to use `C2`?
error: aborting due to previous error
-Subproject commit 7d7fef1690218bbb406cf3bcadf7bb29dbb40cc5
+Subproject commit ce47e529d29f0bf19b31ae80b37b467e42fb97e2
.expect("Malformed llvm version directive");
// Ignore if using system LLVM and actual version
// is smaller the minimum required version
- !(config.system_llvm && &actual_version[..] < min_version)
+ config.system_llvm && &actual_version[..] < min_version
} else {
false
}
let mut results = Vec::new();
let mut mismatch = Mismatch::new(0);
- for result in diff::lines(actual, expected) {
+ for result in diff::lines(expected, actual) {
match result {
diff::Result::Left(str) => {
if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
mismatch.lines.push(DiffLine::Context(line.to_owned()));
}
- mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
+ mismatch.lines.push(DiffLine::Expected(str.to_owned()));
+ line_number += 1;
lines_since_mismatch = 0;
}
diff::Result::Right(str) => {
mismatch.lines.push(DiffLine::Context(line.to_owned()));
}
- mismatch.lines.push(DiffLine::Expected(str.to_owned()));
- line_number += 1;
+ mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
lines_since_mismatch = 0;
}
diff::Result::Both(str, _) => {
-Subproject commit 919604e1ead8294c8ca14f101be4380ea1ea370c
+Subproject commit 61833b9aeab8bf8f0c0c0e42b7c96b6eceb37d0d
-Subproject commit 511321ae1c2fa3f0e334885fecf406dd6c882836
+Subproject commit dee42bda8156a28ead609080e27b02173bb9c29e
clap = "2.25.0"
[dependencies.mdbook]
-version = "0.0.28"
+version = "0.1.2"
default-features = false
extern crate clap;
use std::env;
-use std::io::{self, Write};
use std::path::{Path, PathBuf};
use clap::{App, ArgMatches, SubCommand, AppSettings};
};
if let Err(e) = res {
- writeln!(&mut io::stderr(), "An error occured:\n{}", e).ok();
+ eprintln!("Error: {}", e);
+
+ for cause in e.iter().skip(1) {
+ eprintln!("\tCaused By: {}", cause);
+ }
+
::std::process::exit(101);
}
}
// Build command implementation
pub fn build(args: &ArgMatches) -> Result<()> {
let book_dir = get_book_dir(args);
- let mut book = MDBook::new(&book_dir).read_config()?;
+ let mut book = MDBook::load(&book_dir)?;
// Set this to allow us to catch bugs in advance.
book.config.build.create_missing = false;
-Subproject commit e0e3e22248cd14ebbe0253e9720261a0328bfc59
+Subproject commit 346238f49740d6c98102a6a59811b1625c73a9d7
"openssl", // BSD+advertising clause, cargo, mdbook
"pest", // MPL2, mdbook via handlebars
"thread-id", // Apache-2.0, mdbook
+ "toml-query", // MPL-2.0, mdbook
+ "is-match", // MPL-2.0, mdbook
"cssparser", // MPL-2.0, rustdoc
"smallvec", // MPL-2.0, rustdoc
"fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo