# AWS_SECRET_ACCESS_KEY=...
- secure: "j96XxTVOSUf4s4r4htIxn/fvIa5DWbMgLqWl7r8z2QfgUwscmkMXAwXuFNc7s7bGTpV/+CgDiMFFM6BAFLGKutytIF6oA02s9b+usQYnM0th7YQ2AIgm9GtMTJCJp4AoyfFmh8F2faUICBZlfVLUJ34udHEe35vOklix+0k4WDo="
# TOOLSTATE_REPO_ACCESS_TOKEN=...
- - secure: "cFh8thThqEJLC98XKI5pfqflUzOlxsYPRW20AWRaYOOgYHPTiGWypTXiPbGSKaeAXTZoOA+DpQtEmefc0U6lt9dHc7a/MIaK6isFurjlnKYiLOeTruzyu1z7PWCeZ/jKXsU2RK/88DBtlNwfMdaMIeuKj14IVfpepPPL71ETbuk="
+ - secure: "ESfcXqv4N2VMhqi2iIyw6da9VrsA78I4iR1asouCaq4hzTTrkB4WNRrfURy6xg72gQ4nMhtRJbB0/2jmc9Cu1+g2CzXtyiL223aJ5CKrXdcvbitopQSDfp07dMWm+UED+hNFEanpErKAeU/6FM3A+J+60PMk8MCF1h9tqNRISJw="
before_install:
# We'll use the AWS cli to download/upload cached docker layers, so install
secure: 7Y+JiquYedOAgnUU26uL0DPzrxmTtR+qIwG6rNKSuWDffqU3vVZxbGXim9QpTO80
SCCACHE_DIGEST: f808afabb4a4eb1d7112bcb3fa6be03b61e93412890c88e177c667eb37f46353d7ec294e559b16f9f4b5e894f2185fe7670a0df15fd064889ecbd80f0c34166c
TOOLSTATE_REPO_ACCESS_TOKEN:
- secure: PTZiSxJMVUZ0VnMR5i13E4OagbXfglj7pcskDQiKufVrDm13mLoI0vDJAEM35+bY
+ secure: gKGlVktr7iuqCoYSxHxDE9ltLOKU0nYDEuQxvWbNxUIW7ri5ppn8L06jQzN0GGzN
# By default schannel checks revocation of certificates unlike some other SSL
# backends, but we've historically had problems on CI where a revocation
[[package]]
name = "assert_cli"
-version = "0.5.6"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "clippy"
-version = "0.0.198"
+version = "0.0.200"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy-mini-macro-test 0.2.0",
- "clippy_lints 0.0.198",
+ "clippy_lints 0.0.200",
"compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "clippy_lints"
-version = "0.0.197"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "clippy_lints"
-version = "0.0.198"
+version = "0.0.200"
dependencies = [
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "languageserver-types"
-version = "0.39.0"
+version = "0.41.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)",
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "minifier"
+version = "0.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "miniz-sys"
version = "0.1.10"
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
[[package]]
name = "rls"
-version = "0.127.0"
+version = "0.128.0"
dependencies = [
"cargo 0.28.0",
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clippy_lints 0.0.200",
"env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "languageserver-types 0.41.0 (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)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustfmt-nightly 0.6.1",
+ "rustfmt-nightly 0.7.0",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls-analysis"
-version = "0.12.1"
+version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rls-data"
-version = "0.15.0"
+version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rustc-ap-rustc_cratesio_shim"
-version = "113.0.0"
+version = "128.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)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "113.0.0"
+version = "128.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.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.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 = "113.0.0"
+version = "128.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-rustc_target"
-version = "113.0.0"
+version = "128.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 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-serialize"
-version = "113.0.0"
+version = "128.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-ap-syntax"
-version = "113.0.0"
+version = "128.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_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_errors 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax_pos 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-ap-syntax_pos"
-version = "113.0.0"
+version = "128.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
version = "0.0.0"
dependencies = [
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
name = "rustc_trans"
version = "0.0.0"
dependencies = [
+ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
name = "rustdoc"
version = "0.0.0"
dependencies = [
+ "minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustfmt-nightly"
-version = "0.6.1"
+version = "0.7.0"
dependencies = [
- "assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "assert_cli 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-rustc_target 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-ap-syntax 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
-"checksum assert_cli 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8ca6beaa44a3520407b28a4a779a19b1364fcadcb2f258c41a7baf3102ced0"
+"checksum assert_cli 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5da59dbd8df54562665b925b427221ceda9b771408cb8a6cbd2125d3b001330b"
"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4"
"checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e"
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873"
"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536"
-"checksum clippy_lints 0.0.197 (registry+https://github.com/rust-lang/crates.io-index)" = "ee3b543abb36b1557180d41dd3758581254644d85d021df7f8f8cb395054581c"
"checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c"
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be"
"checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
-"checksum languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4cdd5e52d71aca47050e5b25f03082609c63a1e76b7362ebdd010895b3f854"
+"checksum languageserver-types 0.41.0 (registry+https://github.com/rust-lang/crates.io-index)" = "017cf5ade4be5ebeb06277ccd281c268dbd2e0801128d3992b4b4057f34dd432"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef"
"checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
+"checksum minifier 0.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "26f3e36a4db1981b16567e4abfd6ddc3641bc9b950bdc868701f656bf9b74bdd"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d"
"checksum nibble_vec 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8d77f3db4bce033f4d04db08079b2ef1c3d02b44e86f25d08886fafa7756ffa"
"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
-"checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46"
+"checksum rls-analysis 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da9794cd1f80f2cb888c00641a32f9855d0226c954ee31cef145784914c7142e"
"checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2"
-"checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510"
+"checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988"
"checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
"checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb"
-"checksum rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a01334797c5c4cf56cc40bb9636d7b4c4a076665b9b9b7f100fd666cf0a02ffc"
-"checksum rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03d6f8f7da0de905f6ef80dc14dce3bbc372430622b6aeb421cf13190bc70e8a"
-"checksum rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfd6183804a685c48601651d8c8c7b0daa8f83b0b5e24edfbcb6a0337085127"
-"checksum rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f223157f51bf0e0621bef099de862468892ee4c4b83056f48f63e1bc00ccb72"
-"checksum rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2104a55a87d65cba8a845656f1f19a35da52af403863cd2a4bd5876ba522d879"
-"checksum rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50671adb9b0a7c57a4690ac6a40cb614879f543b64aada42f55b66212492323"
-"checksum rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55793c2a775230c42661194c48d44b35d4c8439d79ad8528e56651e854c48c63"
+"checksum rustc-ap-rustc_cratesio_shim 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7374a2b466e6e3ce489e045302e304849355faf7fd033d4d95e6e86e48c313b4"
+"checksum rustc-ap-rustc_data_structures 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b3c3e566868a04735852eb333db958453a53cacdd935fe508e0c9fd822ea88"
+"checksum rustc-ap-rustc_errors 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b81dc5e8a8e63befb0eaf1c9443e269dee6f8daced4e3149fe8a80947fd682e"
+"checksum rustc-ap-rustc_target 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a6bb7f1df7a4ca231cbe35a5eaebdc22cd2258c0393e856513b5186dec720e4"
+"checksum rustc-ap-serialize 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d1ab72257c28395c45a27a5812d94515ec43e639add4820eafc919a71c1714c3"
+"checksum rustc-ap-syntax 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf9ca2901388714e9ccc7de7281ef06cec55d9f245252ba1d635bc86c730d9a"
+"checksum rustc-ap-syntax_pos 128.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e5217444369a36e98e11f4ac976f03878704893832e2e0b57d49f2f31438139f"
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
"checksum rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1aa5cd8c3a706edb19b6ec6aa7b056bdc635b6e99c5cf7014f9af9d92f15e99"
"checksum rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d69983f8613a9c3ba1a3bbf5e8bdf2fd5c42317b1d8dd8623ca8030173bf8a6b"
};
Miri, miri, "src/tools/miri", "miri", {};
Rls, rls, "src/tools/rls", "rls", {
- let clippy = builder.ensure(Clippy {
- compiler: self.compiler,
- target: self.target,
- extra_features: Vec::new(),
- });
- let channel = &builder.config.channel;
- if clippy.is_some() && channel != "stable" && channel != "beta" {
- self.extra_features.push("clippy".to_owned());
- }
builder.ensure(native::Openssl {
target: self.target,
});
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ xz-utils \
+ g++-sparc64-linux-gnu \
+ libssl-dev \
+ pkg-config
+
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+ENV HOSTS=sparc64-unknown-linux-gnu
+
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
OLDFLAGS="$-"
set -eu
- git config --global user.email '34210020+rust-toolstate-update@users.noreply.github.com'
+ git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com'
git config --global user.name 'Rust Toolstate Update'
git config --global credential.helper store
printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \
an optional explicit output \fIPATH\fR specified for that particular emission
kind. This path takes precedence over the \fB-o\fR option.
.TP
-\fB\-\-print\fR [crate\-name|file\-names|sysroot]
+\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs]
Comma separated list of compiler information to print on stdout.
.TP
\fB\-g\fR
+++ /dev/null
-# `macro_lifetime_matcher`
-
-The tracking issue for this feature is: [#46895]
-
-With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry:
-
-* `lifetime`: a lifetime. Examples: 'static, 'a.
-
-A `lifetime` variable may be followed by anything.
-
-[#46895]: https://github.com/rust-lang/rust/issues/46895
-[frags]: ../book/first-edition/macros.html#syntactic-requirements
-
-------------------------
--- /dev/null
+# `macro_literal_matcher`
+
+The tracking issue for this feature is: [#35625]
+
+The RFC is: [rfc#1576].
+
+With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry:
+
+* `literal`: a literal. Examples: 2, "string", 'c'
+
+A `literal` may be followed by anything, similarly to the `ident` specifier.
+
+[rfc#1576]: http://rust-lang.github.io/rfcs/1576-macros-literal-matcher.html
+[#35625]: https://github.com/rust-lang/rust/issues/35625
+[frags]: ../book/first-edition/macros.html#syntactic-requirements
+
+------------------------
for (trait, supers, errs) in [('Clone', [], 1),
('PartialEq', [], 2),
- ('PartialOrd', ['PartialEq'], 5),
+ ('PartialOrd', ['PartialEq'], 1),
('Eq', ['PartialEq'], 1),
('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1),
('Debug', [], 1),
-Subproject commit 2a2f6d96c8dc578d2474742f14c9bab0b36b0408
+Subproject commit 4cfd7101eb549169cdaeda5313f7c39415b9d736
/// value is not necessarily valid to be used to actually access memory.
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
- /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
- /// and destination may *not* overlap.
+ /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
+ /// and destination must *not* overlap.
///
- /// `copy_nonoverlapping` is semantically equivalent to C's `memcpy`.
+ /// For regions of memory which might overlap, use [`copy`] instead.
+ ///
+ /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`].
+ ///
+ /// [`copy`]: ./fn.copy.html
+ /// [`memcpy`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memcpy
///
/// # Safety
///
- /// Beyond requiring that the program must be allowed to access both regions
- /// of memory, it is Undefined Behavior for source and destination to
- /// overlap. Care must also be taken with the ownership of `src` and
- /// `dst`. This method semantically moves the values of `src` into `dst`.
- /// However it does not drop the contents of `dst`, or prevent the contents
- /// of `src` from being dropped or used.
+ /// Behavior is undefined if any of the following conditions are violated:
+ ///
+ /// * The region of memory which begins at `src` and has a length of
+ /// `count * size_of::<T>()` bytes must be *both* valid and initialized.
+ ///
+ /// * The region of memory which begins at `dst` and has a length of
+ /// `count * size_of::<T>()` bytes must be valid (but may or may not be
+ /// initialized).
+ ///
+ /// * The two regions of memory must *not* overlap.
+ ///
+ /// * `src` must be properly aligned.
+ ///
+ /// * `dst` must be properly aligned.
+ ///
+ /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
+ /// region at `dst` can be used or dropped after calling
+ /// `copy_nonoverlapping`. `copy_nonoverlapping` creates bitwise copies of
+ /// `T`, regardless of whether `T: Copy`, which can result in undefined
+ /// behavior if both copies are used.
+ ///
+ /// [`Copy`]: ../marker/trait.Copy.html
///
/// # Examples
///
- /// A safe swap function:
+ /// Manually implement [`Vec::append`]:
///
/// ```
- /// use std::mem;
/// use std::ptr;
///
- /// # #[allow(dead_code)]
- /// fn swap<T>(x: &mut T, y: &mut T) {
+ /// /// Moves all the elements of `src` into `dst`, leaving `src` empty.
+ /// fn append<T>(dst: &mut Vec<T>, src: &mut Vec<T>) {
+ /// let src_len = src.len();
+ /// let dst_len = dst.len();
+ ///
+ /// // Ensure that `dst` has enough capacity to hold all of `src`.
+ /// dst.reserve(src_len);
+ ///
/// unsafe {
- /// // Give ourselves some scratch space to work with
- /// let mut t: T = mem::uninitialized();
+ /// // The call to offset is always safe because `Vec` will never
+ /// // allocate more than `isize::MAX` bytes.
+ /// let dst = dst.as_mut_ptr().offset(dst_len as isize);
+ /// let src = src.as_ptr();
+ ///
+ /// // The two regions cannot overlap becuase mutable references do
+ /// // not alias, and two different vectors cannot own the same
+ /// // memory.
+ /// ptr::copy_nonoverlapping(src, dst, src_len);
+ /// }
///
- /// // Perform the swap, `&mut` pointers never alias
- /// ptr::copy_nonoverlapping(x, &mut t, 1);
- /// ptr::copy_nonoverlapping(y, x, 1);
- /// ptr::copy_nonoverlapping(&t, y, 1);
+ /// unsafe {
+ /// // Truncate `src` without dropping its contents.
+ /// src.set_len(0);
///
- /// // 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);
+ /// // Notify `dst` that it now holds the contents of `src`.
+ /// dst.set_len(dst_len + src_len);
/// }
/// }
+ ///
+ /// let mut a = vec!['r'];
+ /// let mut b = vec!['u', 's', 't'];
+ ///
+ /// append(&mut a, &mut b);
+ ///
+ /// assert_eq!(a, &['r', 'u', 's', 't']);
+ /// assert!(b.is_empty());
/// ```
+ ///
+ /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append
#[stable(feature = "rust1", since = "1.0.0")]
pub fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
- /// Copies `count * size_of<T>` bytes from `src` to `dst`. The source
+ /// Copies `count * size_of::<T>()` bytes from `src` to `dst`. The source
/// and destination may overlap.
///
- /// `copy` is semantically equivalent to C's `memmove`.
+ /// If the source and destination will *never* overlap,
+ /// [`copy_nonoverlapping`] can be used instead.
+ ///
+ /// `copy` is semantically equivalent to C's [`memmove`].
+ ///
+ /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html
+ /// [`memmove`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memmove
///
/// # Safety
///
- /// Care must be taken with the ownership of `src` and `dst`.
- /// This method semantically moves the values of `src` into `dst`.
- /// However it does not drop the contents of `dst`, or prevent the contents of `src`
- /// from being dropped or used.
+ /// Behavior is undefined if any of the following conditions are violated:
+ ///
+ /// * The region of memory which begins at `src` and has a length of
+ /// `count * size_of::<T>()` bytes must be *both* valid and initialized.
+ ///
+ /// * The region of memory which begins at `dst` and has a length of
+ /// `count * size_of::<T>()` bytes must be valid (but may or may not be
+ /// initialized).
+ ///
+ /// * `src` must be properly aligned.
+ ///
+ /// * `dst` must be properly aligned.
+ ///
+ /// Additionally, if `T` is not [`Copy`], only the region at `src` *or* the
+ /// region at `dst` can be used or dropped after calling `copy`. `copy`
+ /// creates bitwise copies of `T`, regardless of whether `T: Copy`, which
+ /// can result in undefined behavior if both copies are used.
+ ///
+ /// [`Copy`]: ../marker/trait.Copy.html
///
/// # Examples
///
/// dst
/// }
/// ```
- ///
#[stable(feature = "rust1", since = "1.0.0")]
pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
- /// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
- /// bytes of memory starting at `dst` to `val`.
+ /// Sets `count * size_of::<T>()` bytes of memory starting at `dst` to
+ /// `val`.
+ ///
+ /// `write_bytes` is semantically equivalent to C's [`memset`].
+ ///
+ /// [`memset`]: https://www.gnu.org/software/libc/manual/html_node/Copying-Strings-and-Arrays.html#index-memset
+ ///
+ /// # Safety
+ ///
+ /// Behavior is undefined if any of the following conditions are violated:
+ ///
+ /// * The region of memory which begins at `dst` and has a length of
+ /// `count` bytes must be valid.
+ ///
+ /// * `dst` must be properly aligned.
+ ///
+ /// Additionally, the caller must ensure that writing `count` bytes to the
+ /// given region of memory results in a valid value of `T`. Creating an
+ /// invalid value of `T` can result in undefined behavior. An example is
+ /// provided below.
///
/// # Examples
///
+ /// Basic usage:
+ ///
/// ```
/// use std::ptr;
///
/// }
/// assert_eq!(vec, [b'a', b'a', 0, 0]);
/// ```
+ ///
+ /// Creating an invalid value:
+ ///
+ /// ```no_run
+ /// use std::{mem, ptr};
+ ///
+ /// let mut v = Box::new(0i32);
+ ///
+ /// unsafe {
+ /// // Leaks the previously held value by overwriting the `Box<T>` with
+ /// // a null pointer.
+ /// ptr::write_bytes(&mut v, 0, mem::size_of::<Box<i32>>());
+ /// }
+ ///
+ /// // At this point, using or dropping `v` results in undefined behavior.
+ /// // v = Box::new(0i32); // ERROR
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
/// that information can be useful. For example, if you want to iterate
/// backwards, a good start is to know where the end is.
///
-/// When implementing an `ExactSizeIterator`, You must also implement
+/// When implementing an `ExactSizeIterator`, you must also implement
/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must*
/// return the exact size of the iterator.
///
// FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory
-//! Raw, unsafe pointers, `*const T`, and `*mut T`.
+//! Manually manage memory through raw pointers.
//!
//! *[See also the pointer primitive types](../../std/primitive.pointer.html).*
/// Executes the destructor (if any) of the pointed-to value.
///
-/// This has two use cases:
+/// This is semantically equivalent to calling [`ptr::read`] and discarding
+/// the result, but has the following advantages:
///
/// * It is *required* to use `drop_in_place` to drop unsized types like
/// trait objects, because they can't be read out onto the stack and
/// dropped normally.
///
-/// * It is friendlier to the optimizer to do this over `ptr::read` when
+/// * It is friendlier to the optimizer to do this over [`ptr::read`] when
/// dropping manually allocated memory (e.g. when writing Box/Rc/Vec),
/// as the compiler doesn't need to prove that it's sound to elide the
/// copy.
///
+/// [`ptr::read`]: ../ptr/fn.read.html
+///
/// # Safety
///
-/// This has all the same safety problems as `ptr::read` with respect to
-/// invalid pointers, types, and double drops.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `to_drop` must point to valid memory.
+///
+/// * `to_drop` must be properly aligned.
+///
+/// Additionally, if `T` is not [`Copy`], using the pointed-to value after
+/// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop =
+/// foo` counts as a use because it will cause the the value to be dropped
+/// again. [`write`] can be used to overwrite data without causing it to be
+/// dropped.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`write`]: ../ptr/fn.write.html
+///
+/// # Examples
+///
+/// Manually remove the last item from a vector:
+///
+/// ```
+/// use std::ptr;
+/// use std::rc::Rc;
+///
+/// let last = Rc::new(1);
+/// let weak = Rc::downgrade(&last);
+///
+/// let mut v = vec![Rc::new(0), last];
+///
+/// unsafe {
+/// // Without a call `drop_in_place`, the last item would never be dropped,
+/// // and the memory it manages would be leaked.
+/// ptr::drop_in_place(&mut v[1]);
+/// v.set_len(1);
+/// }
+///
+/// assert_eq!(v, &[0.into()]);
+///
+/// // Ensure that the last item was dropped.
+/// assert!(weak.upgrade().is_none());
+/// ```
#[stable(feature = "drop_in_place", since = "1.8.0")]
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
/// Swaps the values at two mutable locations of the same type, without
/// deinitializing either.
///
-/// The values pointed at by `x` and `y` may overlap, unlike `mem::swap` which
-/// is otherwise equivalent. If the values do overlap, then the overlapping
-/// region of memory from `x` will be used. This is demonstrated in the
-/// examples section below.
+/// But for the following two exceptions, this function is semantically
+/// equivalent to [`mem::swap`]:
+///
+/// * It operates on raw pointers instead of references. When references are
+/// available, [`mem::swap`] should be preferred.
+///
+/// * The two pointed-to values may overlap. If the values do overlap, then the
+/// overlapping region of memory from `x` will be used. This is demonstrated
+/// in the examples below.
+///
+/// [`mem::swap`]: ../mem/fn.swap.html
///
/// # Safety
///
-/// This function copies the memory through the raw pointers passed to it
-/// as arguments.
+/// Behavior is undefined if any of the following conditions are violated:
///
-/// Ensure that these pointers are valid before calling `swap`.
+/// * `x` and `y` must point to valid, initialized memory.
+///
+/// * `x` and `y` must be properly aligned.
///
/// # Examples
///
}
}
-/// Replaces the value at `dest` with `src`, returning the old
-/// value, without dropping either.
+/// Replaces the value at `dest` with `src`, returning the old value, without
+/// dropping either.
+///
+/// This function is semantically equivalent to [`mem::replace`] except that it
+/// operates on raw pointers instead of references. When references are
+/// available, [`mem::replace`] should be preferred.
+///
+/// [`mem::replace`]: ../mem/fn.replace.html
///
/// # Safety
///
-/// This is only unsafe because it accepts a raw pointer.
-/// Otherwise, this operation is identical to `mem::replace`.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dest` must point to valid, initialized memory.
+///
+/// * `dest` must be properly aligned.
+///
+/// # Examples
+///
+/// ```
+/// use std::ptr;
+///
+/// let mut rust = vec!['b', 'u', 's', 't'];
+///
+/// // `mem::replace` would have the same effect without requiring the unsafe
+/// // block.
+/// let b = unsafe {
+/// ptr::replace(&mut rust[0], 'r')
+/// };
+///
+/// assert_eq!(b, 'b');
+/// assert_eq!(rust, &['r', 'u', 's', 't']);
+/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
///
/// # Safety
///
-/// Beyond accepting a raw pointer, this is unsafe because it semantically
-/// moves the value out of `src` without preventing further usage of `src`.
-/// If `T` is not `Copy`, then care must be taken to ensure that the value at
-/// `src` is not used before the data is overwritten again (e.g. with `write`,
-/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
-/// because it will attempt to drop the value previously at `*src`.
+/// Behavior is undefined if any of the following conditions are violated:
///
-/// The pointer must be aligned; use `read_unaligned` if that is not the case.
+/// * `src` must point to valid, initialized memory.
+///
+/// * `src` must be properly aligned. Use [`read_unaligned`] if this is not the
+/// case.
+///
+/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
+/// pointed-to value can be used or dropped after calling `read`. `read` creates
+/// a bitwise copy of `T`, regardless of whether `T: Copy`, which can result
+/// in undefined behavior if both copies are used. Note that `*src = foo` counts
+/// as a use because it will attempt to drop the value previously at `*src`.
+/// [`write`] can be used to overwrite data without causing it to be dropped.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`read_unaligned`]: ./fn.read_unaligned.html
+/// [`write`]: ./fn.write.html
///
/// # Examples
///
/// assert_eq!(std::ptr::read(y), 12);
/// }
/// ```
+///
+/// Manually implement [`mem::swap`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// fn swap<T>(a: &mut T, b: &mut T) {
+/// unsafe {
+/// // Create a bitwise copy of the value at `a` in `tmp`.
+/// let tmp = ptr::read(a);
+///
+/// // Exiting at this point (either by explicitly returning or by
+/// // calling a function which panics) would cause the value in `tmp` to
+/// // be dropped while the same value is still referenced by `a`. This
+/// // could trigger undefined behavior if `T` is not `Copy`.
+///
+/// // Create a bitwise copy of the value at `b` in `a`.
+/// // This is safe because mutable references cannot alias.
+/// ptr::copy_nonoverlapping(b, a, 1);
+///
+/// // As above, exiting here could trigger undefined behavior because
+/// // the same value is referenced by `a` and `b`.
+///
+/// // Move `tmp` into `b`.
+/// ptr::write(b, tmp);
+/// }
+/// }
+///
+/// let mut foo = "foo".to_owned();
+/// let mut bar = "bar".to_owned();
+///
+/// swap(&mut foo, &mut bar);
+///
+/// assert_eq!(foo, "bar");
+/// assert_eq!(bar, "foo");
+/// ```
+///
+/// [`mem::swap`]: ../mem/fn.swap.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn read<T>(src: *const T) -> T {
/// Reads the value from `src` without moving it. This leaves the
/// memory in `src` unchanged.
///
-/// Unlike `read`, the pointer may be unaligned.
+/// Unlike [`read`], `read_unaligned` works with unaligned pointers.
+///
+/// [`read`]: ./fn.read.html
///
/// # Safety
///
-/// Beyond accepting a raw pointer, this is unsafe because it semantically
-/// moves the value out of `src` without preventing further usage of `src`.
-/// If `T` is not `Copy`, then care must be taken to ensure that the value at
-/// `src` is not used before the data is overwritten again (e.g. with `write`,
-/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
-/// because it will attempt to drop the value previously at `*src`.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must point to valid, initialized memory.
+///
+/// Additionally, if `T` is not [`Copy`], only the returned value *or* the
+/// pointed-to value can be used or dropped after calling `read_unaligned`.
+/// `read_unaligned` creates a bitwise copy of `T`, regardless of whether `T:
+/// Copy`, and this can result in undefined behavior if both copies are used.
+/// Note that `*src = foo` counts as a use because it will attempt to drop the
+/// value previously at `*src`. [`write_unaligned`] can be used to overwrite
+/// data without causing it to be dropped.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`write_unaligned`]: ./fn.write_unaligned.html
///
/// # Examples
///
-/// Basic usage:
+/// Access members of a packed struct by reference:
///
/// ```
-/// let x = 12;
-/// let y = &x as *const i32;
+/// use std::ptr;
///
-/// unsafe {
-/// assert_eq!(std::ptr::read_unaligned(y), 12);
+/// #[repr(packed, C)]
+/// #[derive(Default)]
+/// struct Packed {
+/// _padding: u8,
+/// unaligned: u32,
/// }
+///
+/// let x = Packed {
+/// _padding: 0x00,
+/// unaligned: 0x01020304,
+/// };
+///
+/// let v = unsafe {
+/// // Take a reference to a 32-bit integer which is not aligned.
+/// let unaligned = &x.unaligned;
+///
+/// // Dereferencing normally will emit an unaligned load instruction,
+/// // causing undefined behavior.
+/// // let v = *unaligned; // ERROR
+///
+/// // Instead, use `read_unaligned` to read improperly aligned values.
+/// let v = ptr::read_unaligned(unaligned);
+///
+/// v
+/// };
+///
+/// // Accessing unaligned values directly is safe.
+/// assert!(x.unaligned == v);
/// ```
#[inline]
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
/// Overwrites a memory location with the given value without reading or
/// dropping the old value.
///
-/// # Safety
-///
-/// This operation is marked unsafe because it accepts a raw pointer.
-///
-/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// `write` does not drop the contents of `dst`. This is safe, but it could leak
/// allocations or resources, so care must be taken not to overwrite an object
/// that should be dropped.
///
/// location pointed to by `dst`.
///
/// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been `read` from.
+/// memory that has previously been [`read`] from.
+///
+/// [`read`]: ./fn.read.html
+///
+/// # Safety
///
-/// The pointer must be aligned; use `write_unaligned` if that is not the case.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dst` must point to valid memory.
+///
+/// * `dst` must be properly aligned. Use [`write_unaligned`] if this is not the
+/// case.
+///
+/// [`write_unaligned`]: ./fn.write_unaligned.html
///
/// # Examples
///
/// assert_eq!(std::ptr::read(y), 12);
/// }
/// ```
+///
+/// Manually implement [`mem::swap`]:
+///
+/// ```
+/// use std::ptr;
+///
+/// fn swap<T>(a: &mut T, b: &mut T) {
+/// unsafe {
+/// let tmp = ptr::read(a);
+/// ptr::copy_nonoverlapping(b, a, 1);
+/// ptr::write(b, tmp);
+/// }
+/// }
+///
+/// let mut foo = "foo".to_owned();
+/// let mut bar = "bar".to_owned();
+///
+/// swap(&mut foo, &mut bar);
+///
+/// assert_eq!(foo, "bar");
+/// assert_eq!(bar, "foo");
+/// ```
+///
+/// [`mem::swap`]: ../mem/fn.swap.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn write<T>(dst: *mut T, src: T) {
/// Overwrites a memory location with the given value without reading or
/// dropping the old value.
///
-/// Unlike `write`, the pointer may be unaligned.
-///
-/// # Safety
+/// Unlike [`write`], the pointer may be unaligned.
///
-/// This operation is marked unsafe because it accepts a raw pointer.
-///
-/// It does not drop the contents of `dst`. This is safe, but it could leak
-/// allocations or resources, so care must be taken not to overwrite an object
-/// that should be dropped.
+/// `write_unaligned` does not drop the contents of `dst`. This is safe, but it
+/// could leak allocations or resources, so care must be taken not to overwrite
+/// an object that should be dropped.
///
/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
/// location pointed to by `dst`.
///
/// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been `read` from.
+/// memory that has previously been read with [`read_unaligned`].
+///
+/// [`write`]: ./fn.write.html
+/// [`read_unaligned`]: ./fn.read_unaligned.html
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `dst` must point to valid memory.
///
/// # Examples
///
-/// Basic usage:
+/// Access fields in a packed struct:
///
/// ```
-/// let mut x = 0;
-/// let y = &mut x as *mut i32;
-/// let z = 12;
+/// use std::{mem, ptr};
+///
+/// #[repr(packed, C)]
+/// #[derive(Default)]
+/// struct Packed {
+/// _padding: u8,
+/// unaligned: u32,
+/// }
+///
+/// let v = 0x01020304;
+/// let mut x: Packed = unsafe { mem::zeroed() };
///
/// unsafe {
-/// std::ptr::write_unaligned(y, z);
-/// assert_eq!(std::ptr::read_unaligned(y), 12);
+/// // Take a reference to a 32-bit integer which is not aligned.
+/// let unaligned = &mut x.unaligned;
+///
+/// // Dereferencing normally will emit an unaligned store instruction,
+/// // causing undefined behavior.
+/// // *unaligned = v; // ERROR
+///
+/// // Instead, use `write_unaligned` to write improperly aligned values.
+/// ptr::write_unaligned(unaligned, v);
/// }
-/// ```
+///
+/// // Accessing unaligned values directly is safe.
+/// assert!(x.unaligned == v);
#[inline]
#[stable(feature = "ptr_unaligned", since = "1.17.0")]
pub unsafe fn write_unaligned<T>(dst: *mut T, src: T) {
/// to not be elided or reordered by the compiler across other volatile
/// operations.
///
+/// Memory read with `read_volatile` should almost always be written to using
+/// [`write_volatile`].
+///
+/// [`write_volatile`]: ./fn.write_volatile.html
+///
/// # Notes
///
/// Rust does not currently have a rigorously and formally defined memory model,
///
/// # Safety
///
-/// Beyond accepting a raw pointer, this is unsafe because it semantically
-/// moves the value out of `src` without preventing further usage of `src`.
-/// If `T` is not `Copy`, then care must be taken to ensure that the value at
-/// `src` is not used before the data is overwritten again (e.g. with `write`,
-/// `write_bytes`, or `copy`). Note that `*src = foo` counts as a use
-/// because it will attempt to drop the value previously at `*src`.
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `src` must point to valid, initialized memory.
+///
+/// * `src` must be properly aligned.
+///
+/// Like [`read`], `read_volatile` creates a bitwise copy of the pointed-to
+/// object, regardless of whether `T` is [`Copy`]. Using both values can cause
+/// undefined behavior. However, storing non-[`Copy`] data in I/O memory is
+/// almost certainly incorrect.
+///
+/// [`Copy`]: ../marker/trait.Copy.html
+/// [`read`]: ./fn.read.html
///
/// # Examples
///
/// to not be elided or reordered by the compiler across other volatile
/// operations.
///
+/// Memory written with `write_volatile` should almost always be read from using
+/// [`read_volatile`].
+///
+/// `write_volatile` does not drop the contents of `dst`. This is safe, but it
+/// could leak allocations or resources, so care must be taken not to overwrite
+/// an object that should be dropped.
+///
+/// Additionally, it does not drop `src`. Semantically, `src` is moved into the
+/// location pointed to by `dst`.
+///
+/// [`read_volatile`]: ./fn.read_volatile.html
+///
/// # Notes
///
/// Rust does not currently have a rigorously and formally defined memory model,
///
/// # Safety
///
-/// This operation is marked unsafe because it accepts a raw pointer.
+/// Behavior is undefined if any of the following conditions are violated:
///
-/// It does not drop the contents of `dst`. This is safe, but it could leak
-/// allocations or resources, so care must be taken not to overwrite an object
-/// that should be dropped.
+/// * `dst` must point to valid memory.
///
-/// This is appropriate for initializing uninitialized memory, or overwriting
-/// memory that has previously been `read` from.
+/// * `dst` must be properly aligned.
///
/// # Examples
///
//! A support library for macro authors when defining new macros.
//!
//! This library, provided by the standard distribution, provides the types
-//! consumed in the interfaces of procedurally defined macro definitions.
-//! Currently the primary use of this crate is to provide the ability to define
-//! new custom derive modes through `#[proc_macro_derive]`.
+//! consumed in the interfaces of procedurally defined macro definitions such as
+//! function-like macros `#[proc_macro]`, macro attribures `#[proc_macro_attribute]` and
+//! custom derive attributes`#[proc_macro_derive]`.
//!
-//! Note that this crate is intentionally very bare-bones currently. The main
-//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
-//! implementations, indicating that it can only go to and come from a string.
+//! Note that this crate is intentionally bare-bones currently.
//! This functionality is intended to be expanded over time as more surface
//! area for macro authors is stabilized.
//!
use syntax::ast;
use syntax::errors::DiagnosticBuilder;
use syntax::parse::{self, token};
-use syntax::symbol::Symbol;
+use syntax::symbol::{keywords, Symbol};
use syntax::tokenstream;
-use syntax::parse::lexer::comments;
+use syntax::parse::lexer::{self, comments};
use syntax_pos::{FileMap, Pos, SyntaxContext, FileName};
use syntax_pos::hygiene::Mark;
/// The main type provided by this crate, representing an abstract stream of
-/// tokens.
+/// tokens, or, more specifically, a sequence of token trees.
+/// The type provide interfaces for iterating over those token trees and, conversely,
+/// collecting a number of token trees into one stream.
///
-/// This is both the input and output of `#[proc_macro_derive]` definitions.
-/// Currently it's required to be a list of valid Rust items, but this
-/// restriction may be lifted in the future.
+/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
+/// and `#[proc_macro_derive]` definitions.
///
/// The API of this type is intentionally bare-bones, but it'll be expanded over
/// time!
#[derive(Clone)]
pub struct TokenStream(tokenstream::TokenStream);
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl !Send for TokenStream {}
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl !Sync for TokenStream {}
/// Error returned from `TokenStream::from_str`.
_inner: (),
}
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl !Send for LexError {}
-#[unstable(feature = "proc_macro", issue = "38356")]
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl !Sync for LexError {}
impl TokenStream {
- /// Returns an empty `TokenStream`.
+ /// Returns an empty `TokenStream` containing no token trees.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn empty() -> TokenStream {
TokenStream(tokenstream::TokenStream::empty())
}
}
+/// Attempts to break the string into tokens and parse those tokens into a token stream.
+/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters
+/// or characters not existing in the language.
+///
+/// NOTE: Some errors may cause panics instead of returning `LexError`. We reserve the right to
+/// change these errors into `LexError`s later.
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl FromStr for TokenStream {
type Err = LexError;
}
}
+/// Prints the token stream as a string that is supposed to be losslessly convertible back
+/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s
+/// with `Delimiter::None` delimiters and negative numeric literals.
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl fmt::Display for TokenStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
+/// Prints token in a form convenient for debugging.
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl fmt::Debug for TokenStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
+/// Creates a token stream containing a single token tree.
#[unstable(feature = "proc_macro", issue = "38356")]
impl From<TokenTree> for TokenStream {
fn from(tree: TokenTree) -> TokenStream {
}
}
+/// Collects a number of token trees into a single stream.
#[unstable(feature = "proc_macro", issue = "38356")]
impl iter::FromIterator<TokenTree> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenTree>>(trees: I) -> Self {
}
}
-#[unstable(feature = "proc_macro", issue = "38356")]
+/// A "flattening" operation on token streams, collects token trees
+/// from multiple token streams into a single stream.
+#[stable(feature = "proc_macro_lib", since = "1.15.0")]
impl iter::FromIterator<TokenStream> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenStream>>(streams: I) -> Self {
let mut builder = tokenstream::TokenStreamBuilder::new();
}
}
-/// Implementation details for the `TokenTree` type, such as iterators.
+/// Public implementation details for the `TokenStream` type, such as iterators.
#[unstable(feature = "proc_macro", issue = "38356")]
pub mod token_stream {
use syntax::tokenstream;
use {TokenTree, TokenStream, Delimiter};
- /// An iterator over `TokenTree`s.
+ /// An iterator over `TokenStream`'s `TokenTree`s.
+ /// The iteration is "shallow", e.g. the iterator doesn't recurse into delimited groups,
+ /// and returns whole groups as token trees.
#[derive(Clone)]
#[unstable(feature = "proc_macro", issue = "38356")]
pub struct IntoIter {
let next = self.cursor.next_as_stream()?;
Some(TokenTree::from_internal(next, &mut self.stack))
})?;
+ // HACK: The condition "dummy span + group with empty delimiter" represents an AST
+ // fragment approximately converted into a token stream. This may happen, for
+ // example, with inputs to proc macro attributes, including derives. Such "groups"
+ // need to flattened during iteration over stream's token trees.
+ // Eventually this needs to be removed in favor of keeping original token trees
+ // and not doing the roundtrip through AST.
if tree.span().0 == DUMMY_SP {
if let TokenTree::Group(ref group) = tree {
if group.delimiter() == Delimiter::None {
/// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input.
/// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs
-/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`.
+/// the `TokenStream` `[Ident("a"), Punct('+', Alone), Ident("b")]`.
///
/// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term.
/// To quote `$` itself, use `$$`.
}
/// The span of the invocation of the current procedural macro.
+ /// Identifiers created with this span will be resolved as if they were written
+ /// directly at the macro call location (call-site hygiene) and other code
+ /// at the macro call site will be able to refer to them as well.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn call_site() -> Span {
::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site))
diagnostic_method!(help, Level::Help);
}
+/// Prints a span in a form convenient for debugging.
#[unstable(feature = "proc_macro", issue = "38356")]
impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[unstable(feature = "proc_macro", issue = "38356")]
#[derive(Clone)]
pub enum TokenTree {
- /// A delimited tokenstream
+ /// A token stream surrounded by bracket delimiters.
Group(Group),
- /// A unicode identifier
- Term(Term),
- /// A punctuation character (`+`, `,`, `$`, etc.).
- Op(Op),
+ /// An identifier.
+ Ident(Ident),
+ /// A single punctuation character (`+`, `,`, `$`, etc.).
+ Punct(Punct),
/// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc.
Literal(Literal),
}
impl !Sync for TokenTree {}
impl TokenTree {
- /// Returns the span of this token, accessing the `span` method of each of
- /// the internal tokens.
+ /// Returns the span of this tree, delegating to the `span` method of
+ /// the contained token or a delimited stream.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn span(&self) -> Span {
match *self {
TokenTree::Group(ref t) => t.span(),
- TokenTree::Term(ref t) => t.span(),
- TokenTree::Op(ref t) => t.span(),
+ TokenTree::Ident(ref t) => t.span(),
+ TokenTree::Punct(ref t) => t.span(),
TokenTree::Literal(ref t) => t.span(),
}
}
pub fn set_span(&mut self, span: Span) {
match *self {
TokenTree::Group(ref mut t) => t.set_span(span),
- TokenTree::Term(ref mut t) => t.set_span(span),
- TokenTree::Op(ref mut t) => t.set_span(span),
+ TokenTree::Ident(ref mut t) => t.set_span(span),
+ TokenTree::Punct(ref mut t) => t.set_span(span),
TokenTree::Literal(ref mut t) => t.set_span(span),
}
}
}
+/// Prints token treee in a form convenient for debugging.
#[unstable(feature = "proc_macro", issue = "38356")]
impl fmt::Debug for TokenTree {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// so don't bother with an extra layer of indirection
match *self {
TokenTree::Group(ref tt) => tt.fmt(f),
- TokenTree::Term(ref tt) => tt.fmt(f),
- TokenTree::Op(ref tt) => tt.fmt(f),
+ TokenTree::Ident(ref tt) => tt.fmt(f),
+ TokenTree::Punct(ref tt) => tt.fmt(f),
TokenTree::Literal(ref tt) => tt.fmt(f),
}
}
}
#[unstable(feature = "proc_macro", issue = "38356")]
-impl From<Term> for TokenTree {
- fn from(g: Term) -> TokenTree {
- TokenTree::Term(g)
+impl From<Ident> for TokenTree {
+ fn from(g: Ident) -> TokenTree {
+ TokenTree::Ident(g)
}
}
#[unstable(feature = "proc_macro", issue = "38356")]
-impl From<Op> for TokenTree {
- fn from(g: Op) -> TokenTree {
- TokenTree::Op(g)
+impl From<Punct> for TokenTree {
+ fn from(g: Punct) -> TokenTree {
+ TokenTree::Punct(g)
}
}
}
}
+/// Prints the token tree as a string that is supposed to be losslessly convertible back
+/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s
+/// with `Delimiter::None` delimiters and negative numeric literals.
#[unstable(feature = "proc_macro", issue = "38356")]
impl fmt::Display for TokenTree {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
TokenTree::Group(ref t) => t.fmt(f),
- TokenTree::Term(ref t) => t.fmt(f),
- TokenTree::Op(ref t) => t.fmt(f),
+ TokenTree::Ident(ref t) => t.fmt(f),
+ TokenTree::Punct(ref t) => t.fmt(f),
TokenTree::Literal(ref t) => t.fmt(f),
}
}
}
-/// A delimited token stream
+/// A delimited token stream.
///
-/// A `Group` internally contains a `TokenStream` which is delimited by a
-/// `Delimiter`. Groups represent multiple tokens internally and have a `Span`
-/// for the entire stream.
+/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s.
#[derive(Clone, Debug)]
#[unstable(feature = "proc_macro", issue = "38356")]
pub struct Group {
Brace,
/// `[ ... ]`
Bracket,
- /// An implicit delimiter, e.g. `$var`, where $var is `...`.
+ /// `Ø ... Ø`
+ /// An implicit delimiter, that may, for example, appear around tokens coming from a
+ /// "macro variable" `$var`. It is important to preserve operator priorities in cases like
+ /// `$var * 3` where `$var` is `1 + 2`.
+ /// Implicit delimiters may not survive roundtrip of a token stream through a string.
None,
}
impl Group {
- /// Creates a new `group` with the given delimiter and token stream.
+ /// Creates a new `Group` with the given delimiter and token stream.
///
/// This constructor will set the span for this group to
/// `Span::call_site()`. To change the span you can use the `set_span`
}
}
+/// Prints the group as a string that should be losslessly convertible back
+/// into the same group (modulo spans), except for possibly `TokenTree::Group`s
+/// with `Delimiter::None` delimiters.
#[unstable(feature = "proc_macro", issue = "38356")]
impl fmt::Display for Group {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
-/// An `Op` is an operator like `+` or `-`, and only represents one character.
+/// An `Punct` is an single punctuation character like `+`, `-` or `#`.
///
-/// Operators like `+=` are represented as two instance of `Op` with different
+/// Multicharacter operators like `+=` are represented as two instances of `Punct` with different
/// forms of `Spacing` returned.
#[unstable(feature = "proc_macro", issue = "38356")]
-#[derive(Copy, Clone, Debug)]
-pub struct Op {
- op: char,
+#[derive(Clone, Debug)]
+pub struct Punct {
+ ch: char,
spacing: Spacing,
span: Span,
}
#[unstable(feature = "proc_macro", issue = "38356")]
-impl !Send for Op {}
+impl !Send for Punct {}
#[unstable(feature = "proc_macro", issue = "38356")]
-impl !Sync for Op {}
+impl !Sync for Punct {}
-/// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace.
+/// Whether an `Punct` is followed immediately by another `Punct` or
+/// followed by another token or whitespace.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[unstable(feature = "proc_macro", issue = "38356")]
pub enum Spacing {
- /// e.g. `+` is `Alone` in `+ =`.
+ /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`.
Alone,
- /// e.g. `+` is `Joint` in `+=`.
+ /// E.g. `+` is `Joint` in `+=` or `'#`.
+ /// Additionally, single quote `'` can join with identifiers to form lifetimes `'ident`.
Joint,
}
-impl Op {
- /// Creates a new `Op` from the given character and spacing.
+impl Punct {
+ /// Creates a new `Punct` from the given character and spacing.
+ /// The `ch` argument must be a valid punctuation character permitted by the language,
+ /// otherwise the function will panic.
///
- /// The returned `Op` will have the default span of `Span::call_site()`
+ /// The returned `Punct` will have the default span of `Span::call_site()`
/// which can be further configured with the `set_span` method below.
#[unstable(feature = "proc_macro", issue = "38356")]
- pub fn new(op: char, spacing: Spacing) -> Op {
- Op {
- op: op,
+ pub fn new(ch: char, spacing: Spacing) -> Punct {
+ const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^',
+ '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\''];
+ if !LEGAL_CHARS.contains(&ch) {
+ panic!("unsupported character `{:?}`", ch)
+ }
+ Punct {
+ ch: ch,
spacing: spacing,
span: Span::call_site(),
}
}
- /// Returns the character this operation represents, for example `'+'`
+ /// Returns the value of this punctuation character as `char`.
#[unstable(feature = "proc_macro", issue = "38356")]
- pub fn op(&self) -> char {
- self.op
+ pub fn as_char(&self) -> char {
+ self.ch
}
- /// Returns the spacing of this operator, indicating whether it's a joint
- /// operator with more operators coming next in the token stream or an
- /// `Alone` meaning that the operator has ended.
+ /// Returns the spacing of this punctuation character, indicating whether it's immediately
+ /// followed by another `Punct` in the token stream, so they can potentially be combined into
+ /// a multicharacter operator (`Joint`), or it's followed by some other token or whitespace
+ /// (`Alone`) so the operator has certainly ended.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn spacing(&self) -> Spacing {
self.spacing
}
- /// Returns the span for this operator character
+ /// Returns the span for this punctuation character.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn span(&self) -> Span {
self.span
}
- /// Configure the span for this operator's character
+ /// Configure the span for this punctuation character.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn set_span(&mut self, span: Span) {
self.span = span;
}
}
+/// Prints the punctuation character as a string that should be losslessly convertible
+/// back into the same character.
#[unstable(feature = "proc_macro", issue = "38356")]
-impl fmt::Display for Op {
+impl fmt::Display for Punct {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
TokenStream::from(TokenTree::from(self.clone())).fmt(f)
}
}
-/// An interned string.
-#[derive(Copy, Clone, Debug)]
+/// An identifier (`ident`).
+#[derive(Clone, Debug)]
#[unstable(feature = "proc_macro", issue = "38356")]
-pub struct Term {
+pub struct Ident {
sym: Symbol,
span: Span,
+ is_raw: bool,
}
#[unstable(feature = "proc_macro", issue = "38356")]
-impl !Send for Term {}
+impl !Send for Ident {}
#[unstable(feature = "proc_macro", issue = "38356")]
-impl !Sync for Term {}
+impl !Sync for Ident {}
-impl Term {
- /// Creates a new `Term` with the given `string` as well as the specified
+impl Ident {
+ /// Creates a new `Ident` with the given `string` as well as the specified
/// `span`.
+ /// The `string` argument must be a valid identifier permitted by the
+ /// language, otherwise the function will panic.
///
/// Note that `span`, currently in rustc, configures the hygiene information
- /// for this identifier. As of this time `Span::call_site()` explicitly
- /// opts-in to **non-hygienic** information (aka copy/pasted code) while
- /// spans like `Span::def_site()` will opt-in to hygienic information,
- /// meaning that code at the call site of the macro can't access this
- /// identifier.
+ /// for this identifier.
+ ///
+ /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene
+ /// meaning that identifiers created with this span will be resolved as if they were written
+ /// directly at the location of the macro call, and other code at the macro call site will be
+ /// able to refer to them as well.
+ ///
+ /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene
+ /// meaning that identifiers created with this span will be resolved at the location of the
+ /// macro definition and other code at the macro call site will not be able to refer to them.
///
/// Due to the current importance of hygiene this constructor, unlike other
/// tokens, requires a `Span` to be specified at construction.
#[unstable(feature = "proc_macro", issue = "38356")]
- pub fn new(string: &str, span: Span) -> Term {
- Term {
+ pub fn new(string: &str, span: Span) -> Ident {
+ if !lexer::is_valid_ident(string) {
+ panic!("`{:?}` is not a valid identifier", string)
+ }
+ Ident {
sym: Symbol::intern(string),
span,
+ is_raw: false,
}
}
- // FIXME: Remove this, do not stabilize
- /// Get a reference to the interned string.
+ /// Same as `Ident::new`, but creates a raw identifier (`r#ident`).
#[unstable(feature = "proc_macro", issue = "38356")]
- pub fn as_str(&self) -> &str {
- unsafe { &*(&*self.sym.as_str() as *const str) }
+ pub fn new_raw(string: &str, span: Span) -> Ident {
+ let mut ident = Ident::new(string, span);
+ if ident.sym == keywords::Underscore.name() ||
+ token::is_path_segment_keyword(ast::Ident::with_empty_ctxt(ident.sym)) {
+ panic!("`{:?}` is not a valid raw identifier", string)
+ }
+ ident.is_raw = true;
+ ident
}
- /// Returns the span of this `Term`, encompassing the entire string returned
+ /// Returns the span of this `Ident`, encompassing the entire string returned
/// by `as_str`.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn span(&self) -> Span {
self.span
}
- /// Configures the span of this `Term`, possibly changing hygiene
- /// information.
+ /// Configures the span of this `Ident`, possibly changing its hygiene context.
#[unstable(feature = "proc_macro", issue = "38356")]
pub fn set_span(&mut self, span: Span) {
self.span = span;
}
}
+/// Prints the identifier as a string that should be losslessly convertible
+/// back into the same identifier.
#[unstable(feature = "proc_macro", issue = "38356")]
-impl fmt::Display for Term {
+impl fmt::Display for Ident {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.is_raw {
+ f.write_str("r#")?;
+ }
self.sym.as_str().fmt(f)
}
}
-/// A literal character (`'a'`), string (`"hello"`), a number (`2.3`), etc.
+/// A literal string (`"hello"`), byte string (`b"hello"`),
+/// character (`'a'`), byte character (`b'a'`), an integer or floating point number
+/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`).
+/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s.
#[derive(Clone, Debug)]
#[unstable(feature = "proc_macro", issue = "38356")]
pub struct Literal {
/// This function will create an integer like `1u32` where the integer
/// value specified is the first part of the token and the integral is
/// also suffixed at the end.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
///
/// Literals created through this method have the `Span::call_site()`
/// span by default, which can be configured with the `set_span` method
/// specified on this token, meaning that invocations like
/// `Literal::i8_unsuffixed(1)` are equivalent to
/// `Literal::u32_unsuffixed(1)`.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
///
/// Literals created through this method have the `Span::call_site()`
/// span by default, which can be configured with the `set_span` method
/// This constructor is similar to those like `Literal::i8_unsuffixed` where
/// the float's value is emitted directly into the token but no suffix is
/// used, so it may be inferred to be a `f64` later in the compiler.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
///
/// # Panics
///
/// specified is the preceding part of the token and `f32` is the suffix of
/// the token. This token will always be inferred to be an `f32` in the
/// compiler.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
///
/// # Panics
///
/// This constructor is similar to those like `Literal::i8_unsuffixed` where
/// the float's value is emitted directly into the token but no suffix is
/// used, so it may be inferred to be a `f64` later in the compiler.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
///
/// # Panics
///
/// specified is the preceding part of the token and `f64` is the suffix of
/// the token. This token will always be inferred to be an `f64` in the
/// compiler.
+ /// Literals created from negative numbers may not survive rountrips through
+ /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal).
///
/// # Panics
///
}
}
+/// Prints the literal as a string that should be losslessly convertible
+/// back into the same literal (except for possible rounding for floating point literals).
#[unstable(feature = "proc_macro", issue = "38356")]
impl fmt::Display for Literal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
})
}
macro_rules! op {
- ($a:expr) => (tt!(Op::new($a, op_kind)));
+ ($a:expr) => (tt!(Punct::new($a, op_kind)));
($a:expr, $b:expr) => ({
- stack.push(tt!(Op::new($b, op_kind)));
- tt!(Op::new($a, Spacing::Joint))
+ stack.push(tt!(Punct::new($b, op_kind)));
+ tt!(Punct::new($a, Spacing::Joint))
});
($a:expr, $b:expr, $c:expr) => ({
- stack.push(tt!(Op::new($c, op_kind)));
- stack.push(tt!(Op::new($b, Spacing::Joint)));
- tt!(Op::new($a, Spacing::Joint))
+ stack.push(tt!(Punct::new($c, op_kind)));
+ stack.push(tt!(Punct::new($b, Spacing::Joint)));
+ tt!(Punct::new($a, Spacing::Joint))
})
}
Pound => op!('#'),
Dollar => op!('$'),
Question => op!('?'),
+ SingleQuote => op!('\''),
- Ident(ident, false) | Lifetime(ident) => {
- tt!(Term::new(&ident.name.as_str(), Span(span)))
+ Ident(ident, false) => {
+ tt!(self::Ident::new(&ident.name.as_str(), Span(span)))
}
Ident(ident, true) => {
- tt!(Term::new(&format!("r#{}", ident), Span(span)))
+ tt!(self::Ident::new_raw(&ident.name.as_str(), Span(span)))
+ }
+ Lifetime(ident) => {
+ let ident = ident.without_first_quote();
+ stack.push(tt!(self::Ident::new(&ident.name.as_str(), Span(span))));
+ tt!(Punct::new('\'', Spacing::Joint))
}
Literal(lit, suffix) => tt!(self::Literal { lit, suffix, span: Span(span) }),
DocComment(c) => {
let style = comments::doc_comment_style(&c.as_str());
let stripped = comments::strip_doc_comment_decoration(&c.as_str());
let stream = vec![
- tt!(Term::new("doc", Span(span))),
- tt!(Op::new('=', Spacing::Alone)),
+ tt!(self::Ident::new("doc", Span(span))),
+ tt!(Punct::new('=', Spacing::Alone)),
tt!(self::Literal::string(&stripped)),
].into_iter().collect();
stack.push(tt!(Group::new(Delimiter::Bracket, stream)));
if style == ast::AttrStyle::Inner {
- stack.push(tt!(Op::new('!', Spacing::Alone)));
+ stack.push(tt!(Punct::new('!', Spacing::Alone)));
}
- tt!(Op::new('#', Spacing::Alone))
+ tt!(Punct::new('#', Spacing::Alone))
}
Interpolated(_) => {
use syntax::parse::token::*;
use syntax::tokenstream::{TokenTree, Delimited};
- let (op, kind, span) = match self {
- self::TokenTree::Op(tt) => (tt.op(), tt.spacing(), tt.span()),
+ let (ch, kind, span) = match self {
+ self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()),
self::TokenTree::Group(tt) => {
return TokenTree::Delimited(tt.span.0, Delimited {
delim: tt.delimiter.to_internal(),
tts: tt.stream.0.into(),
}).into();
},
- self::TokenTree::Term(tt) => {
- let ident = ast::Ident::new(tt.sym, tt.span.0);
- let sym_str = tt.sym.to_string();
- let token = if sym_str.starts_with("'") {
- Lifetime(ident)
- } else if sym_str.starts_with("r#") {
- let name = Symbol::intern(&sym_str[2..]);
- let ident = ast::Ident::new(name, ident.span);
- Ident(ident, true)
- } else {
- Ident(ident, false)
- };
+ self::TokenTree::Ident(tt) => {
+ let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw);
return TokenTree::Token(tt.span.0, token).into();
}
self::TokenTree::Literal(self::Literal {
}
};
- let token = match op {
+ let token = match ch {
'=' => Eq,
'<' => Lt,
'>' => Gt,
'#' => Pound,
'$' => Dollar,
'?' => Question,
- _ => panic!("unsupported character {}", op),
+ '\'' => SingleQuote,
+ _ => unreachable!(),
};
let tree = TokenTree::Token(span.0, token);
#[unstable(feature = "proc_macro_internals", issue = "27812")]
#[doc(hidden)]
pub mod __internal {
- pub use quote::{LiteralKind, Quoter, unquote};
+ pub use quote::{LiteralKind, SpannedSymbol, Quoter, unquote};
use std::cell::Cell;
//! This quasiquoter uses macros 2.0 hygiene to reliably access
//! items from `proc_macro`, to build a `proc_macro::TokenStream`.
-use {Delimiter, Literal, Spacing, Span, Term, Op, Group, TokenStream, TokenTree};
+use {Delimiter, Literal, Spacing, Span, Ident, Punct, Group, TokenStream, TokenTree};
use syntax::ext::base::{ExtCtxt, ProcMacro};
use syntax::parse::token;
+use syntax::symbol::Symbol;
use syntax::tokenstream;
pub struct Quoter;
}
macro_rules! quote_tok {
- (,) => { tt2ts!(Op::new(',', Spacing::Alone)) };
- (.) => { tt2ts!(Op::new('.', Spacing::Alone)) };
- (:) => { tt2ts!(Op::new(':', Spacing::Alone)) };
- (|) => { tt2ts!(Op::new('|', Spacing::Alone)) };
+ (,) => { tt2ts!(Punct::new(',', Spacing::Alone)) };
+ (.) => { tt2ts!(Punct::new('.', Spacing::Alone)) };
+ (:) => { tt2ts!(Punct::new(':', Spacing::Alone)) };
+ (|) => { tt2ts!(Punct::new('|', Spacing::Alone)) };
(::) => {
[
- TokenTree::from(Op::new(':', Spacing::Joint)),
- TokenTree::from(Op::new(':', Spacing::Alone)),
+ TokenTree::from(Punct::new(':', Spacing::Joint)),
+ TokenTree::from(Punct::new(':', Spacing::Alone)),
].iter()
.cloned()
.map(|mut x| {
})
.collect::<TokenStream>()
};
- (!) => { tt2ts!(Op::new('!', Spacing::Alone)) };
- (<) => { tt2ts!(Op::new('<', Spacing::Alone)) };
- (>) => { tt2ts!(Op::new('>', Spacing::Alone)) };
- (_) => { tt2ts!(Op::new('_', Spacing::Alone)) };
+ (!) => { tt2ts!(Punct::new('!', Spacing::Alone)) };
+ (<) => { tt2ts!(Punct::new('<', Spacing::Alone)) };
+ (>) => { tt2ts!(Punct::new('>', Spacing::Alone)) };
+ (_) => { tt2ts!(Punct::new('_', Spacing::Alone)) };
(0) => { tt2ts!(Literal::i8_unsuffixed(0)) };
- (&) => { tt2ts!(Op::new('&', Spacing::Alone)) };
- ($i:ident) => { tt2ts!(Term::new(stringify!($i), Span::def_site())) };
+ (&) => { tt2ts!(Punct::new('&', Spacing::Alone)) };
+ ($i:ident) => { tt2ts!(Ident::new(stringify!($i), Span::def_site())) };
}
macro_rules! quote_tree {
if after_dollar {
after_dollar = false;
match tree {
- TokenTree::Term(_) => {
+ TokenTree::Ident(_) => {
let tree = TokenStream::from(tree);
return Some(quote!(::__internal::unquote(&(unquote tree)),));
}
- TokenTree::Op(ref tt) if tt.op() == '$' => {}
+ TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
_ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
}
- } else if let TokenTree::Op(tt) = tree {
- if tt.op() == '$' {
+ } else if let TokenTree::Punct(ref tt) = tree {
+ if tt.as_char() == '$' {
after_dollar = true;
return None;
}
impl Quote for TokenTree {
fn quote(self) -> TokenStream {
match self {
- TokenTree::Op(tt) => quote!(::TokenTree::Op( (quote tt) )),
+ TokenTree::Punct(tt) => quote!(::TokenTree::Punct( (quote tt) )),
TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )),
- TokenTree::Term(tt) => quote!(::TokenTree::Term( (quote tt) )),
+ TokenTree::Ident(tt) => quote!(::TokenTree::Ident( (quote tt) )),
TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )),
}
}
}
}
-impl Quote for Op {
+impl Quote for Punct {
fn quote(self) -> TokenStream {
- quote!(::Op::new((quote self.op()), (quote self.spacing())))
+ quote!(::Punct::new((quote self.as_char()), (quote self.spacing())))
}
}
-impl Quote for Term {
+impl Quote for Ident {
fn quote(self) -> TokenStream {
- quote!(::Term::new((quote self.sym.as_str()), (quote self.span())))
+ quote!(::Ident::new((quote self.sym.as_str()), (quote self.span())))
}
}
macro_rules! literals {
($($i:ident),*; $($raw:ident),*) => {
+ pub struct SpannedSymbol {
+ sym: Symbol,
+ span: Span,
+ }
+
+ impl SpannedSymbol {
+ pub fn new(string: &str, span: Span) -> SpannedSymbol {
+ SpannedSymbol { sym: Symbol::intern(string), span }
+ }
+ }
+
+ impl Quote for SpannedSymbol {
+ fn quote(self) -> TokenStream {
+ quote!(::__internal::SpannedSymbol::new((quote self.sym.as_str()),
+ (quote self.span)))
+ }
+ }
+
pub enum LiteralKind {
$($i,)*
$($raw(u16),)*
}
impl LiteralKind {
- pub fn with_contents_and_suffix(self, contents: Term, suffix: Option<Term>)
- -> Literal {
+ pub fn with_contents_and_suffix(self, contents: SpannedSymbol,
+ suffix: Option<SpannedSymbol>) -> Literal {
let sym = contents.sym;
let suffix = suffix.map(|t| t.sym);
match self {
}
impl Literal {
- fn kind_contents_and_suffix(self) -> (LiteralKind, Term, Option<Term>) {
+ fn kind_contents_and_suffix(self) -> (LiteralKind, SpannedSymbol, Option<SpannedSymbol>)
+ {
let (kind, contents) = match self.lit {
$(token::Lit::$i(contents) => (LiteralKind::$i, contents),)*
$(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)*
};
- let suffix = self.suffix.map(|sym| Term::new(&sym.as_str(), self.span()));
- (kind, Term::new(&contents.as_str(), self.span()), suffix)
+ let suffix = self.suffix.map(|sym| SpannedSymbol::new(&sym.as_str(), self.span()));
+ (kind, SpannedSymbol::new(&contents.as_str(), self.span()), suffix)
}
}
fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
match expr.node {
- hir::ExprBlock(ref blk) => {
+ hir::ExprBlock(ref blk, _) => {
let blk_exit = self.block(&blk, pred);
self.add_ast_node(expr.hir_id.local_id, &[blk_exit])
}
scope_cf_kind: ScopeCfKind) -> (region::Scope, CFGIndex) {
match destination.target_id {
- hir::ScopeTarget::Block(block_expr_id) => {
+ Ok(loop_id) => {
for b in &self.breakable_block_scopes {
- if b.block_expr_id == self.tcx.hir.node_to_hir_id(block_expr_id).local_id {
- let scope_id = self.tcx.hir.node_to_hir_id(block_expr_id).local_id;
+ if b.block_expr_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
+ let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id;
return (region::Scope::Node(scope_id), match scope_cf_kind {
ScopeCfKind::Break => b.break_index,
ScopeCfKind::Continue => bug!("can't continue to block"),
});
}
}
- span_bug!(expr.span, "no block expr for id {}", block_expr_id);
- }
- hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => {
for l in &self.loop_scopes {
if l.loop_id == self.tcx.hir.node_to_hir_id(loop_id).local_id {
let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id;
});
}
}
- span_bug!(expr.span, "no loop scope for id {}", loop_id);
+ span_bug!(expr.span, "no scope for id {}", loop_id);
}
- hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
- span_bug!(expr.span, "loop scope error: {}", err),
+ Err(err) => span_bug!(expr.span, "scope error: {}", err),
}
}
}
expression.span,
expression.id)
}
- ExprBlock(ref block) => visitor.visit_block(block),
+ ExprBlock(ref block, ref opt_label) => {
+ walk_list!(visitor, visit_label, opt_label);
+ visitor.visit_block(block);
+ }
ExprAssign(ref left_hand_expression, ref right_hand_expression) => {
visitor.visit_expr(right_hand_expression);
visitor.visit_expr(left_hand_expression)
if let Some(ref label) = destination.label {
visitor.visit_label(label);
match destination.target_id {
- ScopeTarget::Block(node_id) |
- ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
- visitor.visit_def_mention(Def::Label(node_id)),
- ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
+ Ok(node_id) => visitor.visit_def_mention(Def::Label(node_id)),
+ Err(_) => {},
};
}
walk_list!(visitor, visit_expr, opt_expr);
if let Some(ref label) = destination.label {
visitor.visit_label(label);
match destination.target_id {
- ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"),
- ScopeTarget::Loop(LoopIdResult::Ok(node_id)) =>
- visitor.visit_def_mention(Def::Label(node_id)),
- ScopeTarget::Loop(LoopIdResult::Err(_)) => {},
+ Ok(node_id) => visitor.visit_def_mention(Def::Label(node_id)),
+ Err(_) => {},
};
}
}
fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>) -> hir::Destination {
match destination {
Some((id, label)) => {
- let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
- hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id)
+ let target_id = if let Def::Label(loop_id) = self.expect_full_def(id) {
+ Ok(self.lower_node_id(loop_id).node_id)
} else {
- hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
+ Err(hir::LoopIdError::UnresolvedLabel)
};
hir::Destination {
label: self.lower_label(Some(label)),
- target_id: hir::ScopeTarget::Loop(target),
+ target_id,
}
}
None => {
- let loop_id = self.loop_scopes
+ let target_id = self.loop_scopes
.last()
- .map(|innermost_loop_id| *innermost_loop_id);
+ .map(|innermost_loop_id| *innermost_loop_id)
+ .map(|id| Ok(self.lower_node_id(id).node_id))
+ .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
+ .into();
hir::Destination {
label: None,
- target_id: hir::ScopeTarget::Loop(
- loop_id
- .map(|id| Ok(self.lower_node_id(id).node_id))
- .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
- .into(),
- ),
+ target_id,
}
}
}
return n;
}
assert!(!def_id.is_local());
- let n = self.cstore
- .item_generics_cloned_untracked(def_id, self.sess)
- .regions
- .len();
+ let item_generics =
+ self.cstore.item_generics_cloned_untracked(def_id, self.sess);
+ let n = item_generics.own_counts().lifetimes;
self.type_def_lifetime_params.insert(def_id, n);
n
});
);
block.expr = Some(this.wrap_in_try_constructor(
"from_ok", tail, unstable_span));
- hir::ExprBlock(P(block))
+ hir::ExprBlock(P(block), None)
})
}
ExprKind::Match(ref expr, ref arms) => hir::ExprMatch(
})
})
}
- ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk, false)),
+ ExprKind::Block(ref blk, opt_label) => {
+ hir::ExprBlock(self.lower_block(blk,
+ opt_label.is_some()),
+ self.lower_label(opt_label))
+ }
ExprKind::Assign(ref el, ref er) => {
hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
let destination = if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
label: None,
- target_id: hir::ScopeTarget::Loop(
- Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
- ),
+ target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
}
} else {
self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
hir::ExprAgain(if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
label: None,
- target_id: hir::ScopeTarget::Loop(
- Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
- ),
+ target_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
}
} else {
self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
hir::ExprBreak(
hir::Destination {
label: None,
- target_id: hir::ScopeTarget::Block(catch_node),
+ target_id: Ok(catch_node),
},
Some(from_err_expr),
),
}
fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {
- self.expr(b.span, hir::ExprBlock(b), attrs)
+ self.expr(b.span, hir::ExprBlock(b, None), attrs)
}
fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
pub rules: BlockCheckMode,
pub span: Span,
/// If true, then there may exist `break 'a` values that aim to
- /// break out of this block early. As of this writing, this is not
- /// currently permitted in Rust itself, but it is generated as
- /// part of `catch` statements.
+ /// break out of this block early.
+ /// Used by `'label: {}` blocks and by `catch` statements.
pub targeted_by_break: bool,
/// If true, don't emit return value type errors as the parser had
/// to recover from a parse error so this block will not have an
/// This may also be a generator literal, indicated by the final boolean,
/// in that case there is an GeneratorClause.
ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span, Option<GeneratorMovability>),
- /// A block (`{ ... }`)
- ExprBlock(P<Block>),
+ /// A block (`'label: { ... }`)
+ ExprBlock(P<Block>, Option<Label>),
/// An assignment (`a = foo()`)
ExprAssign(P<Expr>, P<Expr>),
}
}
-// FIXME(cramertj) this should use `Result` once master compiles w/ a vesion of Rust where
-// `Result` implements `Encodable`/`Decodable`
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum LoopIdResult {
- Ok(NodeId),
- Err(LoopIdError),
-}
-impl Into<Result<NodeId, LoopIdError>> for LoopIdResult {
- fn into(self) -> Result<NodeId, LoopIdError> {
- match self {
- LoopIdResult::Ok(ok) => Ok(ok),
- LoopIdResult::Err(err) => Err(err),
- }
- }
-}
-impl From<Result<NodeId, LoopIdError>> for LoopIdResult {
- fn from(res: Result<NodeId, LoopIdError>) -> Self {
- match res {
- Ok(ok) => LoopIdResult::Ok(ok),
- Err(err) => LoopIdResult::Err(err),
- }
- }
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum ScopeTarget {
- Block(NodeId),
- Loop(LoopIdResult),
-}
-
-impl ScopeTarget {
- pub fn opt_id(self) -> Option<NodeId> {
- match self {
- ScopeTarget::Block(node_id) |
- ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => Some(node_id),
- ScopeTarget::Loop(LoopIdResult::Err(_)) => None,
- }
- }
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub struct Destination {
// This is `Some(_)` iff there is an explicit user-specified `label
// These errors are caught and then reported during the diagnostics pass in
// librustc_passes/loops.rs
- pub target_id: ScopeTarget,
+ pub target_id: Result<NodeId, LoopIdError>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
}
}
+ pub fn simple_span(&self) -> Option<Span> {
+ match self.node {
+ PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ref path1, None) |
+ PatKind::Binding(hir::BindingAnnotation::Mutable, _, ref path1, None) =>
+ Some(path1.span),
+ _ => None,
+ }
+ }
+
/// Return variants that are necessary to exist for the pattern to match.
pub fn necessary_variants(&self) -> Vec<DefId> {
let mut variants = vec![];
self.print_else(e.as_ref().map(|e| &**e))
}
// "final else"
- hir::ExprBlock(ref b) => {
+ hir::ExprBlock(ref b, _) => {
self.cbox(indent_unit - 1)?;
self.ibox(0)?;
self.s.word(" else ")?;
// empty box to satisfy the close.
self.ibox(0)?;
}
- hir::ExprBlock(ref blk) => {
+ hir::ExprBlock(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_name(label.name)?;
+ self.word_space(":")?;
+ }
// containing cbox, will be closed by print-block at }
self.cbox(indent_unit)?;
// head-box, will be closed by print-block after {
self.word_space("=>")?;
match arm.body.node {
- hir::ExprBlock(ref blk) => {
+ hir::ExprBlock(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_name(label.name)?;
+ self.word_space(":")?;
+ }
// the block will close the pattern's ibox
self.print_block_unclosed_indent(&blk, indent_unit)?;
match e.node {
hir::ExprIf(..) |
hir::ExprMatch(..) |
- hir::ExprBlock(_) |
+ hir::ExprBlock(..) |
hir::ExprWhile(..) |
hir::ExprLoop(..) => false,
_ => true,
ExprLoop(body, label, loop_src),
ExprMatch(matchee, arms, match_src),
ExprClosure(capture_clause, decl, body_id, span, gen),
- ExprBlock(blk),
+ ExprBlock(blk, label),
ExprAssign(lhs, rhs),
ExprAssignOp(op, lhs, rhs),
ExprField(owner, field_name),
impl_stable_hash_for_spanned!(ast::Ident);
-impl_stable_hash_for!(enum hir::LoopIdResult {
- Ok(node_id),
- Err(loop_id_error)
-});
-
impl_stable_hash_for!(enum hir::LoopIdError {
OutsideLoopScope,
UnlabeledCfInWhileCondition,
UnresolvedLabel
});
-impl_stable_hash_for!(enum hir::ScopeTarget {
- Block(node_id),
- Loop(loop_id_result)
-});
-
impl<'a> HashStable<StableHashingContext<'a>> for ast::Ident {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
token::Token::Pound |
token::Token::Dollar |
token::Token::Question |
+ token::Token::SingleQuote |
token::Token::Whitespace |
token::Token::Comment |
token::Token::Eof => {}
hasher: &mut StableHasher<W>) {
let ty::Generics {
parent,
- parent_regions,
- parent_types,
- ref regions,
- ref types,
+ ref parent_count,
+ ref params,
- // Reverse map to each `TypeParameterDef`'s `index` field, from
+ // Reverse map to each `TypeParamDef`'s `index` field, from
// `def_id.index` (`def_id.krate` is the same as the item's).
- type_param_to_index: _, // Don't hash this
+ param_def_id_to_index: _, // Don't hash this
has_self,
has_late_bound_regions,
} = *self;
parent.hash_stable(hcx, hasher);
- parent_regions.hash_stable(hcx, hasher);
- parent_types.hash_stable(hcx, hasher);
- regions.hash_stable(hcx, hasher);
- types.hash_stable(hcx, hasher);
+ parent_count.hash_stable(hcx, hasher);
+ params.hash_stable(hcx, hasher);
has_self.hash_stable(hcx, hasher);
has_late_bound_regions.hash_stable(hcx, hasher);
}
}
-impl<'a> HashStable<StableHashingContext<'a>>
-for ty::RegionParameterDef {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>) {
- let ty::RegionParameterDef {
- name,
- def_id,
- index,
- pure_wrt_drop
- } = *self;
-
- name.hash_stable(hcx, hasher);
- def_id.hash_stable(hcx, hasher);
- index.hash_stable(hcx, hasher);
- pure_wrt_drop.hash_stable(hcx, hasher);
- }
-}
+impl_stable_hash_for!(enum ty::GenericParamDefKind {
+ Lifetime,
+ Type(ty)
+});
-impl_stable_hash_for!(struct ty::TypeParameterDef {
+impl_stable_hash_for!(struct ty::GenericParamDef {
name,
def_id,
index,
+ pure_wrt_drop,
+ kind
+});
+
+impl_stable_hash_for!(struct ty::TypeParamDef {
has_default,
object_lifetime_default,
- pure_wrt_drop,
synthetic
});
use rustc_data_structures::fx::FxHashMap;
use syntax::ast;
use traits::{self, PredicateObligation};
-use ty::{self, Ty, TyCtxt};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind};
use ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder};
use ty::outlives::Component;
use ty::subst::{Kind, Substs, UnpackedKind};
// `['a]` for the first impl trait and `'b` for the
// second.
let mut least_region = None;
- for region_def in &abstract_type_generics.regions {
- // Find the index of this region in the list of substitutions.
- let index = region_def.index as usize;
-
+ for param in &abstract_type_generics.params {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {}
+ _ => continue
+ }
// Get the value supplied for this region from the substs.
- let subst_arg = anon_defn.substs.region_at(index);
+ let subst_arg = anon_defn.substs.region_at(param.index as usize);
// Compute the least upper bound of it with the other regions.
debug!("constrain_anon_types: least_region={:?}", least_region);
// during trans.
let generics = self.tcx.generics_of(def_id);
- let parent_len = generics.parent_count();
let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map(
|(index, &kind)| {
- if index < parent_len {
+ if index < generics.parent_count {
// Accommodate missing regions in the parent kinds...
self.fold_kind_mapping_missing_regions_to_empty(kind)
} else {
use infer::type_variable::TypeVariableOrigin;
use ty::{self, Ty, TyInfer, TyVar};
use syntax_pos::Span;
+use errors::DiagnosticBuilder;
struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
}
}
- pub fn need_type_info(&self, body_id: Option<hir::BodyId>, span: Span, ty: Ty<'tcx>) {
+ pub fn need_type_info_err(&self,
+ body_id: Option<hir::BodyId>,
+ span: Span,
+ ty: Ty<'tcx>)
+ -> DiagnosticBuilder<'gcx> {
let ty = self.resolve_type_vars_if_possible(&ty);
let name = self.extract_type_name(&ty);
err.span_label(target_span, label_message);
}
- err.emit();
+ err
}
}
use middle::free_region::RegionRelations;
use middle::region;
use middle::lang_items;
-use ty::subst::Substs;
+use ty::subst::{Kind, Substs};
use ty::{TyVid, IntVid, FloatVid};
-use ty::{self, Ty, TyCtxt};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::TypeFoldable;
use ty::relate::RelateResult;
self.next_region_var(RegionVariableOrigin::NLL(origin))
}
- /// Create a region inference variable for the given
- /// region parameter definition.
- pub fn region_var_for_def(&self,
- span: Span,
- def: &ty::RegionParameterDef)
- -> ty::Region<'tcx> {
- self.next_region_var(EarlyBoundRegion(span, def.name))
- }
-
- /// Create a type inference variable for the given
- /// type parameter definition. The substitutions are
- /// for actual parameters that may be referred to by
- /// the default of this type parameter, if it exists.
- /// E.g. `struct Foo<A, B, C = (A, B)>(...);` when
- /// used in a path such as `Foo::<T, U>::new()` will
- /// use an inference variable for `C` with `[T, U]`
- /// as the substitutions for the default, `(T, U)`.
- pub fn type_var_for_def(&self,
- span: Span,
- def: &ty::TypeParameterDef)
- -> Ty<'tcx> {
- let ty_var_id = self.type_variables
- .borrow_mut()
- .new_var(self.universe(),
- false,
- TypeVariableOrigin::TypeParameterDefinition(span, def.name));
-
- self.tcx.mk_var(ty_var_id)
+ pub fn var_for_def(&self,
+ span: Span,
+ param: &ty::GenericParamDef)
+ -> Kind<'tcx> {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ // Create a region inference variable for the given
+ // region parameter definition.
+ self.next_region_var(EarlyBoundRegion(span, param.name)).into()
+ }
+ GenericParamDefKind::Type(_) => {
+ // Create a type inference variable for the given
+ // type parameter definition. The substitutions are
+ // for actual parameters that may be referred to by
+ // the default of this type parameter, if it exists.
+ // E.g. `struct Foo<A, B, C = (A, B)>(...);` when
+ // used in a path such as `Foo::<T, U>::new()` will
+ // use an inference variable for `C` with `[T, U]`
+ // as the substitutions for the default, `(T, U)`.
+ let ty_var_id =
+ self.type_variables
+ .borrow_mut()
+ .new_var(self.universe(),
+ false,
+ TypeVariableOrigin::TypeParameterDefinition(span, param.name));
+
+ self.tcx.mk_var(ty_var_id).into()
+ }
+ }
}
/// Given a set of generics defined on a type or impl, returns a substitution mapping each
span: Span,
def_id: DefId)
-> &'tcx Substs<'tcx> {
- Substs::for_item(self.tcx, def_id, |def, _| {
- self.region_var_for_def(span, def)
- }, |def, _| {
- self.type_var_for_def(span, def)
+ Substs::for_item(self.tcx, def_id, |param, _| {
+ self.var_for_def(span, param)
})
}
#![cfg_attr(stage0, feature(dyn_trait))]
#![feature(from_ref)]
#![feature(fs_read_write)]
+#![feature(iterator_find_map)]
#![cfg_attr(windows, feature(libc))]
-#![feature(macro_lifetime_matcher)]
+#![cfg_attr(stage0, feature(macro_lifetime_matcher))]
#![feature(macro_vis_matcher)]
#![feature(never_type)]
#![feature(exhaustive_patterns)]
self.consume_expr(&rhs);
}
- hir::ExprBlock(ref blk) => {
+ hir::ExprBlock(ref blk, _) => {
self.walk_block(&blk);
}
}
}
- pat.each_binding(|bm, p_id, sp, path1| {
+ pat.each_binding(|bm, p_id, _sp, path1| {
debug!("adding local variable {} from match with bm {:?}",
p_id, bm);
let name = path1.node;
- ir.add_live_node_for_node(p_id, VarDefNode(sp));
+ ir.add_live_node_for_node(p_id, VarDefNode(path1.span));
ir.add_variable(Local(LocalInfo {
id: p_id,
name: name,
// it probably doesn't now)
break_ln: NodeMap<LiveNode>,
cont_ln: NodeMap<LiveNode>,
-
- // mappings from node ID to LiveNode for "breakable" blocks-- currently only `catch {...}`
- breakable_block_ln: NodeMap<LiveNode>,
}
impl<'a, 'tcx> Liveness<'a, 'tcx> {
users: vec![invalid_users(); num_live_nodes * num_vars],
break_ln: NodeMap(),
cont_ln: NodeMap(),
- breakable_block_ln: NodeMap(),
}
}
fn pat_bindings<F>(&mut self, pat: &hir::Pat, mut f: F) where
F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId),
{
- pat.each_binding(|_bm, p_id, sp, _n| {
+ pat.each_binding(|_bm, p_id, sp, n| {
let ln = self.live_node(p_id, sp);
- let var = self.variable(p_id, sp);
- f(self, ln, var, sp, p_id);
+ let var = self.variable(p_id, n.span);
+ f(self, ln, var, n.span, p_id);
})
}
fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode)
-> LiveNode {
if blk.targeted_by_break {
- self.breakable_block_ln.insert(blk.id, succ);
+ self.break_ln.insert(blk.id, succ);
}
let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ);
blk.stmts.iter().rev().fold(succ, |succ, stmt| {
hir::ExprBreak(label, ref opt_expr) => {
// Find which label this break jumps to
let target = match label.target_id {
- hir::ScopeTarget::Block(node_id) =>
- self.breakable_block_ln.get(&node_id),
- hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) =>
- self.break_ln.get(&node_id),
- hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
- span_bug!(expr.span, "loop scope error: {}", err),
+ Ok(node_id) => self.break_ln.get(&node_id),
+ Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
}.map(|x| *x);
// Now that we know the label we're going to,
hir::ExprAgain(label) => {
// Find which label this expr continues to
let sc = match label.target_id {
- hir::ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"),
- hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) => node_id,
- hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
- span_bug!(expr.span, "loop scope error: {}", err),
+ Ok(node_id) => node_id,
+ Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
};
// Now that we know the label we're going to,
succ
}
- hir::ExprBlock(ref blk) => {
+ // Note that labels have been resolved, so we don't need to look
+ // at the label ident
+ hir::ExprBlock(ref blk, _) => {
self.propagate_through_block(&blk, succ)
}
}
},
None => {
this.pat_bindings(&local.pat, |this, ln, var, sp, id| {
- this.warn_about_unused(sp, id, ln, var);
+ let span = local.pat.simple_span().unwrap_or(sp);
+ this.warn_about_unused(span, id, ln, var);
})
}
}
fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
for arg in &body.arguments {
- arg.pat.each_binding(|_bm, p_id, sp, path1| {
+ arg.pat.each_binding(|_bm, p_id, _, path1| {
+ let sp = path1.span;
let var = self.variable(p_id, sp);
// Ignore unused self.
let name = path1.node;
let suggest_underscore_msg = format!("consider using `_{}` instead",
name);
+
if is_assigned {
self.ir.tcx
.lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp,
hir::ExprCast(ref subexpr, _) => {
record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id)
}
- hir::ExprBlock(ref block) => {
+ hir::ExprBlock(ref block, _) => {
if let Some(ref subexpr) = block.expr {
record_rvalue_scope_if_borrow_expr(
visitor, &subexpr, blk_id);
use hir::map::Map;
use hir::ItemLocalId;
use hir::LifetimeName;
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, GenericParamDefKind};
use errors::DiagnosticBuilder;
use rustc::lint;
for lt_def in generics.lifetimes() {
let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, <_def);
if let hir::LifetimeName::Underscore = lt_name {
- // Pick the elided lifetime "definition" if one exists and use it to make an
- // elision scope.
+ // Pick the elided lifetime "definition" if one exists and use it to make
+ // an elision scope.
elision = Some(region);
} else {
lifetimes.insert(lt_name, region);
.entry(def_id)
.or_insert_with(|| {
tcx.generics_of(def_id)
- .types
+ .params
.iter()
- .map(|def| def.object_lifetime_default)
+ .filter_map(|param| {
+ match param.kind {
+ GenericParamDefKind::Type(ty) => {
+ Some(ty.object_lifetime_default)
+ }
+ GenericParamDefKind::Lifetime => None,
+ }
+ })
.collect()
})
};
});
let names_map: FxHashSet<String> = generics
- .regions
+ .params
.iter()
- .map(|l| l.name.to_string())
+ .filter_map(|param| {
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()),
+ _ => None
+ }
+ })
.collect();
let body_ids: FxHashSet<_> = infcx
use syntax::ast;
use session::DiagnosticMessageId;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
+use ty::GenericParamDefKind;
use ty::error::ExpectedFound;
use ty::fast_reject;
use ty::fold::TypeFolder;
flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string())));
}
- for param in generics.types.iter() {
+ for param in generics.params.iter() {
+ let value = match param.kind {
+ GenericParamDefKind::Type(_) => {
+ trait_ref.substs[param.index as usize].to_string()
+ },
+ GenericParamDefKind::Lifetime => continue,
+ };
let name = param.name.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())));
+ flags.push((name, Some(value)));
}
if let Some(true) = self_ty.ty_to_def_id().map(|def_id| def_id.is_local()) {
self.tcx.lang_items().sized_trait()
.map_or(false, |sized_id| sized_id == trait_ref.def_id())
{
- self.need_type_info(body_id, span, self_ty);
+ self.need_type_info_err(body_id, span, self_ty).emit();
} else {
let mut err = struct_span_err!(self.tcx.sess,
span, E0283,
// Same hacky approach as above to avoid deluging user
// with error messages.
if !ty.references_error() && !self.tcx.sess.has_errors() {
- self.need_type_info(body_id, span, ty);
+ self.need_type_info_err(body_id, span, ty).emit();
}
}
let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder();
// both must be type variables, or the other would've been instantiated
assert!(a.is_ty_var() && b.is_ty_var());
- self.need_type_info(body_id,
- obligation.cause.span,
- a);
+ self.need_type_info_err(body_id,
+ obligation.cause.span,
+ a).emit();
}
}
}
ObligationCauseCode::ReturnType(_) |
ObligationCauseCode::BlockTailExpression(_) => (),
+ ObligationCauseCode::TrivialBound => {
+ err.help("see issue #48214");
+ if tcx.sess.opts.unstable_features.is_nightly_build() {
+ err.help("add #![feature(trivial_bounds)] to the \
+ crate attributes to enable",
+ );
+ }
+ }
}
}
ty::Predicate::Trait(ref data) => {
let trait_obligation = obligation.with(data.clone());
- if data.is_global() {
+ if data.is_global() && !data.has_late_bound_regions() {
// no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too.
if selcx.infcx().predicate_must_hold(&obligation) {
use middle::region;
use middle::const_val::ConstEvalErr;
use ty::subst::Substs;
-use ty::{self, AdtKind, Slice, Ty, TyCtxt, TypeFoldable, ToPredicate};
+use ty::{self, AdtKind, Slice, Ty, TyCtxt, GenericParamDefKind, TypeFoldable, ToPredicate};
use ty::error::{ExpectedFound, TypeError};
use infer::{InferCtxt};
/// Block implicit return
BlockTailExpression(ast::NodeId),
+
+ /// #[feature(trivial_bounds)] is not enabled
+ TrivialBound,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
let predicates: Vec<_> =
util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec())
- .filter(|p| !p.is_global()) // (*)
.collect();
- // (*) Any predicate like `i32: Trait<u32>` or whatever doesn't
- // need to be in the *environment* to be proven, so screen those
- // out. This is important for the soundness of inter-fn
- // caching. Note though that we should probably check that these
- // predicates hold at the point where the environment is
- // constructed, but I am not currently doing so out of laziness.
- // -nmatsakis
-
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
predicates);
// the method may have some early-bound lifetimes, add
// regions for those
let substs = trait_ref.map_bound(|trait_ref| {
- Substs::for_item(
- tcx, def_id,
- |_, _| tcx.types.re_erased,
- |def, _| trait_ref.substs.type_for_def(def))
+ Substs::for_item(tcx, def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
+ GenericParamDefKind::Type(_) => {
+ trait_ref.substs[param.index as usize]
+ }
+ }
+ })
});
// the trait type may have higher-ranked lifetimes in it;
}
// We can't monomorphize things like `fn foo<A>(...)`.
- if !self.generics_of(method.def_id).types.is_empty() {
+ if self.generics_of(method.def_id).own_counts().types != 0 {
return Some(MethodViolationCode::Generic);
}
}
pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- trait_def_id: DefId)
- -> bool {
+ trait_def_id: DefId) -> bool {
tcx.object_safety_violations(trait_def_id).is_empty()
}
use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId;
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, GenericParamDefKind};
use util::common::ErrorReported;
use util::nodemap::FxHashMap;
let name = tcx.item_name(trait_def_id);
let generics = tcx.generics_of(trait_def_id);
let parser = Parser::new(&self.0);
- let types = &generics.types;
let mut result = Ok(());
for token in parser {
match token {
// `{ThisTraitsName}` is allowed
Position::ArgumentNamed(s) if s == name => (),
// So is `{A}` if A is a type parameter
- Position::ArgumentNamed(s) => match types.iter().find(|t| {
- t.name == s
+ Position::ArgumentNamed(s) => match generics.params.iter().find(|param| {
+ param.name == s
}) {
Some(_) => (),
None => {
span_err!(tcx.sess, span, E0230,
- "there is no type parameter \
+ "there is no parameter \
{} on trait {}",
s, name);
result = Err(ErrorReported);
let name = tcx.item_name(trait_ref.def_id);
let trait_str = tcx.item_path_str(trait_ref.def_id);
let generics = tcx.generics_of(trait_ref.def_id);
- let generic_map = generics.types.iter().map(|param| {
- (param.name.to_string(),
- trait_ref.substs.type_for_def(param).to_string())
+ let generic_map = generics.params.iter().filter_map(|param| {
+ let value = match param.kind {
+ GenericParamDefKind::Type(_) => {
+ trait_ref.substs[param.index as usize].to_string()
+ },
+ GenericParamDefKind::Lifetime => return None
+ };
+ let name = param.name.to_string();
+ Some((name, value))
}).collect::<FxHashMap<String, String>>();
let parser = Parser::new(&self.0);
/// There is no built-in impl. There may be some other
/// candidate (a where-clause or user-defined impl).
None,
- /// There is *no* impl for this, builtin or not. Ignore
- /// all where-clauses.
- Never,
/// It is unknown whether there is an impl.
Ambiguous
}
mut obligation: TraitObligation<'tcx>)
-> Result<EvaluationResult, OverflowError>
{
- debug!("evaluate_trait_predicate_recursively({:?})",
- obligation);
+ debug!("evaluate_trait_predicate_recursively({:?})", obligation);
- if !self.intercrate.is_some() && obligation.is_global() {
- // If a param env is consistent, global obligations do not depend on its particular
- // value in order to work, so we can clear out the param env and get better
- // caching. (If the current param env is inconsistent, we don't care what happens).
+ if self.intercrate.is_none() && obligation.is_global()
+ && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) {
+ // If a param env has no global bounds, global obligations do not
+ // depend on its particular value in order to work, so we can clear
+ // out the param env and get better caching.
debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
obligation.param_env = obligation.param_env.without_caller_bounds();
}
let sized_conditions = self.sized_conditions(obligation);
self.assemble_builtin_bound_candidates(sized_conditions,
&mut candidates)?;
- } else if lang_items.unsize_trait() == Some(def_id) {
- self.assemble_candidates_for_unsizing(obligation, &mut candidates);
- } else {
- if lang_items.clone_trait() == Some(def_id) {
- // Same builtin conditions as `Copy`, i.e. every type which has builtin support
- // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
- // types have builtin support for `Clone`.
- let clone_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
- }
-
- self.assemble_generator_candidates(obligation, &mut candidates)?;
- self.assemble_closure_candidates(obligation, &mut candidates)?;
- self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
- self.assemble_candidates_from_impls(obligation, &mut candidates)?;
- self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+ } else if lang_items.unsize_trait() == Some(def_id) {
+ self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+ } else {
+ if lang_items.clone_trait() == Some(def_id) {
+ // Same builtin conditions as `Copy`, i.e. every type which has builtin support
+ // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone`
+ // types have builtin support for `Clone`.
+ let clone_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?;
+ }
+
+ self.assemble_generator_candidates(obligation, &mut candidates)?;
+ self.assemble_closure_candidates(obligation, &mut candidates)?;
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates)?;
+ self.assemble_candidates_from_impls(obligation, &mut candidates)?;
+ self.assemble_candidates_from_object_ty(obligation, &mut candidates);
}
self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
// BUILTIN BOUNDS
//
// These cover the traits that are built-in to the language
- // itself. This includes `Copy` and `Sized` for sure. For the
- // moment, it also includes `Send` / `Sync` and a few others, but
- // those will hopefully change to library-defined traits in the
- // future.
+ // itself: `Copy`, `Clone` and `Sized`.
- // HACK: if this returns an error, selection exits without considering
- // other impls.
fn assemble_builtin_bound_candidates<'o>(&mut self,
conditions: BuiltinImplConditions<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>)
debug!("assemble_builtin_bound_candidates: ambiguous builtin");
Ok(candidates.ambiguous = true)
}
- BuiltinImplConditions::Never => { Err(Unimplemented) }
}
}
fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
-> BuiltinImplConditions<'tcx>
{
- use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
+ use self::BuiltinImplConditions::{Ambiguous, None, Where};
// NOTE: binder moved to (*)
let self_ty = self.infcx.shallow_resolve(
Where(ty::Binder::dummy(Vec::new()))
}
- ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never,
+ ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => None,
ty::TyTuple(tys) => {
Where(ty::Binder::bind(tys.last().into_iter().cloned().collect()))
let self_ty = self.infcx.shallow_resolve(
obligation.predicate.skip_binder().self_ty());
- use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
+ use self::BuiltinImplConditions::{Ambiguous, None, Where};
match self_ty.sty {
ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
ty::TyGenerator(..) | ty::TyGeneratorWitness(..) | ty::TyForeign(..) |
ty::TyRef(_, _, hir::MutMutable) => {
- Never
+ None
}
ty::TyArray(element_ty, _) => {
if is_copy_trait || is_clone_trait {
Where(ty::Binder::bind(substs.upvar_tys(def_id, self.tcx()).collect()))
} else {
- Never
+ None
}
}
super::IntrinsicType => Some(super::IntrinsicType),
super::MethodReceiver => Some(super::MethodReceiver),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
+ super::TrivialBound => Some(super::TrivialBound),
}
}
}
},
Component::Param(p) => {
- let ty = tcx.mk_param(p.idx, p.name);
+ let ty = tcx.mk_ty_param(p.idx, p.name);
Some(ty::Predicate::TypeOutlives(
ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
},
use ty::RegionKind;
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
+use ty::GenericParamDefKind;
use ty::layout::{LayoutDetails, TargetDataLayout};
use ty::maps;
use ty::steal::Steal;
pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> {
let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem);
let adt_def = self.adt_def(def_id);
- let generics = self.generics_of(def_id);
- let mut substs = vec![Kind::from(ty)];
- // Add defaults for other generic params if there are some.
- for def in generics.types.iter().skip(1) {
- assert!(def.has_default);
- let ty = self.type_of(def.def_id).subst(self, &substs);
- substs.push(ty.into());
- }
- let substs = self.mk_substs(substs.into_iter());
+ let substs = Substs::for_item(self, def_id, |param, substs| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => bug!(),
+ GenericParamDefKind::Type(ty_param) => {
+ if param.index == 0 {
+ ty.into()
+ } else {
+ assert!(ty_param.has_default);
+ self.type_of(param.def_id).subst(self, substs).into()
+ }
+ }
+ }
+ });
self.mk_ty(TyAdt(adt_def, substs))
}
self.mk_ty(TyInfer(it))
}
- pub fn mk_param(self,
+ pub fn mk_ty_param(self,
index: u32,
name: InternedString) -> Ty<'tcx> {
self.mk_ty(TyParam(ParamTy { idx: index, name: name }))
}
pub fn mk_self_type(self) -> Ty<'tcx> {
- self.mk_param(0, keywords::SelfType.name().as_interned_str())
+ self.mk_ty_param(0, keywords::SelfType.name().as_interned_str())
}
- pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> {
- self.mk_param(def.index, def.name)
+ pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> Kind<'tcx> {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into()
+ }
+ GenericParamDefKind::Type(_) => self.mk_ty_param(param.index, param.name).into(),
+ }
}
pub fn mk_anon(self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
}
&ty::TyParam(ref p) => {
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+ self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
if p.is_self() {
self.add_flags(TypeFlags::HAS_SELF);
} else {
&ty::TyGenerator(_, ref substs, _) => {
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+ self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
self.add_substs(&substs.substs);
}
&ty::TyClosure(_, ref substs) => {
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
+ self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
self.add_substs(&substs.substs);
}
&ty::TyInfer(infer) => {
- self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right?
+ self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
self.add_flags(TypeFlags::HAS_TY_INFER);
match infer {
ty::FreshTy(_) |
/// Indicates whether this value references only 'global'
/// types/lifetimes that are the same regardless of what fn we are
- /// in. This is used for caching. Errs on the side of returning
- /// false.
+ /// in. This is used for caching.
fn is_global(&self) -> bool {
- !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES)
+ !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
+ }
+
+ /// True if there are any late-bound regions
+ fn has_late_bound_regions(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND)
}
}
if x < min { min = x; }
if x > max { max = x; }
}
+ // We might have no inhabited variants, so pretend there's at least one.
+ if (min, max) == (i128::max_value(), i128::min_value()) {
+ min = 0;
+ max = 0;
+ }
assert!(min <= max, "discriminant range is {}...{}", min, max);
let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max);
impl<'tcx> QueryDescription<'tcx> for queries::is_late_bound_map<'tcx> {
fn describe(_tcx: TyCtxt, _: DefIndex) -> String {
- format!("testing if a region is late boudn")
+ format!("testing if a region is late bound")
}
}
// true if there are "names" of types and regions and so forth
// that are local to a particular fn
- const HAS_LOCAL_NAMES = 1 << 10;
+ const HAS_FREE_LOCAL_NAMES = 1 << 10;
// Present if the type belongs in a local type context.
// Only set for TyInfer other than Fresh.
// ought to be true only for the results of canonicalization.
const HAS_CANONICAL_VARS = 1 << 13;
+ /// Does this have any `ReLateBound` regions? Used to check
+ /// if a global bound is safe to evaluate.
+ const HAS_RE_LATE_BOUND = 1 << 14;
+
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits;
TypeFlags::HAS_TY_ERR.bits |
TypeFlags::HAS_PROJECTION.bits |
TypeFlags::HAS_TY_CLOSURE.bits |
- TypeFlags::HAS_LOCAL_NAMES.bits |
+ TypeFlags::HAS_FREE_LOCAL_NAMES.bits |
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
- TypeFlags::HAS_CANONICAL_VARS.bits;
+ TypeFlags::HAS_CANONICAL_VARS.bits |
+ TypeFlags::HAS_RE_LATE_BOUND.bits;
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct FloatVarValue(pub ast::FloatTy);
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub struct TypeParameterDef {
- pub name: InternedString,
- pub def_id: DefId,
- pub index: u32,
+#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
+pub struct TypeParamDef {
pub has_default: bool,
pub object_lifetime_default: ObjectLifetimeDefault,
+ pub synthetic: Option<hir::SyntheticTyParamKind>,
+}
- /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
- /// on generic parameter `T`, asserts data behind the parameter
- /// `T` won't be accessed during the parent type's `Drop` impl.
- pub pure_wrt_drop: bool,
+impl ty::EarlyBoundRegion {
+ pub fn to_bound_region(&self) -> ty::BoundRegion {
+ ty::BoundRegion::BrNamed(self.def_id, self.name)
+ }
+}
- pub synthetic: Option<hir::SyntheticTyParamKind>,
+#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
+pub enum GenericParamDefKind {
+ Lifetime,
+ Type(TypeParamDef),
}
-#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
-pub struct RegionParameterDef {
+#[derive(Clone, RustcEncodable, RustcDecodable)]
+pub struct GenericParamDef {
pub name: InternedString,
pub def_id: DefId,
pub index: u32,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
- /// on generic parameter `'a`, asserts data of lifetime `'a`
- /// won't be accessed during the parent type's `Drop` impl.
+ /// on generic parameter `'a`/`T`, asserts data behind the parameter
+ /// `'a`/`T` won't be accessed during the parent type's `Drop` impl.
pub pure_wrt_drop: bool,
+
+ pub kind: GenericParamDefKind,
}
-impl RegionParameterDef {
+impl GenericParamDef {
pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion {
- ty::EarlyBoundRegion {
- def_id: self.def_id,
- index: self.index,
- name: self.name,
+ match self.kind {
+ GenericParamDefKind::Lifetime => {
+ ty::EarlyBoundRegion {
+ def_id: self.def_id,
+ index: self.index,
+ name: self.name,
+ }
+ }
+ _ => bug!("cannot convert a non-lifetime parameter def to an early bound region")
}
}
pub fn to_bound_region(&self) -> ty::BoundRegion {
- self.to_early_bound_region_data().to_bound_region()
+ match self.kind {
+ GenericParamDefKind::Lifetime => {
+ self.to_early_bound_region_data().to_bound_region()
+ }
+ _ => bug!("cannot convert a non-lifetime parameter def to an early bound region")
+ }
}
}
-impl ty::EarlyBoundRegion {
- pub fn to_bound_region(&self) -> ty::BoundRegion {
- ty::BoundRegion::BrNamed(self.def_id, self.name)
- }
+pub struct GenericParamCount {
+ pub lifetimes: usize,
+ pub types: usize,
}
/// Information about the formal type/lifetime parameters associated
/// with an item or method. Analogous to hir::Generics.
///
-/// Note that in the presence of a `Self` parameter, the ordering here
-/// is different from the ordering in a Substs. Substs are ordered as
-/// Self, *Regions, *Other Type Params, (...child generics)
-/// while this struct is ordered as
-/// regions = Regions
-/// types = [Self, *Other Type Params]
+/// The ordering of parameters is the same as in Subst (excluding child generics):
+/// Self (optionally), Lifetime params..., Type params...
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Generics {
pub parent: Option<DefId>,
- pub parent_regions: u32,
- pub parent_types: u32,
- pub regions: Vec<RegionParameterDef>,
- pub types: Vec<TypeParameterDef>,
+ pub parent_count: usize,
+ pub params: Vec<GenericParamDef>,
- /// Reverse map to each `TypeParameterDef`'s `index` field
- pub type_param_to_index: FxHashMap<DefId, u32>,
+ /// Reverse map to the `index` field of each `GenericParamDef`
+ pub param_def_id_to_index: FxHashMap<DefId, u32>,
pub has_self: bool,
pub has_late_bound_regions: Option<Span>,
}
impl<'a, 'gcx, 'tcx> Generics {
- pub fn parent_count(&self) -> usize {
- self.parent_regions as usize + self.parent_types as usize
+ pub fn count(&self) -> usize {
+ self.parent_count + self.params.len()
}
- pub fn own_count(&self) -> usize {
- self.regions.len() + self.types.len()
+ pub fn own_counts(&self) -> GenericParamCount {
+ // We could cache this as a property of `GenericParamCount`, but
+ // the aim is to refactor this away entirely eventually and the
+ // presence of this method will be a constant reminder.
+ let mut own_counts = GenericParamCount {
+ lifetimes: 0,
+ types: 0,
+ };
+
+ for param in &self.params {
+ match param.kind {
+ GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
+ GenericParamDefKind::Type(_) => own_counts.types += 1,
+ };
+ }
+
+ own_counts
}
- pub fn count(&self) -> usize {
- self.parent_count() + self.own_count()
+ pub fn requires_monomorphization(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+ for param in &self.params {
+ match param.kind {
+ GenericParamDefKind::Type(_) => return true,
+ GenericParamDefKind::Lifetime => {}
+ }
+ }
+ if let Some(parent_def_id) = self.parent {
+ let parent = tcx.generics_of(parent_def_id);
+ parent.requires_monomorphization(tcx)
+ } else {
+ false
+ }
}
pub fn region_param(&'tcx self,
param: &EarlyBoundRegion,
tcx: TyCtxt<'a, 'gcx, 'tcx>)
- -> &'tcx RegionParameterDef
+ -> &'tcx GenericParamDef
{
- if let Some(index) = param.index.checked_sub(self.parent_count() as u32) {
- &self.regions[index as usize - self.has_self as usize]
+ if let Some(index) = param.index.checked_sub(self.parent_count as u32) {
+ let param = &self.params[index as usize];
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => param,
+ _ => bug!("expected lifetime parameter, but found another generic parameter")
+ }
} else {
tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
.region_param(param, tcx)
}
}
- /// Returns the `TypeParameterDef` associated with this `ParamTy`.
+ /// Returns the `TypeParamDef` associated with this `ParamTy`.
pub fn type_param(&'tcx self,
param: &ParamTy,
tcx: TyCtxt<'a, 'gcx, 'tcx>)
- -> &TypeParameterDef {
- if let Some(idx) = param.idx.checked_sub(self.parent_count() as u32) {
- // non-Self type parameters are always offset by exactly
- // `self.regions.len()`. In the absence of a Self, this is obvious,
- // but even in the presence of a `Self` we just have to "compensate"
- // for the regions:
- //
- // Without a `Self` (or in a nested generics that doesn't have
- // a `Self` in itself, even through it parent does), for example
- // for `fn foo<'a, T1, T2>()`, the situation is:
- // Substs:
- // 0 1 2
- // 'a T1 T2
- // generics.types:
- // 0 1
- // T1 T2
- //
- // And with a `Self`, for example for `trait Foo<'a, 'b, T1, T2>`, the
- // situation is:
- // Substs:
- // 0 1 2 3 4
- // Self 'a 'b T1 T2
- // generics.types:
- // 0 1 2
- // Self T1 T2
- //
- // And it can be seen that in both cases, to move from a substs
- // offset to a generics offset you just have to offset by the
- // number of regions.
- let type_param_offset = self.regions.len();
-
- let has_self = self.has_self && self.parent.is_none();
- let is_separated_self = type_param_offset != 0 && idx == 0 && has_self;
-
- if let Some(idx) = (idx as usize).checked_sub(type_param_offset) {
- assert!(!is_separated_self, "found a Self after type_param_offset");
- &self.types[idx]
- } else {
- assert!(is_separated_self, "non-Self param before type_param_offset");
- &self.types[0]
+ -> &'tcx GenericParamDef {
+ if let Some(index) = param.idx.checked_sub(self.parent_count as u32) {
+ let param = &self.params[index as usize];
+ match param.kind {
+ ty::GenericParamDefKind::Type(_) => param,
+ _ => bug!("expected type parameter, but found another generic parameter")
}
} else {
tcx.generics_of(self.parent.expect("parent_count>0 but no parent?"))
/// ordering.
fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitClosureSubsts<'tcx> {
let generics = tcx.generics_of(def_id);
- let parent_len = generics.parent_count();
+ let parent_len = generics.parent_count;
SplitClosureSubsts {
closure_kind_ty: self.substs.type_at(parent_len),
closure_sig_ty: self.substs.type_at(parent_len + 1),
impl<'tcx> GeneratorSubsts<'tcx> {
fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitGeneratorSubsts<'tcx> {
let generics = tcx.generics_of(def_id);
- let parent_len = generics.parent_count();
+ let parent_len = generics.parent_count;
SplitGeneratorSubsts {
yield_ty: self.substs.type_at(parent_len),
return_ty: self.substs.type_at(parent_len + 1),
ParamTy::new(0, keywords::SelfType.name().as_interned_str())
}
- pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy {
+ pub fn for_def(def: &ty::GenericParamDef) -> ParamTy {
ParamTy::new(def.index, def.name)
}
pub fn to_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
- tcx.mk_param(self.idx, self.name)
+ tcx.mk_ty_param(self.idx, self.name)
}
pub fn is_self(&self) -> bool {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_SKOL;
}
- ty::ReLateBound(..) => { }
+ ty::ReLateBound(..) => {
+ flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
+ }
ty::ReEarlyBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_RE_EARLY_BOUND;
}
match *self {
- ty::ReStatic | ty::ReEmpty | ty::ReErased => (),
- _ => flags = flags | TypeFlags::HAS_LOCAL_NAMES,
+ ty::ReStatic | ty::ReEmpty | ty::ReErased | ty::ReLateBound(..) => (),
+ _ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES,
}
debug!("type_flags({:?}) = {:?}", self, flags);
}
}
-/// A substitution mapping type/region parameters to new values.
+/// A substitution mapping generic parameters to new values.
pub type Substs<'tcx> = Slice<Kind<'tcx>>;
impl<'a, 'gcx, 'tcx> Substs<'tcx> {
/// Creates a Substs that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId)
-> &'tcx Substs<'tcx> {
- Substs::for_item(tcx, def_id, |def, _| {
- tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
- }, |def, _| tcx.mk_param_from_def(def))
+ Substs::for_item(tcx, def_id, |param, _| {
+ tcx.mk_param_from_def(param)
+ })
}
/// Creates a Substs for generic parameter definitions,
- /// by calling closures to obtain each region and type.
+ /// by calling closures to obtain each kind.
/// The closures get to observe the Substs as they're
/// being built, which can be used to correctly
- /// substitute defaults of type parameters.
- pub fn for_item<FR, FT>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- def_id: DefId,
- mut mk_region: FR,
- mut mk_type: FT)
- -> &'tcx Substs<'tcx>
- where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
- FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
+ /// substitute defaults of generic parameters.
+ pub fn for_item<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ def_id: DefId,
+ mut mk_kind: F)
+ -> &'tcx Substs<'tcx>
+ where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
+ {
let defs = tcx.generics_of(def_id);
let mut substs = Vec::with_capacity(defs.count());
- Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
+ Substs::fill_item(&mut substs, tcx, defs, &mut mk_kind);
tcx.intern_substs(&substs)
}
- pub fn extend_to<FR, FT>(&self,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- def_id: DefId,
- mut mk_region: FR,
- mut mk_type: FT)
- -> &'tcx Substs<'tcx>
- where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
- FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx>
+ pub fn extend_to<F>(&self,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ def_id: DefId,
+ mut mk_kind: F)
+ -> &'tcx Substs<'tcx>
+ where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
{
let defs = tcx.generics_of(def_id);
let mut result = Vec::with_capacity(defs.count());
result.extend(self[..].iter().cloned());
- Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type);
+ Substs::fill_single(&mut result, defs, &mut mk_kind);
tcx.intern_substs(&result)
}
- pub fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+ pub fn fill_item<F>(substs: &mut Vec<Kind<'tcx>>,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
defs: &ty::Generics,
- mk_region: &mut FR,
- mk_type: &mut FT)
- where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
- FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
+ mk_kind: &mut F)
+ where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
+ {
if let Some(def_id) = defs.parent {
let parent_defs = tcx.generics_of(def_id);
- Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type);
+ Substs::fill_item(substs, tcx, parent_defs, mk_kind);
}
- Substs::fill_single(substs, defs, mk_region, mk_type)
+ Substs::fill_single(substs, defs, mk_kind)
}
- fn fill_single<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
+ fn fill_single<F>(substs: &mut Vec<Kind<'tcx>>,
defs: &ty::Generics,
- mk_region: &mut FR,
- mk_type: &mut FT)
- where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>,
- FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
- // Handle Self first, before all regions.
- let mut types = defs.types.iter();
- if defs.parent.is_none() && defs.has_self {
- let def = types.next().unwrap();
- let ty = mk_type(def, substs);
- assert_eq!(def.index as usize, substs.len());
- substs.push(ty.into());
- }
-
- for def in &defs.regions {
- let region = mk_region(def, substs);
- assert_eq!(def.index as usize, substs.len());
- substs.push(Kind::from(region));
- }
-
- for def in types {
- let ty = mk_type(def, substs);
- assert_eq!(def.index as usize, substs.len());
- substs.push(Kind::from(ty));
+ mk_kind: &mut F)
+ where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx>
+ {
+ for param in &defs.params {
+ let kind = mk_kind(param, substs);
+ assert_eq!(param.index as usize, substs.len());
+ substs.push(kind);
}
}
}
#[inline]
- pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
- self.type_at(ty_param_def.index as usize)
- }
-
- #[inline]
- pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region<'tcx> {
- self.region_at(def.index as usize)
+ pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> {
+ self.type_at(def.index as usize).into()
}
/// Transform from substitutions for a child of `source_ancestor`
target_substs: &Substs<'tcx>)
-> &'tcx Substs<'tcx> {
let defs = tcx.generics_of(source_ancestor);
- tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
+ tcx.mk_substs(target_substs.iter().chain(&self[defs.params.len()..]).cloned())
}
pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics)
ty::TraitRef {
def_id: trait_id,
- substs: tcx.intern_substs(&substs[..defs.own_count()])
+ substs: tcx.intern_substs(&substs[..defs.params.len()])
}
}
}
use ich::NodeIdHashingMode;
use middle::const_val::ConstVal;
use traits::{self, ObligationCause};
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable};
use ty::fold::TypeVisitor;
-use ty::subst::UnpackedKind;
+use ty::subst::{Substs, UnpackedKind};
use ty::maps::TyCtxtAt;
use ty::TypeVariants::*;
use ty::layout::{Integer, IntegerExt};
/// Given the def-id of some item that has no type parameters, make
/// a suitable "empty substs" for it.
- pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> {
- ty::Substs::for_item(self, item_def_id,
- |_, _| self.types.re_erased,
- |_, _| {
- bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
+ pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
+ Substs::for_item(self, item_def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => self.types.re_erased.into(),
+ GenericParamDefKind::Type(_) => {
+ bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
+ }
+ }
})
}
use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple};
use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, TyAnon};
use ty::{TyDynamic, TyInt, TyUint, TyInfer};
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use ty::{self, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind};
use util::nodemap::FxHashSet;
use std::cell::Cell;
let verbose = self.is_verbose;
let mut num_supplied_defaults = 0;
let mut has_self = false;
- let mut num_regions = 0;
- let mut num_types = 0;
+ let mut own_counts = GenericParamCount {
+ lifetimes: 0,
+ types: 0,
+ };
let mut is_value_path = false;
let fn_trait_kind = ty::tls::with(|tcx| {
// Unfortunately, some kinds of items (e.g., closures) don't have
}
}
let mut generics = tcx.generics_of(item_def_id);
+ let child_own_counts = generics.own_counts();
let mut path_def_id = did;
has_self = generics.has_self;
if let Some(def_id) = generics.parent {
// Methods.
assert!(is_value_path);
- child_types = generics.types.len();
+ child_types = child_own_counts.types;
generics = tcx.generics_of(def_id);
- num_regions = generics.regions.len();
- num_types = generics.types.len();
+ own_counts = generics.own_counts();
if has_self {
print!(f, self, write("<"), print_display(substs.type_at(0)), write(" as "))?;
assert_eq!(has_self, false);
} else {
// Types and traits.
- num_regions = generics.regions.len();
- num_types = generics.types.len();
+ own_counts = child_own_counts;
}
}
if !verbose {
- if generics.types.last().map_or(false, |def| def.has_default) {
+ let mut type_params =
+ generics.params.iter().rev().filter_map(|param| {
+ match param.kind {
+ GenericParamDefKind::Type(ty) => Some((param.def_id, ty.has_default)),
+ GenericParamDefKind::Lifetime => None,
+ }
+ }).peekable();
+ let has_default = {
+ let has_default = type_params.peek().map(|(_, has_default)| has_default);
+ *has_default.unwrap_or(&false)
+ };
+ if has_default {
if let Some(substs) = tcx.lift(&substs) {
- let tps = substs.types().rev().skip(child_types);
- for (def, actual) in generics.types.iter().rev().zip(tps) {
- if !def.has_default {
+ let mut types = substs.types().rev().skip(child_types);
+ for ((def_id, has_default), actual) in type_params.zip(types) {
+ if !has_default {
break;
}
- if tcx.type_of(def.def_id).subst(tcx, substs) != actual {
+ if tcx.type_of(def_id).subst(tcx, substs) != actual {
break;
}
num_supplied_defaults += 1;
Ok(())
};
- print_regions(f, "<", 0, num_regions)?;
+ print_regions(f, "<", 0, own_counts.lifetimes)?;
- let tps = substs.types().take(num_types - num_supplied_defaults)
- .skip(has_self as usize);
+ let tps = substs.types()
+ .take(own_counts.types - num_supplied_defaults)
+ .skip(has_self as usize);
for ty in tps {
start_or_continue(f, "<", ", ")?;
write!(f, "::{}", item_name)?;
}
- print_regions(f, "::<", num_regions, usize::MAX)?;
+ print_regions(f, "::<", own_counts.lifetimes, usize::MAX)?;
// FIXME: consider being smart with defaults here too
- for ty in substs.types().skip(num_types) {
+ for ty in substs.types().skip(own_counts.types) {
start_or_continue(f, "::<", ", ")?;
ty.print_display(f, self)?;
}
}
}
-impl fmt::Debug for ty::TypeParameterDef {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "TypeParameterDef({}, {:?}, {})",
- self.name,
- self.def_id,
- self.index)
- }
-}
-
-impl fmt::Debug for ty::RegionParameterDef {
+impl fmt::Debug for ty::GenericParamDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "RegionParameterDef({}, {:?}, {})",
+ let type_name = match self.kind {
+ ty::GenericParamDefKind::Lifetime => "Lifetime",
+ ty::GenericParamDefKind::Type(_) => "Type",
+ };
+ write!(f, "{}({}, {:?}, {})",
+ type_name,
self.name,
self.def_id,
self.index)
pub fn t_param(&self, index: u32) -> Ty<'tcx> {
let name = format!("T{}", index);
- self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_interned_str())
+ self.infcx.tcx.mk_ty_param(index, Symbol::intern(&name).as_interned_str())
}
pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> {
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnsafeCode {
fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
- if let hir::ExprBlock(ref blk) = e.node {
+ if let hir::ExprBlock(ref blk, _) = e.node {
// Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) {
self.report_unsafe(cx, blk.span, "usage of an `unsafe` block");
if let Some(orig) = orig {
err.span_suggestion(it.span, &help,
- format!("{}use {} as {}", pub_, orig, it.name));
+ format!("{}use {} as {};", pub_, orig, it.name));
} else {
err.span_suggestion(it.span, &help,
- format!("{}use {}", pub_, it.name));
+ format!("{}use {};", pub_, it.name));
}
} else {
err.span_suggestion(it.span, "remove it", "".into());
self.0 += 1;
}
}
+
+/// Lint for trait and lifetime bounds that don't depend on type parameters
+/// which either do nothing, or stop the item from being used.
+pub struct TrivialConstraints;
+
+declare_lint! {
+ TRIVIAL_BOUNDS,
+ Warn,
+ "these bounds don't depend on an type parameters"
+}
+
+impl LintPass for TrivialConstraints {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(TRIVIAL_BOUNDS)
+ }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints {
+ fn check_item(
+ &mut self,
+ cx: &LateContext<'a, 'tcx>,
+ item: &'tcx hir::Item,
+ ) {
+ use rustc::ty::fold::TypeFoldable;
+ use rustc::ty::Predicate::*;
+
+
+ if cx.tcx.features().trivial_bounds {
+ let def_id = cx.tcx.hir.local_def_id(item.id);
+ let predicates = cx.tcx.predicates_of(def_id);
+ for predicate in &predicates.predicates {
+ let predicate_kind_name = match *predicate {
+ Trait(..) => "Trait",
+ TypeOutlives(..) |
+ RegionOutlives(..) => "Lifetime",
+
+ // Ignore projections, as they can only be global
+ // if the trait bound is global
+ Projection(..) |
+ // Ignore bounds that a user can't type
+ WellFormed(..) |
+ ObjectSafe(..) |
+ ClosureKind(..) |
+ Subtype(..) |
+ ConstEvaluatable(..) => continue,
+ };
+ if predicate.is_global() {
+ cx.span_lint(
+ TRIVIAL_BOUNDS,
+ item.span,
+ &format!("{} bound {} does not depend on any type \
+ or lifetime parameters", predicate_kind_name, predicate),
+ );
+ }
+ }
+ }
+ }
+}
UnreachablePub,
TypeAliasBounds,
UnusedBrokenConst,
+ TrivialConstraints,
);
add_builtin_with_new!(sess,
hir::ImplItemKind::Const(..) => true,
hir::ImplItemKind::Method(ref sig, _) => {
let generics = self.tcx.generics_of(def_id);
- let types = generics.parent_types as usize + generics.types.len();
- let needs_inline =
- (types > 0 || tcx.trans_fn_attrs(def_id).requests_inline())
- && !self.metadata_output_only();
+ let needs_inline = (generics.requires_monomorphization(self.tcx) ||
+ tcx.trans_fn_attrs(def_id).requests_inline()) &&
+ !self.metadata_output_only();
let is_const_fn = sig.constness == hir::Constness::Const;
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
needs_inline || is_const_fn || always_encode_mir
#![feature(box_patterns)]
#![feature(fs_read_write)]
#![feature(libc)]
-#![feature(macro_lifetime_matcher)]
+#![cfg_attr(stage0, feature(macro_lifetime_matcher))]
#![feature(proc_macro_internals)]
-#![feature(macro_lifetime_matcher)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
self.in_opt_scope(opt_destruction_scope.map(|de|(de, source_info)), block, move |this| {
this.in_scope((region_scope, source_info), LintLevel::Inherited, block, move |this| {
if targeted_by_break {
- // This is a `break`-able block (currently only `catch { ... }`)
+ // This is a `break`-able block
let exit_block = this.cfg.start_new_block();
let block_exit = this.in_breakable_scope(
None, exit_block, destination.clone(), |this| {
}
}
- hir::ExprBlock(ref blk) => ExprKind::Block { body: &blk },
+ hir::ExprBlock(ref blk, _) => ExprKind::Block { body: &blk },
hir::ExprAssign(ref lhs, ref rhs) => {
ExprKind::Assign {
hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
hir::ExprBreak(dest, ref value) => {
match dest.target_id {
- hir::ScopeTarget::Block(target_id) |
- hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(target_id)) => ExprKind::Break {
+ Ok(target_id) => ExprKind::Break {
label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(target_id).local_id),
value: value.to_ref(),
},
- hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
- bug!("invalid loop id for break: {}", err)
+ Err(err) => bug!("invalid loop id for break: {}", err)
}
}
hir::ExprAgain(dest) => {
match dest.target_id {
- hir::ScopeTarget::Block(_) => bug!("cannot continue to blocks"),
- hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => ExprKind::Continue {
+ Ok(loop_id) => ExprKind::Continue {
label: region::Scope::Node(cx.tcx.hir.node_to_hir_id(loop_id).local_id),
},
- hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) =>
- bug!("invalid loop id for continue: {}", err)
+ Err(err) => bug!("invalid loop id for continue: {}", err)
}
}
hir::ExprMatch(ref discr, ref arms, _) => {
use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::ty::subst::{Substs, Kind};
-use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
+use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::session::config;
use rustc::mir::{self, Location, Promoted};
fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
let generics = tcx.generics_of(def_id);
- generics.parent_types as usize + generics.types.len() > 0
+ generics.requires_monomorphization(tcx)
}
fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
continue;
}
- if !tcx.generics_of(method.def_id).types.is_empty() {
+ if tcx.generics_of(method.def_id).own_counts().types != 0 {
continue;
}
- let substs = Substs::for_item(tcx,
- method.def_id,
- |_, _| tcx.types.re_erased,
- |def, _| trait_ref.substs.type_for_def(def));
+ let substs = Substs::for_item(tcx, method.def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
+ GenericParamDefKind::Type(_) => {
+ trait_ref.substs[param.index as usize]
+ }
+ }
+ });
let instance = ty::Instance::resolve(tcx,
ty::ParamEnv::reveal_all(),
use rustc::hir::def_id::DefId;
use rustc::infer;
use rustc::mir::*;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::maps::Providers;
) {
let tcx = self.tcx;
- let substs = Substs::for_item(
- tcx,
- self.def_id,
- |_, _| tcx.types.re_erased,
- |_, _| ty
- );
+ let substs = Substs::for_item(tcx, self.def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => tcx.types.re_erased.into(),
+ GenericParamDefKind::Type(_) => ty.into(),
+ }
+ });
// `func == Clone::clone(&ty) -> ty`
let func_ty = tcx.mk_fn_def(self.def_id, substs);
}
// Check if this is an unsafe block, or an item
match node {
- Node::NodeExpr(&hir::Expr { node: hir::ExprBlock(ref block), ..}) => {
+ Node::NodeExpr(&hir::Expr { node: hir::ExprBlock(ref block, _), ..}) => {
if block_is_unsafe(&*block) {
// Found an unsafe block, we can bail out here.
return true;
// FIXME: when we make this a hard error, this should have its
// own error code.
- let message = if !tcx.generics_of(def_id).types.is_empty() {
+ let message = if tcx.generics_of(def_id).own_counts().types != 0 {
format!("#[derive] can't be used on a #[repr(packed)] struct with \
type parameters (error E0133)")
} else {
// evaluate the promoted and replace the constant with the evaluated result
Literal::Promoted { index } => {
let generics = self.tcx.generics_of(self.source.def_id);
- if generics.parent_types as usize + generics.types.len() > 0 {
+ if generics.requires_monomorphization(self.tcx) {
// FIXME: can't handle code with generics
return None;
}
self.source.def_id
};
let generics = self.tcx.generics_of(def_id);
- if generics.parent_types as usize + generics.types.len() > 0 {
+ if generics.requires_monomorphization(self.tcx) {
// FIXME: can't handle code with generics
return None;
}
self.source.def_id
};
let generics = self.tcx.generics_of(def_id);
- let has_generics = generics.parent_types as usize + generics.types.len() > 0;
- if has_generics {
+ if generics.requires_monomorphization(self.tcx) {
// FIXME: can't handle code with generics
return None;
}
}
}
- /// matches '-' lit | lit (cf. parser::Parser::parse_pat_literal_maybe_minus),
+ /// matches '-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus),
/// or path for ranges.
///
/// FIXME: do we want to allow expr -> pattern conversion to create path expressions?
i += 1;
};
```
+"##,
+
+E0695: r##"
+A `break` statement without a label appeared inside a labeled block.
+
+Example of erroneous code:
+
+```compile_fail,E0695
+# #![feature(label_break_value)]
+loop {
+ 'a: {
+ break;
+ }
+}
+```
+
+Make sure to always label the `break`:
+
+```
+# #![feature(label_break_value)]
+'l: loop {
+ 'a: {
+ break 'l;
+ }
+}
+```
+
+Or if you want to `break` the labeled block:
+
+```
+# #![feature(label_break_value)]
+loop {
+ 'a: {
+ break 'a;
+ }
+ break;
+}
+```
"##
}
E0642, // patterns aren't allowed in methods without bodies
E0666, // nested `impl Trait` is illegal
E0667, // `impl Trait` in projections
+ E0696, // `continue` pointing to a labeled block
}
use rustc::hir::map::Map;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir;
+use rustc::hir::{self, Destination};
use syntax::ast;
use syntax_pos::Span;
Normal,
Loop(LoopKind),
Closure,
+ LabeledBlock,
}
#[derive(Copy, Clone)]
hir::ExprClosure(.., b, _, _) => {
self.with_context(Closure, |v| v.visit_nested_body(b));
}
+ hir::ExprBlock(ref b, Some(_label)) => {
+ self.with_context(LabeledBlock, |v| v.visit_block(&b));
+ }
hir::ExprBreak(label, ref opt_expr) => {
- let loop_id = match label.target_id {
- hir::ScopeTarget::Block(_) => return,
- hir::ScopeTarget::Loop(loop_res) => {
- match loop_res.into() {
- Ok(loop_id) => loop_id,
- Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
- Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
- self.emit_unlabled_cf_in_while_condition(e.span, "break");
- ast::DUMMY_NODE_ID
- },
- Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
- }
- }
+ if self.require_label_in_labeled_block(e.span, &label, "break") {
+ // If we emitted an error about an unlabeled break in a labeled
+ // block, we don't need any further checking for this break any more
+ return;
+ }
+
+ let loop_id = match label.target_id.into() {
+ Ok(loop_id) => loop_id,
+ Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
+ Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
+ self.emit_unlabled_cf_in_while_condition(e.span, "break");
+ ast::DUMMY_NODE_ID
+ },
+ Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
};
+ if loop_id != ast::DUMMY_NODE_ID {
+ match self.hir_map.find(loop_id).unwrap() {
+ hir::map::NodeBlock(_) => return,
+ _=> (),
+ }
+ }
+
if opt_expr.is_some() {
let loop_kind = if loop_id == ast::DUMMY_NODE_ID {
None
})
};
match loop_kind {
- None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
+ None |
+ Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
Some(kind) => {
struct_span_err!(self.sess, e.span, E0571,
"`break` with value from a `{}` loop",
kind.name())
.span_label(e.span,
- "can only break with a value inside `loop`")
+ "can only break with a value inside \
+ `loop` or breakable block")
.span_suggestion(e.span,
&format!("instead, use `break` on its own \
without a value inside this `{}` loop",
}
}
- self.require_loop("break", e.span);
+ self.require_break_cx("break", e.span);
}
hir::ExprAgain(label) => {
- if let hir::ScopeTarget::Loop(
- hir::LoopIdResult::Err(
- hir::LoopIdError::UnlabeledCfInWhileCondition)) = label.target_id {
- self.emit_unlabled_cf_in_while_condition(e.span, "continue");
+ self.require_label_in_labeled_block(e.span, &label, "continue");
+
+ match label.target_id {
+ Ok(loop_id) => {
+ if let hir::map::NodeBlock(block) = self.hir_map.find(loop_id).unwrap() {
+ struct_span_err!(self.sess, e.span, E0696,
+ "`continue` pointing to a labeled block")
+ .span_label(e.span,
+ "labeled blocks cannot be `continue`'d")
+ .span_note(block.span,
+ "labeled block the continue points to")
+ .emit();
+ }
+ }
+ Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
+ self.emit_unlabled_cf_in_while_condition(e.span, "continue");
+ }
+ _ => {}
}
- self.require_loop("continue", e.span)
+ self.require_break_cx("continue", e.span)
},
_ => intravisit::walk_expr(self, e),
}
self.cx = old_cx;
}
- fn require_loop(&self, name: &str, span: Span) {
+ fn require_break_cx(&self, name: &str, span: Span) {
match self.cx {
+ LabeledBlock |
Loop(_) => {}
Closure => {
struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
}
}
+ fn require_label_in_labeled_block(&mut self, span: Span, label: &Destination, cf_type: &str)
+ -> bool
+ {
+ if self.cx == LabeledBlock {
+ if label.label.is_none() {
+ struct_span_err!(self.sess, span, E0695,
+ "unlabeled `{}` inside of a labeled block", cf_type)
+ .span_label(span,
+ format!("`{}` statements that would diverge to or through \
+ a labeled block need to bear a label", cf_type))
+ .emit();
+ return true;
+ }
+ }
+ return false;
+ }
fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
struct_span_err!(self.sess, span, E0590,
"`break` or `continue` with no label in the condition of a `while` loop")
let mut callee = &**callee;
loop {
callee = match callee.node {
- hir::ExprBlock(ref block) => match block.expr {
+ hir::ExprBlock(ref block, _) => match block.expr {
Some(ref tail) => &tail,
None => break
},
}
}
- hir::ExprBlock(_) |
+ hir::ExprBlock(..) |
hir::ExprIndex(..) |
hir::ExprField(..) |
hir::ExprArray(_) |
use rustc::hir::itemlikevisit::DeepVisitor;
use rustc::lint;
use rustc::middle::privacy::{AccessLevel, AccessLevels};
-use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
+use rustc::ty::{self, TyCtxt, Ty, TypeFoldable, GenericParamDefKind};
use rustc::ty::fold::TypeVisitor;
use rustc::ty::maps::Providers;
+use rustc::ty::subst::UnpackedKind;
use rustc::util::nodemap::NodeSet;
use syntax::ast::{self, CRATE_NODE_ID, Ident};
use syntax::symbol::keywords;
use std::cmp;
use std::mem::replace;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
mod diagnostics;
impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
fn generics(&mut self) -> &mut Self {
- for def in &self.ev.tcx.generics_of(self.item_def_id).types {
- if def.has_default {
- self.ev.tcx.type_of(def.def_id).visit_with(self);
+ for param in &self.ev.tcx.generics_of(self.item_def_id).params {
+ match param.kind {
+ GenericParamDefKind::Type(ty) => {
+ if ty.has_default {
+ self.ev.tcx.type_of(param.def_id).visit_with(self);
+ }
+ }
+ GenericParamDefKind::Lifetime => {}
}
}
self
in_body: bool,
span: Span,
empty_tables: &'a ty::TypeckTables<'tcx>,
+ visited_anon_tys: FxHashSet<DefId>
}
impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
self.tcx.sess.span_err(self.span, &msg);
return true;
}
- // `Self` here is the same `TyAnon`, so skip it to avoid infinite recursion
- for subst in trait_ref.substs.iter().skip(1) {
+ for subst in trait_ref.substs.iter() {
+ // Skip repeated `TyAnon`s to avoid infinite recursion.
+ if let UnpackedKind::Type(ty) = subst.unpack() {
+ if let ty::TyAnon(def_id, ..) = ty.sty {
+ if !self.visited_anon_tys.insert(def_id) {
+ continue;
+ }
+ }
+ }
if subst.visit_with(self) {
return true;
}
impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
fn generics(&mut self) -> &mut Self {
- for def in &self.tcx.generics_of(self.item_def_id).types {
- if def.has_default {
- self.tcx.type_of(def.def_id).visit_with(self);
+ for param in &self.tcx.generics_of(self.item_def_id).params {
+ match param.kind {
+ GenericParamDefKind::Type(ty) => {
+ if ty.has_default {
+ self.tcx.type_of(param.def_id).visit_with(self);
+ }
+ }
+ GenericParamDefKind::Lifetime => {}
}
}
self
in_body: false,
span: krate.span,
empty_tables: &empty_tables,
+ visited_anon_tys: FxHashSet()
};
intravisit::walk_crate(&mut visitor, krate);
self.ribs[ValueNS].pop();
}
+ ExprKind::Block(ref block, label) => self.resolve_labeled_block(label, block.id, block),
+
// Equivalent to `visit::walk_expr` + passing some context to children.
ExprKind::Field(ref subexpression, _) => {
self.resolve_expr(subexpression, Some(expr));
rustc_typeck = { path = "../librustc_typeck" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
-rls-data = "0.15"
+rls-data = "0.16"
rls-span = "0.4"
# FIXME(#40527) should move rustc serialize out of tree
rustc-serialize = "0.3"
}
}
- fn process_def_kind(
- &mut self,
- ref_id: NodeId,
- span: Span,
- sub_span: Option<Span>,
- def_id: DefId,
- ) {
- if self.span.filter_generated(sub_span, span) {
- return;
- }
-
- let def = self.save_ctxt.get_path_def(ref_id);
- match def {
- HirDef::Mod(_) => {
- let span = self.span_from_span(sub_span.expect("No span found for mod ref"));
- self.dumper.dump_ref(Ref {
- kind: RefKind::Mod,
- span,
- ref_id: ::id_from_def_id(def_id),
- });
- }
- HirDef::Struct(..) |
- HirDef::Variant(..) |
- HirDef::Union(..) |
- HirDef::Enum(..) |
- HirDef::TyAlias(..) |
- HirDef::TyForeign(..) |
- HirDef::TraitAlias(..) |
- HirDef::Trait(_) => {
- let span = self.span_from_span(sub_span.expect("No span found for type ref"));
- self.dumper.dump_ref(Ref {
- kind: RefKind::Type,
- span,
- ref_id: ::id_from_def_id(def_id),
- });
- }
- HirDef::Static(..) |
- HirDef::Const(..) |
- HirDef::StructCtor(..) |
- HirDef::VariantCtor(..) => {
- let span = self.span_from_span(sub_span.expect("No span found for var ref"));
- self.dumper.dump_ref(Ref {
- kind: RefKind::Variable,
- span,
- ref_id: ::id_from_def_id(def_id),
- });
- }
- HirDef::Fn(..) => {
- let span = self.span_from_span(sub_span.expect("No span found for fn ref"));
- self.dumper.dump_ref(Ref {
- kind: RefKind::Function,
- span,
- ref_id: ::id_from_def_id(def_id),
- });
- }
- // With macros 2.0, we can legitimately get a ref to a macro, but
- // we don't handle it properly for now (FIXME).
- HirDef::Macro(..) => {}
- HirDef::Local(..) |
- HirDef::Upvar(..) |
- HirDef::SelfTy(..) |
- HirDef::Label(_) |
- HirDef::TyParam(..) |
- HirDef::Method(..) |
- HirDef::AssociatedTy(..) |
- HirDef::AssociatedConst(..) |
- HirDef::PrimTy(_) |
- HirDef::GlobalAsm(_) |
- HirDef::Err => {
- span_bug!(span, "process_def_kind for unexpected item: {:?}", def);
- }
- }
- }
-
fn process_formals(&mut self, formals: &'l [ast::Arg], qualname: &str) {
for arg in formals {
self.visit_pat(&arg.pat);
};
let sub_span = self.span.span_for_last_ident(path.span);
- let mod_id = match self.lookup_def_id(id) {
- Some(def_id) => {
- self.process_def_kind(id, path.span, sub_span, def_id);
- Some(def_id)
- }
- None => None,
- };
-
- // 'use' always introduces an alias, if there is not an explicit
- // one, there is an implicit one.
- let sub_span = match self.span.sub_span_after_keyword(use_tree.span,
- keywords::As) {
- Some(sub_span) => Some(sub_span),
- None => sub_span,
- };
+ let alias_span = self.span.sub_span_after_keyword(use_tree.span, keywords::As);
+ let ref_id = self.lookup_def_id(id);
if !self.span.filter_generated(sub_span, path.span) {
- let span =
- self.span_from_span(sub_span.expect("No span found for use"));
+ let span = self.span_from_span(sub_span.expect("No span found for use"));
+ let alias_span = alias_span.map(|sp| self.span_from_span(sp));
self.dumper.import(&access, Import {
kind: ImportKind::Use,
- ref_id: mod_id.map(|id| ::id_from_def_id(id)),
+ ref_id: ref_id.map(|id| ::id_from_def_id(id)),
span,
+ alias_span,
name: ident.to_string(),
value: String::new(),
parent,
kind: ImportKind::GlobUse,
ref_id: None,
span,
+ alias_span: None,
name: "*".to_owned(),
value: names.join(", "),
parent,
kind: ImportKind::ExternCrate,
ref_id: None,
span,
+ alias_span: None,
name: item.ident.to_string(),
value: String::new(),
parent,
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(custom_attribute)]
-#![feature(macro_lifetime_matcher)]
+#![cfg_attr(stage0, feature(macro_lifetime_matcher))]
#![allow(unused_attributes)]
#[macro_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.
+
+use spec::{LinkerFlavor, Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::openbsd_base::opts();
+ base.max_atomic_width = Some(128);
+ base.abi_blacklist = super::arm_base::abi_blacklist();
+
+ Ok(Target {
+ llvm_target: "aarch64-unknown-openbsd".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: "aarch64".to_string(),
+ target_os: "openbsd".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: base,
+ })
+}
base.cpu = "pentium4".to_string();
base.max_atomic_width = Some(64);
base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m32".to_string());
+ base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-fuse-ld=lld".to_string());
base.stack_probes = true;
Ok(Target {
("x86_64-unknown-bitrig", x86_64_unknown_bitrig),
+ ("aarch64-unknown-openbsd", aarch64_unknown_openbsd),
("i686-unknown-openbsd", i686_unknown_openbsd),
("x86_64-unknown-openbsd", x86_64_unknown_openbsd),
use rustc::traits::query::{CanonicalTyGoal, NoSolution};
use rustc::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
-use rustc::ty::subst::Subst;
+use rustc::ty::subst::{Subst, Substs};
use rustc::util::nodemap::FxHashSet;
use rustc_data_structures::sync::Lrc;
use syntax::codemap::{Span, DUMMY_SP};
debug!("dtorck_constraint: {:?}", def);
if def.is_phantom_data() {
+ // The first generic parameter here is guaranteed to be a type because it's
+ // `PhantomData`.
+ let substs = Substs::identity_for_item(tcx, def_id);
+ assert_eq!(substs.len(), 1);
let result = DtorckConstraint {
outlives: vec![],
- dtorck_types: vec![tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0])],
+ dtorck_types: vec![substs.type_at(0)],
overflows: vec![],
};
debug!("dtorck_constraint: {:?} => {:?}", def, result);
//! the guts are broken up into modules; see the comments in those modules.
#![feature(crate_visibility_modifier)]
+#![feature(iterator_find_map)]
#[macro_use]
extern crate log;
test = false
[dependencies]
+bitflags = "1.0.1"
cc = "1.0.1"
flate2 = "1.0"
jobserver = "0.1.5"
use llvm::{self, ValueRef, AttributePlace};
use base;
-use builder::Builder;
+use builder::{Builder, MemFlags};
use common::{ty_fn_sig, C_usize};
use context::CodegenCx;
use mir::place::PlaceRef;
bx.pointercast(dst.llval, Type::i8p(cx)),
bx.pointercast(llscratch, Type::i8p(cx)),
C_usize(cx, self.layout.size.bytes()),
- self.layout.align.min(scratch_align));
+ self.layout.align.min(scratch_align),
+ MemFlags::empty());
bx.lifetime_end(llscratch, scratch_size);
}
}) => {
let def_id = tcx.hir.local_def_id(node_id);
let generics = tcx.generics_of(def_id);
- if (generics.parent_types == 0 && generics.types.is_empty()) &&
+ if !generics.requires_monomorphization(tcx) &&
// Functions marked with #[inline] are only ever translated
// with "internal" linkage and are never exported.
!Instance::mono(tcx, def_id).def.requires_local(tcx) {
use allocator;
use mir::place::PlaceRef;
use attributes;
-use builder::Builder;
+use builder::{Builder, MemFlags};
use callee;
use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode};
if src_f.layout.ty == dst_f.layout.ty {
memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout,
- src_f.align.min(dst_f.align));
+ src_f.align.min(dst_f.align), MemFlags::empty());
} else {
coerce_unsized_into(bx, src_f, dst_f);
}
dst: ValueRef,
src: ValueRef,
n_bytes: ValueRef,
- align: Align) {
+ align: Align,
+ flags: MemFlags) {
+ if flags.contains(MemFlags::NONTEMPORAL) {
+ // HACK(nox): This is inefficient but there is no nontemporal memcpy.
+ let val = bx.load(src, align);
+ let ptr = bx.pointercast(dst, val_ty(val).ptr_to());
+ bx.store_with_flags(val, ptr, align, flags);
+ return;
+ }
let cx = bx.cx;
let ptr_width = &cx.sess().target.target.target_pointer_width;
let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
let dst_ptr = bx.pointercast(dst, Type::i8p(cx));
let size = bx.intcast(n_bytes, cx.isize_ty, false);
let align = C_i32(cx, align.abi() as i32);
- let volatile = C_bool(cx, false);
+ let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE));
bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
}
src: ValueRef,
layout: TyLayout<'tcx>,
align: Align,
+ flags: MemFlags,
) {
let size = layout.size.bytes();
if size == 0 {
return;
}
- call_memcpy(bx, dst, src, C_usize(bx.cx, size), align);
+ call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags);
}
pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
&CNULL
}
+bitflags! {
+ pub struct MemFlags: u8 {
+ const VOLATILE = 1 << 0;
+ const NONTEMPORAL = 1 << 1;
+ }
+}
+
impl<'a, 'tcx> Builder<'a, 'tcx> {
pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self {
let bx = Builder::with_cx(cx);
}
pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef {
- debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
+ self.store_with_flags(val, ptr, align, MemFlags::empty())
+ }
+
+ pub fn store_with_flags(
+ &self,
+ val: ValueRef,
+ ptr: ValueRef,
+ align: Align,
+ flags: MemFlags,
+ ) -> ValueRef {
+ debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags);
assert!(!self.llbuilder.is_null());
self.count_insn("store");
let ptr = self.check_store(val, ptr);
unsafe {
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
llvm::LLVMSetAlignment(store, align.abi() as c_uint);
+ if flags.contains(MemFlags::VOLATILE) {
+ llvm::LLVMSetVolatile(store, llvm::True);
+ }
+ if flags.contains(MemFlags::NONTEMPORAL) {
+ // According to LLVM [1] building a nontemporal store must
+ // *always* point to a metadata value of the integer 1.
+ //
+ // [1]: http://llvm.org/docs/LangRef.html#store-instruction
+ let one = C_i32(self.cx, 1);
+ let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1);
+ llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node);
+ }
store
}
}
- pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
- debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
- assert!(!self.llbuilder.is_null());
- self.count_insn("store.volatile");
- let ptr = self.check_store(val, ptr);
- unsafe {
- let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
- llvm::LLVMSetVolatile(insn, llvm::True);
- insn
- }
- }
-
pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef,
order: AtomicOrdering, align: Align) {
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
}
}
- pub fn nontemporal_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
- debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
- assert!(!self.llbuilder.is_null());
- self.count_insn("store.nontemporal");
- let ptr = self.check_store(val, ptr);
- unsafe {
- let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
-
- // According to LLVM [1] building a nontemporal store must *always*
- // point to a metadata value of the integer 1. Who knew?
- //
- // [1]: http://llvm.org/docs/LangRef.html#store-instruction
- let one = C_i32(self.cx, 1);
- let node = llvm::LLVMMDNodeInContext(self.cx.llcx,
- &one,
- 1);
- llvm::LLVMSetMetadata(insn,
- llvm::MD_nontemporal as c_uint,
- node);
- insn
- }
- }
-
pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef {
self.count_insn("gep");
unsafe {
use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags};
use rustc::hir::TransFnAttrFlags;
use rustc::hir::def_id::{DefId, CrateNum};
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, UnpackedKind};
use abi::Abi;
use common::CodegenCx;
// Again, only create type information if full debuginfo is enabled
let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
- let names = get_type_parameter_names(cx, generics);
- substs.types().zip(names).map(|(ty, name)| {
- let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
- let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
- let name = CString::new(name.as_str().as_bytes()).unwrap();
- unsafe {
- llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
- DIB(cx),
- ptr::null_mut(),
- name.as_ptr(),
- actual_type_metadata,
- file_metadata,
- 0,
- 0)
+ let names = get_parameter_names(cx, generics);
+ substs.iter().zip(names).filter_map(|(kind, name)| {
+ if let UnpackedKind::Type(ty) = kind.unpack() {
+ let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
+ let actual_type_metadata =
+ type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
+ let name = CString::new(name.as_str().as_bytes()).unwrap();
+ Some(unsafe {
+ llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
+ DIB(cx),
+ ptr::null_mut(),
+ name.as_ptr(),
+ actual_type_metadata,
+ file_metadata,
+ 0,
+ 0)
+ })
+ } else {
+ None
}
}).collect()
} else {
return create_DIArray(DIB(cx), &template_params[..]);
}
- fn get_type_parameter_names(cx: &CodegenCx, generics: &ty::Generics) -> Vec<InternedString> {
+ fn get_parameter_names(cx: &CodegenCx,
+ generics: &ty::Generics)
+ -> Vec<InternedString> {
let mut names = generics.parent.map_or(vec![], |def_id| {
- get_type_parameter_names(cx, cx.tcx.generics_of(def_id))
+ get_parameter_names(cx, cx.tcx.generics_of(def_id))
});
- names.extend(generics.types.iter().map(|param| param.name));
+ names.extend(generics.params.iter().map(|param| param.name));
names
}
to_immediate(bx, load, cx.layout_of(tp_ty))
},
"volatile_store" => {
- let tp_ty = substs.type_at(0);
let dst = args[0].deref(bx.cx);
- if let OperandValue::Pair(a, b) = args[1].val {
- bx.volatile_store(a, dst.project_field(bx, 0).llval);
- bx.volatile_store(b, dst.project_field(bx, 1).llval);
- } else {
- let val = if let OperandValue::Ref(ptr, align) = args[1].val {
- bx.load(ptr, align)
- } else {
- if dst.layout.is_zst() {
- return;
- }
- from_immediate(bx, args[1].immediate())
- };
- let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to());
- let store = bx.volatile_store(val, ptr);
- unsafe {
- llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32);
- }
- }
+ args[1].val.volatile_store(bx, dst);
return;
},
"prefetch_read_data" | "prefetch_write_data" |
}
"nontemporal_store" => {
- let tp_ty = substs.type_at(0);
let dst = args[0].deref(bx.cx);
- let val = if let OperandValue::Ref(ptr, align) = args[1].val {
- bx.load(ptr, align)
- } else {
- from_immediate(bx, args[1].immediate())
- };
- let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to());
- let store = bx.nontemporal_store(val, ptr);
- unsafe {
- llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32);
- }
- return
+ args[1].val.nontemporal_store(bx, dst);
+ return;
}
_ => {
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;
+#[macro_use] extern crate bitflags;
extern crate flate2;
extern crate libc;
#[macro_use] extern crate rustc;
use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode};
use base;
use callee;
-use builder::Builder;
+use builder::{Builder, MemFlags};
use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef};
use consts;
use meth;
// have scary latent bugs around.
let scratch = PlaceRef::alloca(bx, arg.layout, "arg");
- base::memcpy_ty(bx, scratch.llval, llval, op.layout, align);
+ base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty());
(scratch.llval, scratch.align, true)
} else {
(llval, align, true)
use base;
use common::{self, CodegenCx, C_null, C_undef, C_usize};
-use builder::Builder;
+use builder::{Builder, MemFlags};
use value::Value;
use type_of::LayoutLlvmExt;
use type_::Type;
impl<'a, 'tcx> OperandValue {
pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+ self.store_with_flags(bx, dest, MemFlags::empty());
+ }
+
+ pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+ self.store_with_flags(bx, dest, MemFlags::VOLATILE);
+ }
+
+ pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) {
+ self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
+ }
+
+ fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) {
debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
// Avoid generating stores of zero-sized values, because the only way to have a zero-sized
// value is through `undef`, and store itself is useless.
return;
}
match self {
- OperandValue::Ref(r, source_align) =>
+ OperandValue::Ref(r, source_align) => {
base::memcpy_ty(bx, dest.llval, r, dest.layout,
- source_align.min(dest.align)),
+ source_align.min(dest.align), flags)
+ }
OperandValue::Immediate(s) => {
- bx.store(base::from_immediate(bx, s), dest.llval, dest.align);
+ let val = base::from_immediate(bx, s);
+ bx.store_with_flags(val, dest.llval, dest.align, flags);
}
OperandValue::Pair(a, b) => {
for (i, &x) in [a, b].iter().enumerate() {
if common::val_ty(x) == Type::i1(bx.cx) {
llptr = bx.pointercast(llptr, Type::i8p(bx.cx));
}
- bx.store(base::from_immediate(bx, x), llptr, dest.align);
+ let val = base::from_immediate(bx, x);
+ bx.store_with_flags(val, llptr, dest.align, flags);
}
}
}
use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
use rustc::traits;
use rustc::ty::{self, RegionKind, Ty, TyCtxt, ToPredicate, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
use rustc::ty::wf::object_region_bounds;
use rustc_target::spec::abi;
use std::slice;
-> ty::GenericPredicates<'tcx>;
/// What lifetime should we use when a lifetime is omitted (and not elided)?
- fn re_infer(&self, span: Span, _def: Option<&ty::RegionParameterDef>)
+ fn re_infer(&self, span: Span, _def: Option<&ty::GenericParamDef>)
-> Option<ty::Region<'tcx>>;
/// What type should we use when a type is omitted?
/// Same as ty_infer, but with a known type parameter definition.
fn ty_infer_for_def(&self,
- _def: &ty::TypeParameterDef,
+ _def: &ty::GenericParamDef,
span: Span) -> Ty<'tcx> {
self.ty_infer(span)
}
span: Span,
}
+struct ParamRange {
+ required: usize,
+ accepted: usize
+}
+
/// Dummy type used for the `Self` of a `TraitRef` created for converting
/// a trait object, and which gets removed in `ExistentialTraitRef`.
/// This type must not appear anywhere in other converted types.
impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
pub fn ast_region_to_region(&self,
lifetime: &hir::Lifetime,
- def: Option<&ty::RegionParameterDef>)
+ def: Option<&ty::GenericParamDef>)
-> ty::Region<'tcx>
{
let tcx = self.tcx();
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
let decl_generics = tcx.generics_of(def_id);
- let num_types_provided = parameters.types.len();
- let expected_num_region_params = decl_generics.regions.len();
- let supplied_num_region_params = parameters.lifetimes.len();
- if expected_num_region_params != supplied_num_region_params {
- report_lifetime_number_error(tcx, span,
- supplied_num_region_params,
- expected_num_region_params);
+ let ty_provided = parameters.types.len();
+ let lt_provided = parameters.lifetimes.len();
+
+ let mut lt_accepted = 0;
+ let mut ty_params = ParamRange { required: 0, accepted: 0 };
+ for param in &decl_generics.params {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ lt_accepted += 1;
+ }
+ GenericParamDefKind::Type(ty) => {
+ ty_params.accepted += 1;
+ if !ty.has_default {
+ ty_params.required += 1;
+ }
+ }
+ };
+ }
+ if self_ty.is_some() {
+ ty_params.required -= 1;
+ ty_params.accepted -= 1;
+ }
+
+ if lt_accepted != lt_provided {
+ report_lifetime_number_error(tcx, span, lt_provided, lt_accepted);
}
// If a self-type was declared, one should be provided.
assert_eq!(decl_generics.has_self, self_ty.is_some());
// Check the number of type parameters supplied by the user.
- let ty_param_defs = &decl_generics.types[self_ty.is_some() as usize..];
- if !infer_types || num_types_provided > ty_param_defs.len() {
- check_type_argument_count(tcx, span, num_types_provided, ty_param_defs);
+ if !infer_types || ty_provided > ty_params.required {
+ check_type_argument_count(tcx, span, ty_provided, ty_params);
}
let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
- let default_needs_object_self = |p: &ty::TypeParameterDef| {
- if is_object && p.has_default {
- if tcx.at(span).type_of(p.def_id).has_self_ty() {
- // There is no suitable inference default for a type parameter
- // that references self, in an object type.
- return true;
+ let default_needs_object_self = |param: &ty::GenericParamDef| {
+ if let GenericParamDefKind::Type(ty) = param.kind {
+ if is_object && ty.has_default {
+ if tcx.at(span).type_of(param.def_id).has_self_ty() {
+ // There is no suitable inference default for a type parameter
+ // that references self, in an object type.
+ return true;
+ }
}
}
false
};
- let substs = Substs::for_item(tcx, def_id, |def, _| {
- let i = def.index as usize - self_ty.is_some() as usize;
- if let Some(lifetime) = parameters.lifetimes.get(i) {
- self.ast_region_to_region(lifetime, Some(def))
- } else {
- tcx.types.re_static
- }
- }, |def, substs| {
- let i = def.index as usize;
+ let own_self = self_ty.is_some() as usize;
+ let substs = Substs::for_item(tcx, def_id, |param, substs| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ let i = param.index as usize - own_self;
+ if let Some(lifetime) = parameters.lifetimes.get(i) {
+ self.ast_region_to_region(lifetime, Some(param)).into()
+ } else {
+ tcx.types.re_static.into()
+ }
+ }
+ GenericParamDefKind::Type(ty) => {
+ let i = param.index as usize;
- // Handle Self first, so we can adjust the index to match the AST.
- if let (0, Some(ty)) = (i, self_ty) {
- return ty;
- }
+ // Handle Self first, so we can adjust the index to match the AST.
+ if let (0, Some(ty)) = (i, self_ty) {
+ return ty.into();
+ }
- let i = i - self_ty.is_some() as usize - decl_generics.regions.len();
- if i < num_types_provided {
- // A provided type parameter.
- self.ast_ty_to_ty(¶meters.types[i])
- } else if infer_types {
- // No type parameters were provided, we can infer all.
- let ty_var = if !default_needs_object_self(def) {
- self.ty_infer_for_def(def, span)
- } else {
- self.ty_infer(span)
- };
- ty_var
- } else if def.has_default {
- // No type parameter provided, but a default exists.
-
- // If we are converting an object type, then the
- // `Self` parameter is unknown. However, some of the
- // other type parameters may reference `Self` in their
- // defaults. This will lead to an ICE if we are not
- // careful!
- if default_needs_object_self(def) {
- struct_span_err!(tcx.sess, span, E0393,
- "the type parameter `{}` must be explicitly specified",
- def.name)
- .span_label(span, format!("missing reference to `{}`", def.name))
- .note(&format!("because of the default `Self` reference, \
- type parameters must be specified on object types"))
- .emit();
- tcx.types.err
- } else {
- // This is a default type parameter.
- self.normalize_ty(
- span,
- tcx.at(span).type_of(def.def_id)
- .subst_spanned(tcx, substs, Some(span))
- )
+ let i = i - (lt_accepted + own_self);
+ if i < ty_provided {
+ // A provided type parameter.
+ self.ast_ty_to_ty(¶meters.types[i]).into()
+ } else if infer_types {
+ // No type parameters were provided, we can infer all.
+ if !default_needs_object_self(param) {
+ self.ty_infer_for_def(param, span).into()
+ } else {
+ self.ty_infer(span).into()
+ }
+ } else if ty.has_default {
+ // No type parameter provided, but a default exists.
+
+ // If we are converting an object type, then the
+ // `Self` parameter is unknown. However, some of the
+ // other type parameters may reference `Self` in their
+ // defaults. This will lead to an ICE if we are not
+ // careful!
+ if default_needs_object_self(param) {
+ struct_span_err!(tcx.sess, span, E0393,
+ "the type parameter `{}` must be explicitly \
+ specified",
+ param.name)
+ .span_label(span,
+ format!("missing reference to `{}`", param.name))
+ .note(&format!("because of the default `Self` reference, \
+ type parameters must be specified on object \
+ types"))
+ .emit();
+ tcx.types.err.into()
+ } else {
+ // This is a default type parameter.
+ self.normalize_ty(
+ span,
+ tcx.at(span).type_of(param.def_id)
+ .subst_spanned(tcx, substs, Some(span))
+ ).into()
+ }
+ } else {
+ // We've already errored above about the mismatch.
+ tcx.types.err.into()
+ }
}
- } else {
- // We've already errored above about the mismatch.
- tcx.types.err
}
});
let item_id = tcx.hir.get_parent_node(node_id);
let item_def_id = tcx.hir.local_def_id(item_id);
let generics = tcx.generics_of(item_def_id);
- let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id)];
- tcx.mk_param(index, tcx.hir.name(node_id).as_interned_str())
+ let index = generics.param_def_id_to_index[&tcx.hir.local_def_id(node_id)];
+ tcx.mk_ty_param(index, tcx.hir.name(node_id).as_interned_str())
}
Def::SelfTy(_, Some(def_id)) => {
// Self in impl (we know the concrete type).
let mut substs = Vec::with_capacity(generics.count());
if let Some(parent_id) = generics.parent {
let parent_generics = tcx.generics_of(parent_id);
- Substs::fill_item(
- &mut substs, tcx, parent_generics,
- &mut |def, _| tcx.mk_region(
- ty::ReEarlyBound(def.to_early_bound_region_data())),
- &mut |def, _| tcx.mk_param_from_def(def)
- );
+ Substs::fill_item(&mut substs, tcx, parent_generics, &mut |param, _| {
+ tcx.mk_param_from_def(param)
+ });
// Replace all lifetimes with 'static
for subst in &mut substs {
}
debug!("impl_trait_ty_to_ty: substs from parent = {:?}", substs);
}
- assert_eq!(substs.len(), generics.parent_count());
+ assert_eq!(substs.len(), generics.parent_count);
// Fill in our own generics with the resolved lifetimes
- assert_eq!(lifetimes.len(), generics.own_count());
+ assert_eq!(lifetimes.len(), generics.params.len());
substs.extend(lifetimes.iter().map(|lt| Kind::from(self.ast_region_to_region(lt, None))));
debug!("impl_trait_ty_to_ty: final substs = {:?}", substs);
(auto_traits, trait_bounds)
}
-fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
- ty_param_defs: &[ty::TypeParameterDef]) {
- let accepted = ty_param_defs.len();
- let required = ty_param_defs.iter().take_while(|x| !x.has_default).count();
+fn check_type_argument_count(tcx: TyCtxt,
+ span: Span,
+ supplied: usize,
+ ty_params: ParamRange)
+{
+ let (required, accepted) = (ty_params.required, ty_params.accepted);
if supplied < required {
let expected = if required < accepted {
"expected at least"
arm_span: arm.body.span,
source: match_src
});
- coercion.coerce(self, &cause, &arm.body, arm_ty, self.diverges.get());
+ coercion.coerce(self, &cause, &arm.body, arm_ty);
}
}
use rustc::infer::LateBoundRegionConversionTime;
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::error_reporting::ArgKind;
-use rustc::ty::{self, ToPolyTraitRef, Ty};
+use rustc::ty::{self, ToPolyTraitRef, Ty, GenericParamDefKind};
use rustc::ty::subst::Substs;
use rustc::ty::TypeFoldable;
use std::cmp;
// inference phase (`upvar.rs`).
let base_substs =
Substs::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id));
- let substs = base_substs.extend_to(
- self.tcx,
- expr_def_id,
- |_, _| span_bug!(expr.span, "closure has region param"),
- |_, _| {
- self.infcx
- .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span))
- },
- );
+ let substs = base_substs.extend_to(self.tcx,expr_def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ span_bug!(expr.span, "closure has region param")
+ }
+ GenericParamDefKind::Type(_) => {
+ self.infcx
+ .next_ty_var(TypeVariableOrigin::ClosureSynthetic(expr.span)).into()
+ }
+ }
+ });
if let Some(GeneratorTypes { yield_ty, interior, movability }) = generator_types {
let substs = ty::GeneratorSubsts { substs };
self.demand_eqtype(
//! sort of a minor point so I've opted to leave it for later---after all
//! we may want to adjust precisely when coercions occur.
-use check::{Diverges, FnCtxt, Needs};
+use check::{FnCtxt, Needs};
use rustc::hir;
use rustc::hir::def_id::DefId;
exprs: &[E],
prev_ty: Ty<'tcx>,
new: &hir::Expr,
- new_ty: Ty<'tcx>,
- new_diverges: Diverges)
+ new_ty: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>
where E: AsCoercionSite
{
let new_ty = self.resolve_type_vars_with_obligations(new_ty);
debug!("coercion::try_find_coercion_lub({:?}, {:?})", prev_ty, new_ty);
- // Special-ish case: we can coerce any type `T` into the `!`
- // type, but only if the source expression diverges.
- if prev_ty.is_never() && new_diverges.always() {
- debug!("permit coercion to `!` because expr diverges");
- return Ok(prev_ty);
- }
-
// Special-case that coercion alone cannot handle:
// Two function item types of differing IDs or Substs.
if let (&ty::TyFnDef(..), &ty::TyFnDef(..)) = (&prev_ty.sty, &new_ty.sty) {
fcx: &FnCtxt<'a, 'gcx, 'tcx>,
cause: &ObligationCause<'tcx>,
expression: &'gcx hir::Expr,
- expression_ty: Ty<'tcx>,
- expression_diverges: Diverges)
+ expression_ty: Ty<'tcx>)
{
self.coerce_inner(fcx,
cause,
Some(expression),
expression_ty,
- expression_diverges,
None, false)
}
cause,
None,
fcx.tcx.mk_nil(),
- Diverges::Maybe,
Some(augment_error),
label_unit_as_expected)
}
cause: &ObligationCause<'tcx>,
expression: Option<&'gcx hir::Expr>,
mut expression_ty: Ty<'tcx>,
- expression_diverges: Diverges,
augment_error: Option<&mut FnMut(&mut DiagnosticBuilder)>,
label_expression_as_expected: bool)
{
exprs,
self.merged_ty(),
expression,
- expression_ty,
- expression_diverges),
+ expression_ty),
Expressions::UpFront(ref coercion_sites) =>
fcx.try_find_coercion_lub(cause,
&coercion_sites[0..self.pushed],
self.merged_ty(),
expression,
- expression_ty,
- expression_diverges),
+ expression_ty),
}
}
} else {
use rustc::hir::{self, ImplItemKind, TraitItemKind};
use rustc::infer::{self, InferOk};
-use rustc::ty::{self, TyCtxt};
+use rustc::ty::{self, TyCtxt, GenericParamDefKind};
use rustc::ty::util::ExplicitSelf;
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
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[..];
+ let trait_params = trait_generics.own_counts().lifetimes;
+ let impl_params = impl_generics.own_counts().lifetimes;
debug!("check_region_bounds_on_impl_method: \
trait_generics={:?} \
// but found 0" it's confusing, because it looks like there
// 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() {
+ if trait_params != impl_params {
let mut err = struct_span_err!(tcx.sess,
span,
E0195,
-> Result<(), ErrorReported> {
let impl_m_generics = tcx.generics_of(impl_m.def_id);
let trait_m_generics = tcx.generics_of(trait_m.def_id);
- let num_impl_m_type_params = impl_m_generics.types.len();
- let num_trait_m_type_params = trait_m_generics.types.len();
+ let num_impl_m_type_params = impl_m_generics.own_counts().types;
+ let num_trait_m_type_params = trait_m_generics.own_counts().types;
if num_impl_m_type_params != num_trait_m_type_params {
let impl_m_node_id = tcx.hir.as_local_node_id(impl_m.def_id).unwrap();
let impl_m_item = tcx.hir.expect_impl_item(impl_m_node_id);
let mut error_found = false;
let impl_m_generics = tcx.generics_of(impl_m.def_id);
let trait_m_generics = tcx.generics_of(trait_m.def_id);
- for (impl_ty, trait_ty) in impl_m_generics.types.iter().zip(trait_m_generics.types.iter()) {
- if impl_ty.synthetic != trait_ty.synthetic {
- let impl_node_id = tcx.hir.as_local_node_id(impl_ty.def_id).unwrap();
+ let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| {
+ match param.kind {
+ GenericParamDefKind::Type(ty) => Some((param.def_id, ty.synthetic)),
+ GenericParamDefKind::Lifetime => None,
+ }
+ });
+ let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| {
+ match param.kind {
+ GenericParamDefKind::Type(ty) => Some((param.def_id, ty.synthetic)),
+ GenericParamDefKind::Lifetime => None,
+ }
+ });
+ for ((impl_def_id, impl_synthetic),
+ (trait_def_id, trait_synthetic)) in impl_m_type_params.zip(trait_m_type_params) {
+ if impl_synthetic != trait_synthetic {
+ let impl_node_id = tcx.hir.as_local_node_id(impl_def_id).unwrap();
let impl_span = tcx.hir.span(impl_node_id);
- let trait_span = tcx.def_span(trait_ty.def_id);
+ let trait_span = tcx.def_span(trait_def_id);
let mut err = struct_span_err!(tcx.sess,
impl_span,
E0643,
}
}
- let i_n_tps = tcx.generics_of(def_id).types.len();
+ let i_n_tps = tcx.generics_of(def_id).own_counts().types;
if i_n_tps != n_tps {
let span = match it.node {
hir::ForeignItemFn(_, _, ref generics) => generics.span,
/// and in libcore/intrinsics.rs
pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
it: &hir::ForeignItem) {
- let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
+ let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)).as_interned_str());
let name = it.name.as_str();
let (n_tps, inputs, output) = if name.starts_with("atomic_") {
let split : Vec<&str> = name.split('_').collect();
it: &hir::ForeignItem) {
let param = |n| {
let name = Symbol::intern(&format!("P{}", n)).as_interned_str();
- tcx.mk_param(n, name)
+ tcx.mk_ty_param(n, name)
};
let def_id = tcx.hir.local_def_id(it.id);
- let i_n_tps = tcx.generics_of(def_id).types.len();
+ let i_n_tps = tcx.generics_of(def_id).own_counts().types;
let name = it.name.as_str();
let (n_tps, inputs, output) = match &*name {
use hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::traits;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, GenericParamDefKind};
use rustc::ty::subst::Subst;
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
use rustc::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
// Create subst for early-bound lifetime parameters, combining
// parameters from the type and those from the method.
- assert_eq!(method_generics.parent_count(), parent_substs.len());
+ assert_eq!(method_generics.parent_count, parent_substs.len());
let provided = &segment.parameters;
- Substs::for_item(self.tcx, pick.item.def_id, |def, _| {
- let i = def.index as usize;
+ let own_counts = method_generics.own_counts();
+ Substs::for_item(self.tcx, pick.item.def_id, |param, _| {
+ let i = param.index as usize;
if i < parent_substs.len() {
- parent_substs.region_at(i)
- } else if let Some(lifetime)
- = provided.as_ref().and_then(|p| p.lifetimes.get(i - parent_substs.len())) {
- AstConv::ast_region_to_region(self.fcx, lifetime, Some(def))
+ parent_substs[i]
} else {
- self.region_var_for_def(self.span, def)
- }
- }, |def, _cur_substs| {
- let i = def.index as usize;
- if i < parent_substs.len() {
- parent_substs.type_at(i)
- } else if let Some(ast_ty)
- = provided.as_ref().and_then(|p| {
- p.types.get(i - parent_substs.len() - method_generics.regions.len())
- })
- {
- self.to_ty(ast_ty)
- } else {
- self.type_var_for_def(self.span, def)
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ if let Some(lifetime) = provided.as_ref().and_then(|p| {
+ p.lifetimes.get(i - parent_substs.len())
+ }) {
+ return AstConv::ast_region_to_region(
+ self.fcx, lifetime, Some(param)).into();
+ }
+ }
+ GenericParamDefKind::Type(_) => {
+ if let Some(ast_ty) = provided.as_ref().and_then(|p| {
+ p.types.get(i - parent_substs.len() - own_counts.lifetimes)
+ }) {
+ return self.to_ty(ast_ty).into();
+ }
+ }
+ }
+ self.var_for_def(self.span, param)
}
})
}
use rustc::ty::subst::Substs;
use rustc::traits;
use rustc::ty::{self, Ty, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
use rustc::ty::subst::Subst;
use rustc::infer::{self, InferOk};
trait_def_id);
// Construct a trait-reference `self_ty : Trait<input_tys>`
- let substs = Substs::for_item(self.tcx,
- trait_def_id,
- |def, _| self.region_var_for_def(span, def),
- |def, _substs| {
- if def.index == 0 {
- self_ty
- } else if let Some(ref input_types) = opt_input_types {
- input_types[def.index as usize - 1]
- } else {
- self.type_var_for_def(span, def)
+ let substs = Substs::for_item(self.tcx, trait_def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {}
+ GenericParamDefKind::Type(_) => {
+ if param.index == 0 {
+ return self_ty.into();
+ } else if let Some(ref input_types) = opt_input_types {
+ return input_types[param.index as usize - 1].into();
+ }
+ }
}
+ self.var_for_def(span, param)
});
let trait_ref = ty::TraitRef::new(trait_def_id, substs);
let method_item = self.associated_item(trait_def_id, m_name, Namespace::Value).unwrap();
let def_id = method_item.def_id;
let generics = tcx.generics_of(def_id);
- assert_eq!(generics.types.len(), 0);
- assert_eq!(generics.regions.len(), 0);
+ assert_eq!(generics.params.len(), 0);
debug!("lookup_in_trait_adjusted: method_item={:?}", method_item);
let mut obligations = vec![];
use rustc::ty::subst::{Subst, Substs};
use rustc::traits::{self, ObligationCause};
use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
+use rustc::ty::GenericParamDefKind;
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::util::nodemap::FxHashSet;
use rustc::infer::{self, InferOk};
// method yet. So create fresh variables here for those too,
// if there are any.
let generics = self.tcx.generics_of(method);
- assert_eq!(substs.types().count(), generics.parent_types as usize);
- assert_eq!(substs.regions().count(), generics.parent_regions as usize);
+ assert_eq!(substs.len(), generics.parent_count as usize);
// Erase any late-bound regions from the method and substitute
// in the values from the substitution.
let xform_fn_sig = self.erase_late_bound_regions(&fn_sig);
- if generics.types.is_empty() && generics.regions.is_empty() {
+ if generics.params.is_empty() {
xform_fn_sig.subst(self.tcx, substs)
} else {
- let substs = Substs::for_item(self.tcx, method, |def, _| {
- let i = def.index as usize;
+ let substs = Substs::for_item(self.tcx, method, |param, _| {
+ let i = param.index as usize;
if i < substs.len() {
- substs.region_at(i)
+ substs[i]
} else {
- // In general, during probe we erase regions. See
- // `impl_self_ty()` for an explanation.
- self.tcx.types.re_erased
- }
- }, |def, _cur_substs| {
- let i = def.index as usize;
- if i < substs.len() {
- substs.type_at(i)
- } else {
- self.type_var_for_def(self.span, def)
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ // In general, during probe we erase regions. See
+ // `impl_self_ty()` for an explanation.
+ self.tcx.types.re_erased.into()
+ }
+ GenericParamDefKind::Type(_) => self.var_for_def(self.span, param),
+ }
}
});
xform_fn_sig.subst(self.tcx, substs)
}
fn fresh_item_substs(&self, def_id: DefId) -> &'tcx Substs<'tcx> {
- Substs::for_item(self.tcx,
- def_id,
- |_, _| self.tcx.types.re_erased,
- |_, _| self.next_ty_var(
- TypeVariableOrigin::SubstitutionPlaceholder(
- self.tcx.def_span(def_id))))
+ Substs::for_item(self.tcx, def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => self.tcx.types.re_erased.into(),
+ GenericParamDefKind::Type(_) => {
+ self.next_ty_var(TypeVariableOrigin::SubstitutionPlaceholder(
+ self.tcx.def_span(def_id))).into()
+ }
+ }
+ })
}
/// Replace late-bound-regions bound by `value` with `'static` using
use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region;
use rustc::mir::interpret::{GlobalId};
-use rustc::ty::subst::{Kind, Subst, Substs};
+use rustc::ty::subst::{Kind, UnpackedKind, Subst, Substs};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
-use rustc::ty::{self, Ty, TyCtxt, Visibility, ToPredicate};
+use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate};
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::maps::Providers;
/// you get indicates whether any subexpression that was
/// evaluating up to and including `X` diverged.
///
- /// We use this flag for two purposes:
+ /// We currently use this flag only for diagnostic purposes:
///
/// - To warn about unreachable code: if, after processing a
/// sub-expression but before we have applied the effects of the
/// foo();}` or `{return; 22}`, where we would warn on the
/// `foo()` or `22`.
///
- /// - To permit assignment into a local variable or other place
- /// (including the "return slot") of type `!`. This is allowed
- /// if **either** the type of value being assigned is `!`, which
- /// means the current code is dead, **or** the expression's
- /// diverging flag is true, which means that a diverging value was
- /// wrapped (e.g., `let x: ! = foo(return)`).
- ///
- /// To repeat the last point: an expression represents dead-code
- /// if, after checking it, **either** its type is `!` OR the
- /// diverges flag is set to something other than `Maybe`.
+ /// An expression represents dead-code if, after checking it,
+ /// the diverges flag is set to something other than `Maybe`.
diverges: Cell<Diverges>,
/// Whether any child nodes have any type errors.
} else {
for item in &m.items {
let generics = tcx.generics_of(tcx.hir.local_def_id(item.id));
- if !generics.types.is_empty() {
+ if generics.params.len() - generics.own_counts().lifetimes != 0 {
let mut err = struct_span_err!(tcx.sess, item.span, E0044,
"foreign items may not have type parameters");
err.span_label(item.span, "can't have type parameters");
let item_id = tcx.hir.ty_param_owner(node_id);
let item_def_id = tcx.hir.local_def_id(item_id);
let generics = tcx.generics_of(item_def_id);
- let index = generics.type_param_to_index[&def_id];
+ let index = generics.param_def_id_to_index[&def_id];
ty::GenericPredicates {
parent: None,
predicates: self.param_env.caller_bounds.iter().filter(|predicate| {
}
}
- fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
+ fn re_infer(&self, span: Span, def: Option<&ty::GenericParamDef>)
-> Option<ty::Region<'tcx>> {
let v = match def {
Some(def) => infer::EarlyBoundRegion(span, def.name),
}
fn ty_infer_for_def(&self,
- ty_param_def: &ty::TypeParameterDef,
+ ty_param_def: &ty::GenericParamDef,
span: Span) -> Ty<'tcx> {
- self.type_var_for_def(span, ty_param_def)
+ if let UnpackedKind::Type(ty) = self.var_for_def(span, ty_param_def).unpack() {
+ return ty;
+ }
+ unreachable!()
}
fn projected_ty_from_poly_trait_ref(&self,
&self.cause(return_expr.span,
ObligationCauseCode::ReturnType(return_expr.id)),
return_expr,
- return_expr_ty,
- self.diverges.get());
+ return_expr_ty);
}
let mut coerce: DynamicCoerceMany = CoerceMany::new(coerce_to_ty);
let if_cause = self.cause(sp, ObligationCauseCode::IfExpression);
- coerce.coerce(self, &if_cause, then_expr, then_ty, then_diverges);
+ coerce.coerce(self, &if_cause, then_expr, then_ty);
if let Some(else_expr) = opt_else_expr {
let else_ty = self.check_expr_with_expectation(else_expr, expected);
let else_diverges = self.diverges.get();
- coerce.coerce(self, &if_cause, else_expr, else_ty, else_diverges);
+ coerce.coerce(self, &if_cause, else_expr, else_ty);
// We won't diverge unless both branches do (or the condition does).
self.diverges.set(cond_diverges | then_diverges & else_diverges);
base: &'gcx hir::Expr,
field: &Spanned<ast::Name>) -> Ty<'tcx> {
let expr_t = self.check_expr_with_needs(base, needs);
- let expr_t = self.structurally_resolved_type(expr.span,
+ let expr_t = self.structurally_resolved_type(base.span,
expr_t);
let mut private_candidate = None;
let mut autoderef = self.autoderef(expr.span, expr_t);
if let Some(index) = fields.iter().position(|f| f.name.to_ident() == ident) {
let field = &fields[index];
let field_ty = self.field_ty(expr.span, field, substs);
+ // Save the index of all fields regardless of their visibility in case
+ // of error recovery.
+ self.write_field_index(expr.id, index);
if field.vis.is_accessible_from(def_scope, self.tcx) {
let adjustments = autoderef.adjust_steps(needs);
self.apply_adjustments(base, adjustments);
autoderef.finalize();
- self.write_field_index(expr.id, index);
self.tcx.check_stability(field.did, Some(expr.id), expr.span);
return field_ty;
}
// Warn for non-block expressions with diverging children.
match expr.node {
- hir::ExprBlock(_) |
+ hir::ExprBlock(..) |
hir::ExprLoop(..) | hir::ExprWhile(..) |
hir::ExprIf(..) | hir::ExprMatch(..) => {}
tcx.mk_nil()
}
hir::ExprBreak(destination, ref expr_opt) => {
- if let Some(target_id) = destination.target_id.opt_id() {
- let (e_ty, e_diverges, cause);
+ if let Ok(target_id) = destination.target_id {
+ let (e_ty, cause);
if let Some(ref e) = *expr_opt {
// If this is a break with a value, we need to type-check
// the expression. Get an expected type from the loop context.
// Recurse without `enclosing_breakables` borrowed.
e_ty = self.check_expr_with_hint(e, coerce_to);
- e_diverges = self.diverges.get();
cause = self.misc(e.span);
} else {
// Otherwise, this is a break *without* a value. That's
// always legal, and is equivalent to `break ()`.
e_ty = tcx.mk_nil();
- e_diverges = Diverges::Maybe;
cause = self.misc(expr.span);
}
let ctxt = enclosing_breakables.find_breakable(target_id);
if let Some(ref mut coerce) = ctxt.coerce {
if let Some(ref e) = *expr_opt {
- coerce.coerce(self, &cause, e, e_ty, e_diverges);
+ coerce.coerce(self, &cause, e, e_ty);
} else {
assert!(e_ty.is_nil());
coerce.coerce_forced_unit(self, &cause, &mut |_| (), true);
hir::ExprClosure(capture, ref decl, body_id, _, gen) => {
self.check_expr_closure(expr, capture, &decl, body_id, gen, expected)
}
- hir::ExprBlock(ref body) => {
+ hir::ExprBlock(ref body, _) => {
self.check_block_with_expected(&body, expected)
}
hir::ExprCall(ref callee, ref args) => {
for e in args {
let e_ty = self.check_expr_with_hint(e, coerce_to);
let cause = self.misc(e.span);
- coerce.coerce(self, &cause, e, e_ty, self.diverges.get());
+ coerce.coerce(self, &cause, e, e_ty);
}
coerce.complete(self)
} else {
} else if idx_t.references_error() {
idx_t
} else {
- let base_t = self.structurally_resolved_type(expr.span, base_t);
+ let base_t = self.structurally_resolved_type(base.span, base_t);
match self.lookup_indexing(expr, base, base_t, idx_t, needs) {
Some((index_ty, element_ty)) => {
// two-phase not needed because index_ty is never mutable
};
// In some cases, blocks have just one exit, but other blocks
- // can be targeted by multiple breaks. This cannot happen in
- // normal Rust syntax today, but it can happen when we desugar
+ // can be targeted by multiple breaks. This can happen both
+ // with labeled blocks as well as when we desugar
// a `do catch { ... }` expression.
//
// Example 1:
coerce.coerce(self,
&cause,
tail_expr,
- tail_expr_ty,
- self.diverges.get());
+ tail_expr_ty);
} else {
// Subtle: if there is no explicit tail expression,
// that is typically equivalent to a tail expression
let (fn_start, has_self) = match (type_segment, fn_segment) {
(_, Some((_, generics))) => {
- (generics.parent_count(), generics.has_self)
+ (generics.parent_count, generics.has_self)
}
(Some((_, generics)), None) => {
- (generics.own_count(), generics.has_self)
+ (generics.params.len(), generics.has_self)
}
(None, None) => (0, false)
};
- let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| {
- let mut i = def.index as usize;
+ let substs = Substs::for_item(self.tcx, def.def_id(), |param, substs| {
+ let mut i = param.index as usize;
let segment = if i < fn_start {
+ if let GenericParamDefKind::Type(_) = param.kind {
+ // Handle Self first, so we can adjust the index to match the AST.
+ if has_self && i == 0 {
+ return opt_self_ty.map(|ty| Kind::from(ty)).unwrap_or_else(|| {
+ self.var_for_def(span, param)
+ });
+ }
+ }
i -= has_self as usize;
type_segment
} else {
i -= fn_start;
fn_segment
};
- let lifetimes = segment.map_or(&[][..], |(s, _)| {
- s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
- });
- if let Some(lifetime) = lifetimes.get(i) {
- AstConv::ast_region_to_region(self, lifetime, Some(def))
- } else {
- self.re_infer(span, Some(def)).unwrap()
- }
- }, |def, substs| {
- let mut i = def.index as usize;
-
- let segment = if i < fn_start {
- // Handle Self first, so we can adjust the index to match the AST.
- if has_self && i == 0 {
- return opt_self_ty.unwrap_or_else(|| {
- self.type_var_for_def(span, def)
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ let lifetimes = segment.map_or(&[][..], |(s, _)| {
+ s.parameters.as_ref().map_or(&[][..], |p| &p.lifetimes[..])
});
+
+ if let Some(lifetime) = lifetimes.get(i) {
+ AstConv::ast_region_to_region(self, lifetime, Some(param)).into()
+ } else {
+ self.re_infer(span, Some(param)).unwrap().into()
+ }
}
- i -= has_self as usize;
- type_segment
- } else {
- i -= fn_start;
- fn_segment
- };
- let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
- (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
- });
+ GenericParamDefKind::Type(_) => {
+ let (types, infer_types) = segment.map_or((&[][..], true), |(s, _)| {
+ (s.parameters.as_ref().map_or(&[][..], |p| &p.types[..]), s.infer_types)
+ });
- // Skip over the lifetimes in the same segment.
- if let Some((_, generics)) = segment {
- i -= generics.regions.len();
- }
+ // Skip over the lifetimes in the same segment.
+ if let Some((_, generics)) = segment {
+ i -= generics.own_counts().lifetimes;
+ }
- if let Some(ast_ty) = types.get(i) {
- // A provided type parameter.
- self.to_ty(ast_ty)
- } else if !infer_types && def.has_default {
- // No type parameter provided, but a default exists.
- let default = self.tcx.type_of(def.def_id);
- self.normalize_ty(
- span,
- default.subst_spanned(self.tcx, substs, Some(span))
- )
- } else {
- // No type parameters were provided, we can infer all.
- // This can also be reached in some error cases:
- // We prefer to use inference variables instead of
- // TyError to let type inference recover somewhat.
- self.type_var_for_def(span, def)
+ let has_default = match param.kind {
+ GenericParamDefKind::Type(ty) => ty.has_default,
+ _ => unreachable!()
+ };
+
+ if let Some(ast_ty) = types.get(i) {
+ // A provided type parameter.
+ self.to_ty(ast_ty).into()
+ } else if !infer_types && has_default {
+ // No type parameter provided, but a default exists.
+ let default = self.tcx.type_of(param.def_id);
+ self.normalize_ty(
+ span,
+ default.subst_spanned(self.tcx, substs, Some(span))
+ ).into()
+ } else {
+ // No type parameters were provided, we can infer all.
+ // This can also be reached in some error cases:
+ // We prefer to use inference variables instead of
+ // TyError to let type inference recover somewhat.
+ self.var_for_def(span, param)
+ }
+ }
}
});
format!("{} type parameter{}", n, if n == 1 { "" } else { "s" })
};
- // Check provided type parameters.
- let type_defs = segment.map_or(&[][..], |(_, generics)| {
- if generics.parent.is_none() {
- &generics.types[generics.has_self as usize..]
- } else {
- &generics.types
- }
- });
- let required_len = type_defs.iter().take_while(|d| !d.has_default).count();
- if types.len() > type_defs.len() {
- let span = types[type_defs.len()].span;
- let expected_text = count_type_params(type_defs.len());
+ // Check provided parameters.
+ let ((ty_required, ty_accepted), lt_accepted) =
+ segment.map_or(((0, 0), 0), |(_, generics)| {
+ struct ParamRange {
+ required: usize,
+ accepted: usize
+ };
+
+ let mut lt_accepted = 0;
+ let mut ty_params = ParamRange { required: 0, accepted: 0 };
+ for param in &generics.params {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ lt_accepted += 1;
+ }
+ GenericParamDefKind::Type(ty) => {
+ ty_params.accepted += 1;
+ if !ty.has_default {
+ ty_params.required += 1;
+ }
+ }
+ };
+ }
+ if generics.parent.is_none() && generics.has_self {
+ ty_params.required -= 1;
+ ty_params.accepted -= 1;
+ }
+
+ ((ty_params.required, ty_params.accepted), lt_accepted)
+ });
+
+ if types.len() > ty_accepted {
+ let span = types[ty_accepted].span;
+ let expected_text = count_type_params(ty_accepted);
let actual_text = count_type_params(types.len());
struct_span_err!(self.tcx.sess, span, E0087,
"too many type parameters provided: \
// type parameters, we force instantiate_value_path to
// use inference variables instead of the provided types.
*segment = None;
- } else if types.len() < required_len && !infer_types && !supress_mismatch_error {
- let expected_text = count_type_params(required_len);
+ } else if types.len() < ty_required && !infer_types && !supress_mismatch_error {
+ let expected_text = count_type_params(ty_required);
let actual_text = count_type_params(types.len());
struct_span_err!(self.tcx.sess, span, E0089,
"too few type parameters provided: \
AstConv::prohibit_projection(self, bindings[0].span);
}
- // Check provided lifetime parameters.
- let lifetime_defs = segment.map_or(&[][..], |(_, generics)| &generics.regions);
- let required_len = lifetime_defs.len();
-
// Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
let has_late_bound_lifetime_defs =
segment.map_or(None, |(_, generics)| generics.has_late_bound_regions);
let primary_msg = "cannot specify lifetime arguments explicitly \
if late bound lifetime parameters are present";
let note_msg = "the late bound lifetime parameter is introduced here";
- if !is_method_call && (lifetimes.len() > lifetime_defs.len() ||
- lifetimes.len() < required_len && !infer_lifetimes) {
+ if !is_method_call && (lifetimes.len() > lt_accepted ||
+ lifetimes.len() < lt_accepted && !infer_lifetimes) {
let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg);
err.span_note(span_late, note_msg);
err.emit();
return;
}
- if lifetimes.len() > lifetime_defs.len() {
- let span = lifetimes[lifetime_defs.len()].span;
- let expected_text = count_lifetime_params(lifetime_defs.len());
+ if lifetimes.len() > lt_accepted {
+ let span = lifetimes[lt_accepted].span;
+ let expected_text = count_lifetime_params(lt_accepted);
let actual_text = count_lifetime_params(lifetimes.len());
struct_span_err!(self.tcx.sess, span, E0088,
"too many lifetime parameters provided: \
expected_text, actual_text)
.span_label(span, format!("expected {}", expected_text))
.emit();
- } else if lifetimes.len() < required_len && !infer_lifetimes {
- let expected_text = count_lifetime_params(lifetime_defs.len());
+ } else if lifetimes.len() < lt_accepted && !infer_lifetimes {
+ let expected_text = count_lifetime_params(lt_accepted);
let actual_text = count_lifetime_params(lifetimes.len());
struct_span_err!(self.tcx.sess, span, E0090,
"too few lifetime parameters provided: \
span: Span,
segment: &mut Option<(&hir::PathSegment, &ty::Generics)>)
-> bool {
- use hir::SyntheticTyParamKind::*;
-
let segment = segment.map(|(path_segment, generics)| {
let explicit = !path_segment.infer_types;
- let impl_trait = generics.types.iter()
- .any(|ty_param| {
- match ty_param.synthetic {
- Some(ImplTrait) => true,
- _ => false,
- }
- });
+ let impl_trait = generics.params.iter().any(|param| {
+ if let ty::GenericParamDefKind::Type(ty) = param.kind {
+ if let Some(hir::SyntheticTyParamKind::ImplTrait) = ty.synthetic {
+ return true;
+ }
+ }
+ false
+ });
if explicit && impl_trait {
let mut err = struct_span_err! {
ty
} else {
if !self.is_tainted_by_errors() {
- self.need_type_info((**self).body_id, sp, ty);
+ self.need_type_info_err((**self).body_id, sp, ty)
+ .note("type must be known at this point")
+ .emit();
}
self.demand_suptype(sp, self.tcx.types.err, ty);
self.tcx.types.err
use hir::def_id::DefId;
use rustc::traits::{self, ObligationCauseCode};
-use rustc::ty::{self, Lift, Ty, TyCtxt};
+use rustc::ty::{self, Lift, Ty, TyCtxt, GenericParamDefKind};
+use rustc::ty::subst::Substs;
use rustc::ty::util::ExplicitSelf;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::middle::lang_items;
let param_env = self.param_env;
self.inherited.enter(|inh| {
let fcx = FnCtxt::new(&inh, param_env, id);
+ if !inh.tcx.features().trivial_bounds {
+ // As predicates are cached rather than obligations, this
+ // needsto be called first so that they are checked with an
+ // empty param_env.
+ check_false_global_bounds(&fcx, span, id);
+ }
let wf_tys = f(&fcx, fcx.tcx.global_tcx());
fcx.select_all_obligations_or_error();
fcx.regionck_item(id, span, &wf_tys);
fcx.register_wf_obligation(ty, span, code.clone());
}
ty::AssociatedKind::Method => {
- reject_shadowing_type_parameters(fcx.tcx, item.def_id);
+ reject_shadowing_parameters(fcx.tcx, item.def_id);
let sig = fcx.tcx.fn_sig(item.def_id);
let sig = fcx.normalize_associated_types_in(span, &sig);
check_fn_or_method(tcx, fcx, span, sig,
let mut substituted_predicates = Vec::new();
let generics = tcx.generics_of(def_id);
- let is_our_default = |def: &ty::TypeParameterDef|
- def.has_default && def.index >= generics.parent_count() as u32;
+ let is_our_default = |def: &ty::GenericParamDef| {
+ match def.kind {
+ GenericParamDefKind::Type(ty) => {
+ ty.has_default && def.index >= generics.parent_count as u32
+ }
+ _ => unreachable!()
+ }
+ };
// Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
// For example this forbids the declaration:
// struct Foo<T = Vec<[u32]>> { .. }
// Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
- for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
- let ty = fcx.tcx.type_of(d);
- // ignore dependent defaults -- that is, where the default of one type
- // parameter includes another (e.g., <T, U = T>). In those cases, we can't
- // be sure if it will error or not as user might always specify the other.
- if !ty.needs_subst() {
- fcx.register_wf_obligation(ty, fcx.tcx.def_span(d),
- ObligationCauseCode::MiscObligation);
+ for param in &generics.params {
+ if let GenericParamDefKind::Type(_) = param.kind {
+ if is_our_default(¶m) {
+ let ty = fcx.tcx.type_of(param.def_id);
+ // ignore dependent defaults -- that is, where the default of one type
+ // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+ // be sure if it will error or not as user might always specify the other.
+ if !ty.needs_subst() {
+ fcx.register_wf_obligation(ty, fcx.tcx.def_span(param.def_id),
+ ObligationCauseCode::MiscObligation);
+ }
+ }
}
}
// For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
//
// First we build the defaulted substitution.
- let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
- // All regions are identity.
- fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
- }, |def, _| {
- // If the param has a default,
- if is_our_default(def) {
- let default_ty = fcx.tcx.type_of(def.def_id);
- // and it's not a dependent default
- if !default_ty.needs_subst() {
- // then substitute with the default.
- return default_ty;
+ let substs = Substs::for_item(fcx.tcx, def_id, |param, _| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => {
+ // All regions are identity.
+ fcx.tcx.mk_param_from_def(param)
+ }
+ GenericParamDefKind::Type(_) => {
+ // If the param has a default,
+ if is_our_default(param) {
+ let default_ty = fcx.tcx.type_of(param.def_id);
+ // and it's not a dependent default
+ if !default_ty.needs_subst() {
+ // then substitute with the default.
+ return default_ty.into();
+ }
}
+ // Mark unwanted params as err.
+ fcx.tcx.types.err.into()
}
- // Mark unwanted params as err.
- fcx.tcx.types.err
- });
+ }
+ });
// Now we build the substituted predicates.
for &pred in predicates.predicates.iter() {
struct CountParams { params: FxHashSet<u32> }
err.emit();
}
-fn reject_shadowing_type_parameters(tcx: TyCtxt, def_id: DefId) {
+fn reject_shadowing_parameters(tcx: TyCtxt, def_id: DefId) {
let generics = tcx.generics_of(def_id);
let parent = tcx.generics_of(generics.parent.unwrap());
- let impl_params: FxHashMap<_, _> = parent.types
- .iter()
- .map(|tp| (tp.name, tp.def_id))
- .collect();
-
- for method_param in &generics.types {
+ let impl_params: FxHashMap<_, _> =
+ parent.params.iter()
+ .flat_map(|param| {
+ match param.kind {
+ GenericParamDefKind::Lifetime => None,
+ GenericParamDefKind::Type(_) => Some((param.name, param.def_id)),
+ }
+ })
+ .collect();
+
+ for method_param in generics.params.iter() {
+ match method_param.kind {
+ // Shadowing is checked in resolve_lifetime.
+ GenericParamDefKind::Lifetime => continue,
+ _ => {},
+ };
if impl_params.contains_key(&method_param.name) {
// Tighten up the span to focus on only the shadowing type
let type_span = tcx.def_span(method_param.def_id);
}
}
+/// Feature gates RFC 2056 - trivial bounds, checking for global bounds that
+/// aren't true.
+fn check_false_global_bounds<'a, 'gcx, 'tcx>(
+ fcx: &FnCtxt<'a, 'gcx, 'tcx>,
+ span: Span,
+ id: ast::NodeId,
+) {
+ use rustc::ty::TypeFoldable;
+
+ let empty_env = ty::ParamEnv::empty();
+
+ let def_id = fcx.tcx.hir.local_def_id(id);
+ let predicates = fcx.tcx.predicates_of(def_id).predicates;
+ // Check elaborated bounds
+ let implied_obligations = traits::elaborate_predicates(fcx.tcx, predicates);
+
+ for pred in implied_obligations {
+ // Match the existing behavior.
+ if pred.is_global() && !pred.has_late_bound_regions() {
+ let obligation = traits::Obligation::new(
+ traits::ObligationCause::new(
+ span,
+ id,
+ traits::TrivialBound,
+ ),
+ empty_env,
+ pred,
+ );
+ fcx.register_predicate(obligation);
+ }
+ }
+
+ fcx.select_all_obligations_or_error();
+}
+
pub struct CheckTypeWellFormedVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
fn report_error(&self, t: Ty<'tcx>) {
if !self.tcx.sess.has_errors() {
self.infcx
- .need_type_info(Some(self.body.id()), self.span.to_span(&self.tcx), t);
+ .need_type_info_err(Some(self.body.id()), self.span.to_span(&self.tcx), t).emit();
}
}
}
self.tcx.at(span).type_param_predicates((self.item_def_id, def_id))
}
- fn re_infer(&self, _span: Span, _def: Option<&ty::RegionParameterDef>)
+ fn re_infer(&self, _span: Span, _def: Option<&ty::GenericParamDef>)
-> Option<ty::Region<'tcx>> {
None
}
let param_owner = tcx.hir.ty_param_owner(param_id);
let param_owner_def_id = tcx.hir.local_def_id(param_owner);
let generics = tcx.generics_of(param_owner_def_id);
- let index = generics.type_param_to_index[&def_id];
- let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id).as_interned_str());
+ let index = generics.param_def_id_to_index[&def_id];
+ let ty = tcx.mk_ty_param(index, tcx.hir.ty_param_name(param_id).as_interned_str());
// Don't look for bounds where the type parameter isn't in scope.
let parent = if item_def_id == param_owner_def_id {
// the node id for the Self type parameter.
let param_id = item.id;
- opt_self = Some(ty::TypeParameterDef {
+ opt_self = Some(ty::GenericParamDef {
index: 0,
name: keywords::SelfType.name().as_interned_str(),
def_id: tcx.hir.local_def_id(param_id),
- has_default: false,
- object_lifetime_default: rl::Set1::Empty,
pure_wrt_drop: false,
- synthetic: None,
+ kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ synthetic: None,
+ }),
});
allow_defaults = true;
let has_self = opt_self.is_some();
let mut parent_has_self = false;
let mut own_start = has_self as u32;
- let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
+ let parent_count = parent_def_id.map_or(0, |def_id| {
let generics = tcx.generics_of(def_id);
assert_eq!(has_self, false);
parent_has_self = generics.has_self;
own_start = generics.count() as u32;
- (generics.parent_regions + generics.regions.len() as u32,
- generics.parent_types + generics.types.len() as u32)
+ generics.parent_count + generics.params.len()
});
+ let mut params: Vec<_> = opt_self.into_iter().collect();
+
let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
- let regions = early_lifetimes.enumerate().map(|(i, l)| {
- ty::RegionParameterDef {
+ params.extend(early_lifetimes.enumerate().map(|(i, l)| {
+ ty::GenericParamDef {
name: l.lifetime.name.name().as_interned_str(),
index: own_start + i as u32,
def_id: tcx.hir.local_def_id(l.lifetime.id),
pure_wrt_drop: l.pure_wrt_drop,
+ kind: ty::GenericParamDefKind::Lifetime,
}
- }).collect::<Vec<_>>();
+ }));
let hir_id = tcx.hir.node_to_hir_id(node_id);
let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id);
// Now create the real type parameters.
- let type_start = own_start + regions.len() as u32;
- let types = ast_generics.ty_params().enumerate().map(|(i, p)| {
+ let type_start = own_start - has_self as u32 + params.len() as u32;
+ params.extend(ast_generics.ty_params().enumerate().map(|(i, p)| {
if p.name == keywords::SelfType.name() {
span_bug!(p.span, "`Self` should not be the name of a regular parameter");
}
}
}
- ty::TypeParameterDef {
+ ty::GenericParamDef {
index: type_start + i as u32,
name: p.name.as_interned_str(),
def_id: tcx.hir.local_def_id(p.id),
- has_default: p.default.is_some(),
- object_lifetime_default:
- object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]),
pure_wrt_drop: p.pure_wrt_drop,
- synthetic: p.synthetic,
+ kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+ has_default: p.default.is_some(),
+ object_lifetime_default:
+ object_lifetime_defaults.as_ref().map_or(rl::Set1::Empty, |o| o[i]),
+ synthetic: p.synthetic,
+ }),
}
- });
-
- let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
+ }));
// provide junk type parameter defs - the only place that
// cares about anything but the length is instantiation,
};
for (i, &arg) in dummy_args.iter().enumerate() {
- types.push(ty::TypeParameterDef {
+ params.push(ty::GenericParamDef {
index: type_start + i as u32,
name: Symbol::intern(arg).as_interned_str(),
def_id,
- has_default: false,
- object_lifetime_default: rl::Set1::Empty,
pure_wrt_drop: false,
- synthetic: None,
+ kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ synthetic: None,
+ }),
});
}
tcx.with_freevars(node_id, |fv| {
- types.extend(fv.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| {
- ty::TypeParameterDef {
+ params.extend(fv.iter().zip((dummy_args.len() as u32)..).map(|(_, i)| {
+ ty::GenericParamDef {
index: type_start + i,
name: Symbol::intern("<upvar>").as_interned_str(),
def_id,
- has_default: false,
- object_lifetime_default: rl::Set1::Empty,
pure_wrt_drop: false,
- synthetic: None,
+ kind: ty::GenericParamDefKind::Type(ty::TypeParamDef {
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ synthetic: None,
+ }),
}
}));
});
}
- let type_param_to_index = types.iter()
- .map(|param| (param.def_id, param.index))
- .collect();
+ let param_def_id_to_index = params.iter()
+ .map(|param| (param.def_id, param.index))
+ .collect();
tcx.alloc_generics(ty::Generics {
parent: parent_def_id,
- parent_regions,
- parent_types,
- regions,
- types,
- type_param_to_index,
+ parent_count,
+ params,
+ param_def_id_to_index,
has_self: has_self || parent_has_self,
has_late_bound_regions: has_late_bound_regions(tcx, node),
})
}
let substs = ty::ClosureSubsts {
- substs: Substs::for_item(
- tcx,
- def_id,
- |def, _| {
- let region = def.to_early_bound_region_data();
- tcx.mk_region(ty::ReEarlyBound(region))
- },
- |def, _| tcx.mk_param_from_def(def)
- )
+ substs: Substs::identity_for_item(tcx, def_id),
};
tcx.mk_closure(def_id, substs)
};
let generics = tcx.generics_of(def_id);
- let parent_count = generics.parent_count() as u32;
+ let parent_count = generics.parent_count as u32;
let has_own_self = generics.has_self && parent_count == 0;
let mut predicates = vec![];
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
- hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => {
+ hir::ItemImpl(.., ref impl_item_refs) => {
let impl_def_id = self.tcx.hir.local_def_id(item.id);
enforce_impl_params_are_constrained(self.tcx,
- generics,
impl_def_id,
impl_item_refs);
enforce_impl_items_are_distinct(self.tcx, impl_item_refs);
}
fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- impl_hir_generics: &hir::Generics,
impl_def_id: DefId,
impl_item_refs: &[hir::ImplItemRef])
{
ctp::identify_constrained_type_params(
tcx, &impl_predicates.predicates.as_slice(), impl_trait_ref, &mut input_parameters);
- // Disallow ANY unconstrained type parameters.
- for (ty_param, param) in impl_generics.types.iter().zip(impl_hir_generics.ty_params()) {
- let param_ty = ty::ParamTy::for_def(ty_param);
- if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
- report_unused_parameter(tcx, param.span, "type", ¶m_ty.to_string());
- }
- }
-
// Disallow unconstrained lifetimes, but only if they appear in assoc types.
let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
- .map(|item_ref| tcx.hir.local_def_id(item_ref.id.node_id))
+ .map(|item_ref| tcx.hir.local_def_id(item_ref.id.node_id))
.filter(|&def_id| {
let item = tcx.associated_item(def_id);
item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
.flat_map(|def_id| {
ctp::parameters_for(&tcx.type_of(def_id), true)
}).collect();
- for (ty_lifetime, lifetime) in impl_generics.regions.iter()
- .zip(impl_hir_generics.lifetimes())
- {
- let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data());
- if
- lifetimes_in_associated_types.contains(¶m) && // (*)
- !input_parameters.contains(¶m)
- {
- report_unused_parameter(tcx, lifetime.lifetime.span,
- "lifetime", &lifetime.lifetime.name.name().to_string());
+ for param in &impl_generics.params {
+ match param.kind {
+ // Disallow ANY unconstrained type parameters.
+ ty::GenericParamDefKind::Type(_) => {
+ let param_ty = ty::ParamTy::for_def(param);
+ if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
+ report_unused_parameter(tcx,
+ tcx.def_span(param.def_id),
+ "type",
+ ¶m_ty.to_string());
+ }
+ }
+ ty::GenericParamDefKind::Lifetime => {
+ let param_lt = ctp::Parameter::from(param.to_early_bound_region_data());
+ if lifetimes_in_associated_types.contains(¶m_lt) && // (*)
+ !input_parameters.contains(¶m_lt) {
+ report_unused_parameter(tcx,
+ tcx.def_span(param.def_id),
+ "lifetime",
+ ¶m.name.to_string());
+ }
+ }
}
}
// Vec<U>`. Decomposing `Vec<U>` into
// components would yield `U`, and we add the
// where clause that `U: 'a`.
- let ty: Ty<'tcx> = tcx.mk_param(param_ty.idx, param_ty.name);
+ let ty: Ty<'tcx> = tcx.mk_ty_param(param_ty.idx, param_ty.name);
required_predicates
.insert(ty::OutlivesPredicate(ty.into(), outlived_region));
}
[dependencies]
pulldown-cmark = { version = "0.1.2", default-features = false }
tempdir = "0.3"
+minifier = "0.0.11"
}
fn generics_to_path_params(&self, generics: ty::Generics) -> hir::PathParameters {
- let lifetimes = HirVec::from_vec(
- generics
- .regions
- .iter()
- .map(|p| {
- let name = if p.name == "" {
+ let mut lifetimes = vec![];
+ let mut types = vec![];
+
+ for param in generics.params.iter() {
+ match param.kind {
+ ty::GenericParamDefKind::Lifetime => {
+ let name = if param.name == "" {
hir::LifetimeName::Static
} else {
- hir::LifetimeName::Name(p.name.as_symbol())
+ hir::LifetimeName::Name(param.name.as_symbol())
};
- hir::Lifetime {
+ lifetimes.push(hir::Lifetime {
id: ast::DUMMY_NODE_ID,
span: DUMMY_SP,
name,
- }
- })
- .collect(),
- );
- let types = HirVec::from_vec(
- generics
- .types
- .iter()
- .map(|p| P(self.ty_param_to_ty(p.clone())))
- .collect(),
- );
+ });
+ }
+ ty::GenericParamDefKind::Type(_) => {
+ types.push(P(self.ty_param_to_ty(param.clone())));
+ }
+ }
+ }
hir::PathParameters {
- lifetimes: lifetimes,
- types: types,
+ lifetimes: HirVec::from_vec(lifetimes),
+ types: HirVec::from_vec(types),
bindings: HirVec::new(),
parenthesized: false,
}
}
- fn ty_param_to_ty(&self, param: ty::TypeParameterDef) -> hir::Ty {
+ fn ty_param_to_ty(&self, param: ty::GenericParamDef) -> hir::Ty {
debug!("ty_param_to_ty({:?}) {:?}", param, param.def_id);
hir::Ty {
id: ast::DUMMY_NODE_ID,
&self,
tcx: TyCtxt<'b, 'c, 'd>,
pred: ty::Predicate<'d>,
- ) -> FxHashSet<GenericParam> {
+ ) -> FxHashSet<GenericParamDef> {
pred.walk_tys()
.flat_map(|t| {
let mut regions = FxHashSet();
// We only care about late bound regions, as we need to add them
// to the 'for<>' section
&ty::ReLateBound(_, ty::BoundRegion::BrNamed(_, name)) => {
- Some(GenericParam::Lifetime(Lifetime(name.to_string())))
+ Some(GenericParamDef::Lifetime(Lifetime(name.to_string())))
}
&ty::ReVar(_) | &ty::ReEarlyBound(_) => None,
_ => panic!("Unexpected region type {:?}", r),
for p in generic_params.iter_mut() {
match p {
- &mut GenericParam::Type(ref mut ty) => {
+ &mut GenericParamDef::Type(ref mut ty) => {
// We never want something like 'impl<T=Foo>'
ty.default.take();
ty.bounds.insert(0, TyParamBound::maybe_sized(self.cx));
}
}
- _ => {}
+ GenericParamDef::Lifetime(_) => {}
}
}
pub use self::TyParamBound::*;
pub use self::SelfTy::*;
pub use self::FunctionRetTy::*;
-pub use self::Visibility::*;
+pub use self::Visibility::{Public, Inherited};
use syntax;
use rustc_target::spec::abi::Abi;
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::hir::def_id::DefIndexAddressSpace;
use rustc::ty::subst::Substs;
-use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind};
+use rustc::ty::{self, TyCtxt, Region, RegionVid, Ty, AdtKind, GenericParamCount};
use rustc::middle::stability;
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_typeck::hir_ty_to_ty;
}
}
-impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
+impl<'tcx> Clean<TyParam> for ty::GenericParamDef {
fn clean(&self, cx: &DocContext) -> TyParam {
cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
+ let has_default = match self.kind {
+ ty::GenericParamDefKind::Type(ty) => ty.has_default,
+ _ => panic!("tried to convert a non-type GenericParamDef as a type")
+ };
TyParam {
name: self.name.clean(cx),
did: self.def_id,
bounds: vec![], // these are filled in from the where-clauses
- default: if self.has_default {
+ default: if has_default {
Some(cx.tcx.type_of(self.def_id).clean(cx))
} else {
None
if let &ty::RegionKind::ReLateBound(..) = *reg {
debug!(" hit an ReLateBound {:?}", reg);
if let Some(lt) = reg.clean(cx) {
- late_bounds.push(GenericParam::Lifetime(lt));
+ late_bounds.push(GenericParamDef::Lifetime(lt));
}
}
}
}
}
-impl Clean<Lifetime> for ty::RegionParameterDef {
- fn clean(&self, _: &DocContext) -> Lifetime {
+impl<'tcx> Clean<Lifetime> for ty::GenericParamDef {
+ fn clean(&self, _cx: &DocContext) -> Lifetime {
Lifetime(self.name.to_string())
}
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
-pub enum GenericParam {
+pub enum GenericParamDef {
Lifetime(Lifetime),
Type(TyParam),
}
-impl GenericParam {
+impl GenericParamDef {
pub fn is_synthetic_type_param(&self) -> bool {
- if let GenericParam::Type(ref t) = *self {
- t.synthetic.is_some()
- } else {
- false
+ match self {
+ GenericParamDef::Type(ty) => ty.synthetic.is_some(),
+ GenericParamDef::Lifetime(_) => false,
}
}
}
-impl Clean<GenericParam> for hir::GenericParam {
- fn clean(&self, cx: &DocContext) -> GenericParam {
+impl Clean<GenericParamDef> for hir::GenericParam {
+ fn clean(&self, cx: &DocContext) -> GenericParamDef {
match *self {
- hir::GenericParam::Lifetime(ref l) => GenericParam::Lifetime(l.clean(cx)),
- hir::GenericParam::Type(ref t) => GenericParam::Type(t.clean(cx)),
+ hir::GenericParam::Lifetime(ref l) => GenericParamDef::Lifetime(l.clean(cx)),
+ hir::GenericParam::Type(ref t) => GenericParamDef::Type(t.clean(cx)),
}
}
}
// maybe use a Generic enum and use Vec<Generic>?
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Default, Hash)]
pub struct Generics {
- pub params: Vec<GenericParam>,
+ pub params: Vec<GenericParamDef>,
pub where_predicates: Vec<WherePredicate>,
}
let mut params = Vec::with_capacity(self.params.len());
for p in &self.params {
let p = p.clean(cx);
- if let GenericParam::Type(ref tp) = p {
+ if let GenericParamDef::Type(ref tp) = p {
if tp.synthetic == Some(hir::SyntheticTyParamKind::ImplTrait) {
cx.impl_trait_bounds.borrow_mut().insert(tp.did, tp.bounds.clone());
}
WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds } => {
if bounds.is_empty() {
for param in &mut g.params {
- if let GenericParam::Type(ref mut type_param) = *param {
+ if let GenericParamDef::Type(ref mut type_param) = *param {
if &type_param.name == name {
mem::swap(bounds, &mut type_param.bounds);
break
// Bounds in the type_params and lifetimes fields are repeated in the
// predicates field (see rustc_typeck::collect::ty_generics), so remove
// them.
- let stripped_typarams = gens.types.iter().filter_map(|tp| {
- if tp.name == keywords::SelfType.name().as_str() {
- assert_eq!(tp.index, 0);
- None
+ let stripped_typarams = gens.params.iter().filter_map(|param| {
+ if let ty::GenericParamDefKind::Type(_) = param.kind {
+ if param.name == keywords::SelfType.name().as_str() {
+ assert_eq!(param.index, 0);
+ None
+ } else {
+ Some(param.clean(cx))
+ }
} else {
- Some(tp.clean(cx))
+ None
}
- }).collect::<Vec<_>>();
+ }).collect::<Vec<TyParam>>();
let mut where_predicates = preds.predicates.to_vec().clean(cx);
// and instead see `where T: Foo + Bar + Sized + 'a`
Generics {
- params: gens.regions
- .clean(cx)
- .into_iter()
- .map(|lp| GenericParam::Lifetime(lp))
- .chain(
- simplify::ty_params(stripped_typarams)
- .into_iter()
- .map(|tp| GenericParam::Type(tp))
- )
- .collect(),
+ params: gens.params
+ .iter()
+ .flat_map(|param| {
+ if let ty::GenericParamDefKind::Lifetime = param.kind {
+ Some(GenericParamDef::Lifetime(param.clean(cx)))
+ } else {
+ None
+ }
+ }).chain(
+ simplify::ty_params(stripped_typarams)
+ .into_iter()
+ .map(|tp| GenericParamDef::Type(tp))
+ )
+ .collect(),
where_predicates: simplify::where_clauses(cx, where_predicates),
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
pub struct PolyTrait {
pub trait_: Type,
- pub generic_params: Vec<GenericParam>,
+ pub generic_params: Vec<GenericParamDef>,
}
/// A representation of a Type suitable for hyperlinking purposes. Ideally one can get the original
let mut ty_substs = FxHashMap();
let mut lt_substs = FxHashMap();
provided_params.with_parameters(|provided_params| {
- for (i, ty_param) in generics.ty_params().enumerate() {
- let ty_param_def = Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
- if let Some(ty) = provided_params.types.get(i).cloned() {
- ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
- } else if let Some(default) = ty_param.default.clone() {
- ty_substs.insert(ty_param_def, default.into_inner().clean(cx));
- }
- }
-
- for (i, lt_param) in generics.lifetimes().enumerate() {
- if let Some(lt) = provided_params.lifetimes.get(i).cloned() {
- if !lt.is_elided() {
- let lt_def_id = cx.tcx.hir.local_def_id(lt_param.lifetime.id);
- lt_substs.insert(lt_def_id, lt.clean(cx));
+ let mut indices = GenericParamCount {
+ lifetimes: 0,
+ types: 0
+ };
+ for param in generics.params.iter() {
+ match param {
+ hir::GenericParam::Lifetime(lt_param) => {
+ if let Some(lt) = provided_params.lifetimes
+ .get(indices.lifetimes).cloned() {
+ if !lt.is_elided() {
+ let lt_def_id =
+ cx.tcx.hir.local_def_id(lt_param.lifetime.id);
+ lt_substs.insert(lt_def_id, lt.clean(cx));
+ }
+ }
+ indices.lifetimes += 1;
+ }
+ hir::GenericParam::Type(ty_param) => {
+ let ty_param_def =
+ Def::TyParam(cx.tcx.hir.local_def_id(ty_param.id));
+ if let Some(ty) = provided_params.types
+ .get(indices.types).cloned() {
+ ty_substs.insert(ty_param_def, ty.into_inner().clean(cx));
+ } else if let Some(default) = ty_param.default.clone() {
+ ty_substs.insert(ty_param_def,
+ default.into_inner().clean(cx));
+ }
+ indices.types += 1;
}
}
}
pub enum Visibility {
Public,
Inherited,
+ Crate,
+ Restricted(DefId, Path),
}
impl Clean<Option<Visibility>> for hir::Visibility {
- fn clean(&self, _: &DocContext) -> Option<Visibility> {
- Some(if *self == hir::Visibility::Public { Public } else { Inherited })
+ fn clean(&self, cx: &DocContext) -> Option<Visibility> {
+ Some(match *self {
+ hir::Visibility::Public => Visibility::Public,
+ hir::Visibility::Inherited => Visibility::Inherited,
+ hir::Visibility::Crate => Visibility::Crate,
+ hir::Visibility::Restricted { ref path, .. } => {
+ let path = path.clean(cx);
+ let did = register_def(cx, path.def);
+ Visibility::Restricted(did, path)
+ }
+ })
}
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Debug, Hash)]
pub struct BareFunctionDecl {
pub unsafety: hir::Unsafety,
- pub generic_params: Vec<GenericParam>,
+ pub generic_params: Vec<GenericParamDef>,
pub decl: FnDecl,
pub abi: Abi,
}
#[derive(Eq, PartialEq, Hash, Debug)]
enum SimpleBound {
RegionBound(Lifetime),
- TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParam>, hir::TraitBoundModifier)
+ TraitBound(Vec<PathSegment>, Vec<SimpleBound>, Vec<GenericParamDef>, hir::TraitBoundModifier)
}
enum AutoTraitResult {
}
}
+/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
+///
+/// If the given `error_format` is `ErrorOutputType::Json` and no `CodeMap` is given, a new one
+/// will be created for the handler.
+pub fn new_handler(error_format: ErrorOutputType, codemap: Option<Lrc<codemap::CodeMap>>)
+ -> errors::Handler
+{
+ // rustdoc doesn't override (or allow to override) anything from this that is relevant here, so
+ // stick to the defaults
+ let sessopts = config::basic_options();
+ let emitter: Box<dyn Emitter + sync::Send> = match error_format {
+ ErrorOutputType::HumanReadable(color_config) => Box::new(
+ EmitterWriter::stderr(
+ color_config,
+ codemap.map(|cm| cm as _),
+ false,
+ sessopts.debugging_opts.teach,
+ ).ui_testing(sessopts.debugging_opts.ui_testing)
+ ),
+ ErrorOutputType::Json(pretty) => {
+ let codemap = codemap.unwrap_or_else(
+ || Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping())));
+ Box::new(
+ JsonEmitter::stderr(
+ None,
+ codemap,
+ pretty,
+ sessopts.debugging_opts.suggestion_applicability,
+ ).ui_testing(sessopts.debugging_opts.ui_testing)
+ )
+ },
+ ErrorOutputType::Short(color_config) => Box::new(
+ EmitterWriter::stderr(
+ color_config,
+ codemap.map(|cm| cm as _),
+ true,
+ false)
+ ),
+ };
+
+ errors::Handler::with_emitter_and_flags(
+ emitter,
+ errors::HandlerFlags {
+ can_emit_warnings: true,
+ treat_err_as_bug: false,
+ external_macro_backtrace: false,
+ ..Default::default()
+ },
+ )
+}
+
pub fn run_core(search_paths: SearchPaths,
cfgs: Vec<String>,
externs: config::Externs,
},
error_format,
edition,
- ..config::basic_options().clone()
+ ..config::basic_options()
};
driver::spawn_thread_pool(sessopts, move |sessopts| {
let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
- let emitter: Box<dyn Emitter + sync::Send> = match error_format {
- ErrorOutputType::HumanReadable(color_config) => Box::new(
- EmitterWriter::stderr(
- color_config,
- Some(codemap.clone()),
- false,
- sessopts.debugging_opts.teach,
- ).ui_testing(sessopts.debugging_opts.ui_testing)
- ),
- ErrorOutputType::Json(pretty) => Box::new(
- JsonEmitter::stderr(
- None,
- codemap.clone(),
- pretty,
- sessopts.debugging_opts.suggestion_applicability,
- ).ui_testing(sessopts.debugging_opts.ui_testing)
- ),
- ErrorOutputType::Short(color_config) => Box::new(
- EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
- ),
- };
-
- let diagnostic_handler = errors::Handler::with_emitter_and_flags(
- emitter,
- errors::HandlerFlags {
- can_emit_warnings: true,
- treat_err_as_bug: false,
- external_macro_backtrace: false,
- ..Default::default()
- },
- );
+ let diagnostic_handler = new_handler(error_format, Some(codemap.clone()));
let mut sess = session::build_session_(
sessopts, cpath, diagnostic_handler, codemap,
use std::fs;
use std::path::Path;
use std::str;
+use errors;
use html::markdown::Markdown;
#[derive(Clone)]
impl ExternalHtml {
pub fn load(in_header: &[String], before_content: &[String], after_content: &[String],
- md_before_content: &[String], md_after_content: &[String])
+ md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler)
-> Option<ExternalHtml> {
- load_external_files(in_header)
+ load_external_files(in_header, diag)
.and_then(|ih|
- load_external_files(before_content)
+ load_external_files(before_content, diag)
.map(|bc| (ih, bc))
)
.and_then(|(ih, bc)|
- load_external_files(md_before_content)
+ load_external_files(md_before_content, diag)
.map(|m_bc| (ih, format!("{}{}", bc, Markdown(&m_bc, &[]))))
)
.and_then(|(ih, bc)|
- load_external_files(after_content)
+ load_external_files(after_content, diag)
.map(|ac| (ih, bc, ac))
)
.and_then(|(ih, bc, ac)|
- load_external_files(md_after_content)
+ load_external_files(md_after_content, diag)
.map(|m_ac| (ih, bc, format!("{}{}", ac, Markdown(&m_ac, &[]))))
)
.map(|(ih, bc, ac)|
BadUtf8,
}
-pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
+pub fn load_string<P: AsRef<Path>>(file_path: P, diag: &errors::Handler)
+ -> Result<String, LoadStringError>
+{
let file_path = file_path.as_ref();
let contents = match fs::read(file_path) {
Ok(bytes) => bytes,
Err(e) => {
- eprintln!("error reading `{}`: {}", file_path.display(), e);
+ diag.struct_err(&format!("error reading `{}`: {}", file_path.display(), e)).emit();
return Err(LoadStringError::ReadFail);
}
};
match str::from_utf8(&contents) {
Ok(s) => Ok(s.to_string()),
Err(_) => {
- eprintln!("error reading `{}`: not UTF-8", file_path.display());
+ diag.struct_err(&format!("error reading `{}`: not UTF-8", file_path.display())).emit();
Err(LoadStringError::BadUtf8)
}
}
}
-fn load_external_files(names: &[String]) -> Option<String> {
+fn load_external_files(names: &[String], diag: &errors::Handler) -> Option<String> {
let mut out = String::new();
for name in names {
- let s = match load_string(name) {
+ let s = match load_string(name, diag) {
Ok(s) => s,
Err(_) => return None,
};
}
}
-impl fmt::Display for clean::GenericParam {
+impl fmt::Display for clean::GenericParamDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
- clean::GenericParam::Lifetime(ref lp) => write!(f, "{}", lp),
- clean::GenericParam::Type(ref tp) => {
+ clean::GenericParamDef::Lifetime(ref lp) => write!(f, "{}", lp),
+ clean::GenericParamDef::Type(ref tp) => {
f.write_str(&tp.name)?;
if !tp.bounds.is_empty() {
impl<'a> fmt::Display for VisSpace<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.get() {
- Some(clean::Public) => write!(f, "pub "),
- Some(clean::Inherited) | None => Ok(())
+ Some(clean::Public) => f.write_str("pub "),
+ Some(clean::Inherited) | None => Ok(()),
+ Some(clean::Visibility::Crate) => write!(f, "pub(crate) "),
+ Some(clean::Visibility::Restricted(did, ref path)) => {
+ f.write_str("pub(")?;
+ if path.segments.len() != 1
+ || (path.segments[0].name != "self" && path.segments[0].name != "super")
+ {
+ f.write_str("in ")?;
+ }
+ resolved_path(f, did, path, true, false)?;
+ f.write_str(") ")
+ }
}
}
}
token::Lifetime(..) => Class::Lifetime,
token::Eof | token::Interpolated(..) |
- token::Tilde | token::At | token::DotEq => Class::None,
+ token::Tilde | token::At | token::DotEq | token::SingleQuote => Class::None,
};
// Anything that didn't return above is the simple case where we the
use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
use html::{highlight, layout};
+use minifier;
+
/// A pair of name and its optional document.
pub type NameDoc = (String, Option<String>);
match self.name {
Some(ref name) => {
let mut data = BTreeMap::new();
- data.insert("name".to_owned(), name.to_json());
+ data.insert("n".to_owned(), name.to_json());
if let Some(ref generics) = self.generics {
- data.insert("generics".to_owned(), generics.to_json());
+ data.insert("g".to_owned(), generics.to_json());
}
Json::Object(data)
},
Json::Null
} else {
let mut data = BTreeMap::new();
- data.insert("inputs".to_owned(), self.inputs.to_json());
- data.insert("output".to_owned(), self.output.to_json());
+ if !self.inputs.is_empty() {
+ data.insert("i".to_owned(), self.inputs.to_json());
+ }
+ if let Some(ref output) = self.output {
+ data.insert("o".to_owned(), output.to_json());
+ }
Json::Object(data)
}
}
css_file_extension: Option<PathBuf>,
renderinfo: RenderInfo,
sort_modules_alphabetically: bool,
- themes: Vec<PathBuf>) -> Result<(), Error> {
+ themes: Vec<PathBuf>,
+ enable_minification: bool) -> Result<(), Error> {
let src_root = match krate.src {
FileName::Real(ref p) => match p.parent() {
Some(p) => p.to_path_buf(),
CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
- write_shared(&cx, &krate, &*cache, index)?;
+ write_shared(&cx, &krate, &*cache, index, enable_minification)?;
// And finally render the whole crate's documentation
cx.krate(krate)
fn write_shared(cx: &Context,
krate: &clean::Crate,
cache: &Cache,
- search_index: String) -> Result<(), Error> {
+ search_index: String,
+ enable_minification: bool) -> Result<(), Error> {
// Write out the shared files. Note that these are shared among all rustdoc
// docs placed in the output directory, so this needs to be a synchronized
// operation with respect to all other rustdocs running around.
format!(
r#"var themes = document.getElementById("theme-choices");
var themePicker = document.getElementById("theme-picker");
-themePicker.onclick = function() {{
+
+function switchThemeButtonState() {{
if (themes.style.display === "block") {{
themes.style.display = "none";
themePicker.style.borderBottomRightRadius = "3px";
themePicker.style.borderBottomLeftRadius = "0";
}}
}};
+
+function handleThemeButtonsBlur(e) {{
+ var active = document.activeElement;
+ var related = e.relatedTarget;
+
+ if (active.id !== "themePicker" &&
+ (!active.parentNode || active.parentNode.id !== "theme-choices") &&
+ (!related ||
+ (related.id !== "themePicker" &&
+ (!related.parentNode || related.parentNode.id !== "theme-choices")))) {{
+ switchThemeButtonState();
+ }}
+}}
+
+themePicker.onclick = switchThemeButtonState;
+themePicker.onblur = handleThemeButtonsBlur;
[{}].forEach(function(item) {{
var but = document.createElement('button');
but.innerHTML = item;
but.onclick = function(el) {{
switchTheme(currentTheme, mainTheme, item);
}};
+ but.onblur = handleThemeButtonsBlur;
themes.appendChild(but);
}});"#,
themes.iter()
.join(",")).as_bytes(),
)?;
- write(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
- include_bytes!("static/main.js"))?;
- write(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
- include_bytes!("static/settings.js"))?;
+ write_minify(cx.dst.join(&format!("main{}.js", cx.shared.resource_suffix)),
+ include_str!("static/main.js"),
+ enable_minification)?;
+ write_minify(cx.dst.join(&format!("settings{}.js", cx.shared.resource_suffix)),
+ include_str!("static/settings.js"),
+ enable_minification)?;
{
let mut data = format!("var resourcesSuffix = \"{}\";\n",
- cx.shared.resource_suffix).into_bytes();
- data.extend_from_slice(include_bytes!("static/storage.js"));
- write(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)), &data)?;
+ cx.shared.resource_suffix);
+ data.push_str(include_str!("static/storage.js"));
+ write_minify(cx.dst.join(&format!("storage{}.js", cx.shared.resource_suffix)),
+ &data,
+ enable_minification)?;
}
if let Some(ref css) = cx.shared.css_file_extension {
}
fn show_item(item: &IndexItem, krate: &str) -> String {
- format!("{{'crate':'{}','ty':{},'name':'{}','path':'{}'{}}}",
- krate, item.ty as usize, item.name, item.path,
+ format!("{{'crate':'{}','ty':{},'name':'{}','desc':'{}','p':'{}'{}}}",
+ krate, item.ty as usize, item.name, item.desc.replace("'", "\\'"), item.path,
if let Some(p) = item.parent_idx {
format!(",'parent':{}", p)
} else {
Ok(try_err!(fs::write(&dst, contents), &dst))
}
+fn write_minify(dst: PathBuf, contents: &str, enable_minification: bool) -> Result<(), Error> {
+ if enable_minification {
+ write(dst, minifier::js::minify(contents).as_bytes())
+ } else {
+ write(dst, contents.as_bytes())
+ }
+}
+
/// Takes a path to a source file and cleans the path to it. This canonicalizes
/// things like ".." to components which preserve the "top down" hierarchy of a
/// static HTML tree. Each component in the cleaned path will be passed as an
impl<'a> Cache {
fn generics(&mut self, generics: &clean::Generics) {
for param in &generics.params {
- if let clean::GenericParam::Type(ref typ) = *param {
- self.typarams.insert(typ.did, typ.name.clone());
+ match *param {
+ clean::GenericParamDef::Type(ref typ) => {
+ self.typarams.insert(typ.did, typ.name.clone());
+ }
+ clean::GenericParamDef::Lifetime(_) => {}
}
}
}
ty: item.type_(),
name: item_name.to_string(),
path: path.clone(),
- desc: String::new(),
+ desc: plain_summary_line(item.doc_value()),
parent: None,
parent_idx: None,
search_type: get_index_search_type(&item),
return this.indexOf(searchString, position) === position;
};
}
+ if (!String.prototype.endsWith) {
+ String.prototype.endsWith = function(suffix, length) {
+ var l = length || this.length;
+ return this.indexOf(suffix, l - suffix.length) !== -1;
+ };
+ }
function getPageId() {
var id = document.location.href.split('#')[1];
onEach(e.getElementsByTagName('span'), function(i_e) {
removeClass(i_e, 'line-highlighted');
});
- })
+ });
for (i = from; i <= to; ++i) {
addClass(document.getElementById(i), 'line-highlighted');
}
var obj = searchIndex[results[i].id];
obj.lev = results[i].lev;
if (isType !== true || obj.type) {
+ var res = buildHrefAndPath(obj);
+ obj.displayPath = pathSplitter(res[0]);
+ obj.fullPath = obj.displayPath + obj.name;
+ obj.href = res[1];
out.push(obj);
+ if (out.length >= MAX_RESULTS) {
+ break;
+ }
}
}
- if (out.length >= MAX_RESULTS) {
- break;
- }
}
return out;
}
// match as well.
var lev_distance = MAX_LEV_DISTANCE + 1;
if (val.generics.length > 0) {
- if (obj.generics && obj.generics.length >= val.generics.length) {
- var elems = obj.generics.slice(0);
+ if (obj.g && obj.g.length >= val.generics.length) {
+ var elems = obj.g.slice(0);
var total = 0;
var done = 0;
// We need to find the type that matches the most to remove it in order
// Check for type name and type generics (if any).
function checkType(obj, val, literalSearch) {
var lev_distance = MAX_LEV_DISTANCE + 1;
- if (obj.name === val.name) {
+ if (obj.n === val.name) {
if (literalSearch === true) {
if (val.generics && val.generics.length !== 0) {
- if (obj.generics && obj.length >= val.generics.length) {
- var elems = obj.generics.slice(0);
+ if (obj.g && obj.length >= val.generics.length) {
+ var elems = obj.g.slice(0);
var allFound = true;
var x;
}
// If the type has generics but don't match, then it won't return at this point.
// Otherwise, `checkGenerics` will return 0 and it'll return.
- if (obj.generics && obj.generics.length !== 0) {
+ if (obj.g && obj.g.length !== 0) {
var tmp_lev = checkGenerics(obj, val);
if (tmp_lev <= MAX_LEV_DISTANCE) {
return tmp_lev;
}
// Names didn't match so let's check if one of the generic types could.
if (literalSearch === true) {
- if (obj.generics && obj.generics.length > 0) {
- for (var x = 0; x < obj.generics.length; ++x) {
- if (obj.generics[x] === val.name) {
+ if (obj.g && obj.g.length > 0) {
+ for (var x = 0; x < obj.g.length; ++x) {
+ if (obj.g[x] === val.name) {
return true;
}
}
}
return false;
}
- var lev_distance = Math.min(levenshtein(obj.name, val.name), lev_distance);
+ var lev_distance = Math.min(levenshtein(obj.n, val.name), lev_distance);
if (lev_distance <= MAX_LEV_DISTANCE) {
lev_distance = Math.min(checkGenerics(obj, val), lev_distance);
- } else if (obj.generics && obj.generics.length > 0) {
+ } else if (obj.g && obj.g.length > 0) {
// We can check if the type we're looking for is inside the generics!
- for (var x = 0; x < obj.generics.length; ++x) {
- lev_distance = Math.min(levenshtein(obj.generics[x], val.name),
+ for (var x = 0; x < obj.g.length; ++x) {
+ lev_distance = Math.min(levenshtein(obj.g[x], val.name),
lev_distance);
}
}
function findArg(obj, val, literalSearch) {
var lev_distance = MAX_LEV_DISTANCE + 1;
- if (obj && obj.type && obj.type.inputs.length > 0) {
- for (var i = 0; i < obj.type.inputs.length; i++) {
- var tmp = checkType(obj.type.inputs[i], val, literalSearch);
+ if (obj && obj.type && obj.type.i && obj.type.i.length > 0) {
+ for (var i = 0; i < obj.type.i.length; i++) {
+ var tmp = checkType(obj.type.i[i], val, literalSearch);
if (literalSearch === true && tmp === true) {
return true;
}
function checkReturned(obj, val, literalSearch) {
var lev_distance = MAX_LEV_DISTANCE + 1;
- if (obj && obj.type && obj.type.output) {
- var tmp = checkType(obj.type.output, val, literalSearch);
+ if (obj && obj.type && obj.type.o) {
+ var tmp = checkType(obj.type.o, val, literalSearch);
if (literalSearch === true && tmp === true) {
return true;
}
var fullId = generateId(ty);
// allow searching for void (no output) functions as well
- var typeOutput = type.output ? type.output.name : "";
+ var typeOutput = type.o ? type.o.name : "";
var returned = checkReturned(ty, output, true);
if (output.name === "*" || returned === true) {
var in_args = false;
ALIASES[window.currentCrate][query.raw]) {
var aliases = ALIASES[window.currentCrate][query.raw];
for (var i = 0; i < aliases.length; ++i) {
+ aliases[i].is_alias = true;
+ aliases[i].alias = query.raw;
+ aliases[i].path = aliases[i].p;
+ var res = buildHrefAndPath(aliases[i]);
+ aliases[i].displayPath = pathSplitter(res[0]);
+ aliases[i].fullPath = aliases[i].displayPath + aliases[i].name;
+ aliases[i].href = res[1];
ret['others'].unshift(aliases[i]);
if (ret['others'].length > MAX_RESULTS) {
ret['others'].pop();
};
}
- function escape(content) {
- var h1 = document.createElement('h1');
- h1.textContent = content;
- return h1.innerHTML;
- }
-
- function pathSplitter(path) {
- return '<span>' + path.replace(/::/g, '::</span><span>');
- }
-
function buildHrefAndPath(item) {
var displayPath;
var href;
return [displayPath, href];
}
+ function escape(content) {
+ var h1 = document.createElement('h1');
+ h1.textContent = content;
+ return h1.innerHTML;
+ }
+
+ function pathSplitter(path) {
+ var tmp = '<span>' + path.replace(/::/g, '::</span><span>');
+ if (tmp.endsWith("<span>")) {
+ return tmp.slice(0, tmp.length - 6);
+ }
+ return tmp;
+ }
+
function addTab(array, query, display) {
var extraStyle = '';
if (display === false) {
}
var output = '';
+ var duplicates = {};
+ var length = 0;
if (array.length > 0) {
output = '<table class="search-results"' + extraStyle + '>';
- var shown = [];
array.forEach(function(item) {
- var name, type, href, displayPath;
-
- var id_ty = item.ty + item.path + item.name;
- if (shown.indexOf(id_ty) !== -1) {
- return;
- }
+ var name, type;
- shown.push(id_ty);
name = item.name;
type = itemTypes[item.ty];
- var res = buildHrefAndPath(item);
- var href = res[1];
- var displayPath = res[0];
+ if (item.is_alias !== true) {
+ if (duplicates[item.fullPath]) {
+ return;
+ }
+ duplicates[item.fullPath] = true;
+ }
+ length += 1;
output += '<tr class="' + type + ' result"><td>' +
- '<a href="' + href + '">' +
- pathSplitter(displayPath) + '<span class="' + type + '">' +
+ '<a href="' + item.href + '">' +
+ (item.is_alias === true ?
+ ('<span class="alias"><b>' + item.alias + ' </b></span><span ' +
+ 'class="grey"><i> - see </i></span>') : '') +
+ item.displayPath + '<span class="' + type + '">' +
name + '</span></a></td><td>' +
- '<a href="' + href + '">' +
+ '<a href="' + item.href + '">' +
'<span class="desc">' + escape(item.desc) +
' </span></a></td></tr>';
});
encodeURIComponent('rust ' + query.query) +
'">DuckDuckGo</a>?</div>';
}
- return output;
+ return [output, length];
}
function makeTabHeader(tabNb, text, nbElems) {
if (results['others'].length === 1 &&
getCurrentValue('rustdoc-go-to-only-result') === "true") {
var elem = document.createElement('a');
- var res = buildHrefAndPath(results['others'][0]);
- elem.href = res[1];
+ elem.href = results['others'][0].href;
elem.style.display = 'none';
// For firefox, we need the element to be in the DOM so it can be clicked.
document.body.appendChild(elem);
elem.click();
}
- var output, query = getQuery(search_input.value);
+ var query = getQuery(search_input.value);
currentResults = query.id;
- output = '<h1>Results for ' + escape(query.query) +
+
+ var ret_others = addTab(results['others'], query);
+ var ret_in_args = addTab(results['in_args'], query, false);
+ var ret_returned = addTab(results['returned'], query, false);
+
+ var output = '<h1>Results for ' + escape(query.query) +
(query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>' +
'<div id="titles">' +
- makeTabHeader(0, "In Names", results['others'].length) +
- makeTabHeader(1, "In Parameters", results['in_args'].length) +
- makeTabHeader(2, "In Return Types", results['returned'].length) +
- '</div><div id="results">';
-
- output += addTab(results['others'], query);
- output += addTab(results['in_args'], query, false);
- output += addTab(results['returned'], query, false);
- output += '</div>';
+ makeTabHeader(0, "In Names", ret_others[1]) +
+ makeTabHeader(1, "In Parameters", ret_in_args[1]) +
+ makeTabHeader(2, "In Return Types", ret_returned[1]) +
+ '</div><div id="results">' +
+ ret_others[0] + ret_in_args[0] + ret_returned[0] + '</div>';
addClass(document.getElementById('main'), 'hidden');
var search = document.getElementById('search');
}
}
if (queries.length > 1) {
- function getSmallest(arrays, positions) {
+ function getSmallest(arrays, positions, notDuplicates) {
var start = null;
for (var it = 0; it < positions.length; ++it) {
if (arrays[it].length > positions[it] &&
- (start === null || start > arrays[it][positions[it]].lev)) {
+ (start === null || start > arrays[it][positions[it]].lev) &&
+ !notDuplicates[arrays[it][positions[it]].fullPath]) {
start = arrays[it][positions[it]].lev;
}
}
function mergeArrays(arrays) {
var ret = [];
var positions = [];
+ var notDuplicates = {};
for (var x = 0; x < arrays.length; ++x) {
positions.push(0);
}
while (ret.length < MAX_RESULTS) {
- var smallest = getSmallest(arrays, positions);
+ var smallest = getSmallest(arrays, positions, notDuplicates);
+
if (smallest === null) {
break;
}
for (x = 0; x < arrays.length && ret.length < MAX_RESULTS; ++x) {
if (arrays[x].length > positions[x] &&
- arrays[x][positions[x]].lev === smallest) {
+ arrays[x][positions[x]].lev === smallest &&
+ !notDuplicates[arrays[x][positions[x]].fullPath]) {
ret.push(arrays[x][positions[x]]);
+ notDuplicates[arrays[x][positions[x]].fullPath] = true;
positions[x] += 1;
}
}
hasClass(next.nextElementSibling, 'docblock')))) {
insertAfter(toggle.cloneNode(true), e.childNodes[e.childNodes.length - 1]);
}
- }
+ };
onEach(document.getElementsByClassName('method'), func);
onEach(document.getElementsByClassName('impl'), func);
onEach(document.getElementsByClassName('impl-items'), function(e) {
}
#theme-choices > button:hover, #theme-choices > button:focus {
- background-color: #444;
+ background-color: #4e4e4e;
}
@media (max-width: 700px) {
#all-types:hover {
background-color: #606060;
}
+
+.search-results td span.alias {
+ color: #fff;
+}
+.search-results td span.grey {
+ color: #ccc;
+}
\ No newline at end of file
}
#all-types:hover {
background-color: #f9f9f9;
+}
+
+.search-results td span.alias {
+ color: #000;
+}
+.search-results td span.grey {
+ color: #999;
}
\ No newline at end of file
extern crate rustc_errors as errors;
extern crate pulldown_cmark;
extern crate tempdir;
+extern crate minifier;
extern crate serialize as rustc_serialize; // used by deriving
use std::collections::{BTreeMap, BTreeSet};
use std::default::Default;
use std::env;
-use std::fmt::Display;
-use std::io;
-use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use std::sync::mpsc::channel;
use syntax::edition::Edition;
use externalfiles::ExternalHtml;
+use rustc::session::{early_warn, early_error};
use rustc::session::search_paths::SearchPaths;
use rustc::session::config::{ErrorOutputType, RustcOptGroup, Externs, CodegenOptions};
use rustc::session::config::{nightly_options, build_codegen_options};
fn get_args() -> Option<Vec<String>> {
env::args_os().enumerate()
.map(|(i, arg)| arg.into_string().map_err(|arg| {
- print_error(format!("Argument {} is not valid Unicode: {:?}", i, arg));
+ early_warn(ErrorOutputType::default(),
+ &format!("Argument {} is not valid Unicode: {:?}", i, arg));
}).ok())
.collect()
}
"How errors and other messages are produced",
"human|json|short")
}),
+ unstable("disable-minification", |o| {
+ o.optflag("",
+ "disable-minification",
+ "Disable minification applied on JS files")
+ }),
]
}
let matches = match options.parse(&args[1..]) {
Ok(m) => m,
Err(err) => {
- print_error(err);
- return 1;
+ early_error(ErrorOutputType::default(), &err.to_string());
}
};
// Check for unstable options.
nightly_options::check_nightly_options(&matches, &opts());
- // check for deprecated options
- check_deprecated_options(&matches);
-
if matches.opt_present("h") || matches.opt_present("help") {
usage("rustdoc");
return 0;
return 0;
}
+ let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
+ Some("auto") => ColorConfig::Auto,
+ Some("always") => ColorConfig::Always,
+ Some("never") => ColorConfig::Never,
+ None => ColorConfig::Auto,
+ Some(arg) => {
+ early_error(ErrorOutputType::default(),
+ &format!("argument for --color must be `auto`, `always` or `never` \
+ (instead was `{}`)", arg));
+ }
+ };
+ let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
+ Some("human") => ErrorOutputType::HumanReadable(color),
+ Some("json") => ErrorOutputType::Json(false),
+ Some("pretty-json") => ErrorOutputType::Json(true),
+ Some("short") => ErrorOutputType::Short(color),
+ None => ErrorOutputType::HumanReadable(color),
+ Some(arg) => {
+ early_error(ErrorOutputType::default(),
+ &format!("argument for --error-format must be `human`, `json` or \
+ `short` (instead was `{}`)", arg));
+ }
+ };
+
+ let diag = core::new_handler(error_format, None);
+
+ // check for deprecated options
+ check_deprecated_options(&matches, &diag);
+
let to_check = matches.opt_strs("theme-checker");
if !to_check.is_empty() {
let paths = theme::load_css_paths(include_bytes!("html/static/themes/light.css"));
println!("rustdoc: [theme-checker] Starting tests!");
for theme_file in to_check.iter() {
print!(" - Checking \"{}\"...", theme_file);
- let (success, differences) = theme::test_theme_against(theme_file, &paths);
+ let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
if !differences.is_empty() || !success {
println!(" FAILED");
errors += 1;
}
if matches.free.is_empty() {
- print_error("missing file operand");
+ diag.struct_err("missing file operand").emit();
return 1;
}
if matches.free.len() > 1 {
- print_error("too many file operands");
+ diag.struct_err("too many file operands").emit();
return 1;
}
let input = &matches.free[0];
- let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
- Some("auto") => ColorConfig::Auto,
- Some("always") => ColorConfig::Always,
- Some("never") => ColorConfig::Never,
- None => ColorConfig::Auto,
- Some(arg) => {
- print_error(&format!("argument for --color must be `auto`, `always` or `never` \
- (instead was `{}`)", arg));
- return 1;
- }
- };
- let error_format = match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
- Some("human") => ErrorOutputType::HumanReadable(color),
- Some("json") => ErrorOutputType::Json(false),
- Some("pretty-json") => ErrorOutputType::Json(true),
- Some("short") => ErrorOutputType::Short(color),
- None => ErrorOutputType::HumanReadable(color),
- Some(arg) => {
- print_error(&format!("argument for --error-format must be `human`, `json` or \
- `short` (instead was `{}`)", arg));
- return 1;
- }
- };
-
let mut libs = SearchPaths::new();
for s in &matches.opt_strs("L") {
libs.add_path(s, error_format);
let externs = match parse_externs(&matches) {
Ok(ex) => ex,
Err(err) => {
- print_error(err);
+ diag.struct_err(&err.to_string()).emit();
return 1;
}
};
if let Some(ref p) = css_file_extension {
if !p.is_file() {
- writeln!(
- &mut io::stderr(),
- "rustdoc: option --extend-css argument must be a file."
- ).unwrap();
+ diag.struct_err("option --extend-css argument must be a file").emit();
return 1;
}
}
.iter()
.map(|s| (PathBuf::from(&s), s.to_owned())) {
if !theme_file.is_file() {
- println!("rustdoc: option --themes arguments must all be files");
+ diag.struct_err("option --themes arguments must all be files").emit();
return 1;
}
- let (success, ret) = theme::test_theme_against(&theme_file, &paths);
+ let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
if !success || !ret.is_empty() {
- println!("rustdoc: invalid theme: \"{}\"", theme_s);
- println!(" Check what's wrong with the \"theme-checker\" option");
+ diag.struct_err(&format!("invalid theme: \"{}\"", theme_s))
+ .help("check what's wrong with the --theme-checker option")
+ .emit();
return 1;
}
themes.push(theme_file);
&matches.opt_strs("html-before-content"),
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
- &matches.opt_strs("markdown-after-content")) {
+ &matches.opt_strs("markdown-after-content"), &diag) {
Some(eh) => eh,
None => return 3,
};
let linker = matches.opt_str("linker").map(PathBuf::from);
let sort_modules_alphabetically = !matches.opt_present("sort-modules-by-appearance");
let resource_suffix = matches.opt_str("resource-suffix");
+ let enable_minification = !matches.opt_present("disable-minification");
let edition = matches.opt_str("edition").unwrap_or("2015".to_string());
let edition = match edition.parse() {
Ok(e) => e,
Err(_) => {
- print_error("could not parse edition");
+ diag.struct_err("could not parse edition").emit();
return 1;
}
};
match (should_test, markdown_input) {
(true, true) => {
return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot,
- display_warnings, linker, edition, cg)
+ display_warnings, linker, edition, cg, &diag)
}
(true, false) => {
return test::run(Path::new(input), cfgs, libs, externs, test_args, crate_name,
(false, true) => return markdown::render(Path::new(input),
output.unwrap_or(PathBuf::from("doc")),
&matches, &external_html,
- !matches.opt_present("markdown-no-toc")),
+ !matches.opt_present("markdown-no-toc"), &diag),
(false, false) => {}
}
let res = acquire_input(PathBuf::from(input), externs, edition, cg, &matches, error_format,
move |out| {
let Output { krate, passes, renderinfo } = out;
+ let diag = core::new_handler(error_format, None);
info!("going to format");
match output_format.as_ref().map(|s| &**s) {
Some("html") | None => {
css_file_extension,
renderinfo,
sort_modules_alphabetically,
- themes)
+ themes,
+ enable_minification)
.expect("failed to generate documentation");
0
}
Some(s) => {
- print_error(format!("unknown output format: {}", s));
+ diag.struct_err(&format!("unknown output format: {}", s)).emit();
1
}
}
});
res.unwrap_or_else(|s| {
- print_error(format!("input error: {}", s));
+ diag.struct_err(&format!("input error: {}", s)).emit();
1
})
}
-/// Prints an uniformized error message on the standard error output
-fn print_error<T>(error_message: T) where T: Display {
- writeln!(
- &mut io::stderr(),
- "rustdoc: {}\nTry 'rustdoc --help' for more information.",
- error_message
- ).unwrap();
-}
-
/// Looks inside the command line arguments to extract the relevant input format
/// and files and then generates the necessary rustdoc output for formatting.
fn acquire_input<R, F>(input: PathBuf,
}
/// Prints deprecation warnings for deprecated options
-fn check_deprecated_options(matches: &getopts::Matches) {
+fn check_deprecated_options(matches: &getopts::Matches, diag: &errors::Handler) {
let deprecated_flags = [
"input-format",
"output-format",
for flag in deprecated_flags.into_iter() {
if matches.opt_present(flag) {
- eprintln!("WARNING: the '{}' flag is considered deprecated", flag);
- eprintln!("WARNING: please see https://github.com/rust-lang/rust/issues/44136");
- }
- }
+ let mut err = diag.struct_warn(&format!("the '{}' flag is considered deprecated",
+ flag));
+ err.warn("please see https://github.com/rust-lang/rust/issues/44136");
- if matches.opt_present("no-defaults") {
- eprintln!("WARNING: (you may want to use --document-private-items)");
+ if *flag == "no-defaults" {
+ err.help("you may want to use --document-private-items");
+ }
+
+ err.emit();
+ }
}
}
use std::io::prelude::*;
use std::path::{PathBuf, Path};
+use errors;
use getopts;
use testing;
use rustc::session::search_paths::SearchPaths;
/// Render `input` (e.g. "foo.md") into an HTML file in `output`
/// (e.g. output = "bar" => "bar/foo.html").
pub fn render(input: &Path, mut output: PathBuf, matches: &getopts::Matches,
- external_html: &ExternalHtml, include_toc: bool) -> isize {
+ external_html: &ExternalHtml, include_toc: bool, diag: &errors::Handler) -> isize {
output.push(input.file_stem().unwrap());
output.set_extension("html");
css.push_str(&s)
}
- let input_str = match load_string(input) {
+ let input_str = match load_string(input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
let mut out = match File::create(&output) {
Err(e) => {
- eprintln!("rustdoc: {}: {}", output.display(), e);
+ diag.struct_err(&format!("{}: {}", output.display(), e)).emit();
return 4;
}
Ok(f) => f
let (metadata, text) = extract_leading_metadata(&input_str);
if metadata.is_empty() {
- eprintln!("rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`");
+ diag.struct_err("invalid markdown file: no initial lines starting with `# ` or `%`").emit();
return 5;
}
let title = metadata[0];
match err {
Err(e) => {
- eprintln!("rustdoc: cannot write to `{}`: {}", output.display(), e);
+ diag.struct_err(&format!("cannot write to `{}`: {}", output.display(), e)).emit();
6
}
Ok(_) => 0,
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
display_warnings: bool, linker: Option<PathBuf>, edition: Edition,
- cg: CodegenOptions) -> isize {
- let input_str = match load_string(input) {
+ cg: CodegenOptions, diag: &errors::Handler) -> isize {
+ let input_str = match load_string(input, diag) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
Err(LoadStringError::BadUtf8) => return 2,
use std::io::Read;
use std::path::Path;
+use errors::Handler;
+
macro_rules! try_something {
- ($e:expr, $out:expr) => ({
+ ($e:expr, $diag:expr, $out:expr) => ({
match $e {
Ok(c) => c,
Err(e) => {
- eprintln!("rustdoc: got an error: {}", e);
+ $diag.struct_err(&e.to_string()).emit();
return $out;
}
}
}
}
-pub fn test_theme_against<P: AsRef<Path>>(f: &P, against: &CssPath) -> (bool, Vec<String>) {
- let mut file = try_something!(File::open(f), (false, Vec::new()));
+pub fn test_theme_against<P: AsRef<Path>>(f: &P, against: &CssPath, diag: &Handler)
+ -> (bool, Vec<String>)
+{
+ let mut file = try_something!(File::open(f), diag, (false, Vec::new()));
let mut data = Vec::with_capacity(1000);
- try_something!(file.read_to_end(&mut data), (false, Vec::new()));
+ try_something!(file.read_to_end(&mut data), diag, (false, Vec::new()));
let paths = load_css_paths(&data);
let mut ret = Vec::new();
get_differences(against, &paths, &mut ret);
/// Returns the largest integer less than or equal to a number.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.99_f32;
/// let g = 3.0_f32;
/// Returns the smallest integer greater than or equal to a number.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.01_f32;
/// let g = 4.0_f32;
/// Returns the nearest integer to a number. Round half-way cases away from
/// `0.0`.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.3_f32;
/// let g = -3.3_f32;
/// Returns the integer part of a number.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.3_f32;
/// let g = -3.7_f32;
/// Returns the fractional part of a number.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Computes the absolute value of `self`. Returns `NAN` if the
/// number is `NAN`.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// - `NAN` if the number is `NAN`
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// In other words, the result is `self / rhs` rounded to the integer `n`
/// such that `self >= n * rhs`.
///
+ /// # Examples
+ ///
/// ```
/// #![feature(euclidean_division)]
/// let a: f32 = 7.0;
///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
///
+ /// # Examples
+ ///
/// ```
/// #![feature(euclidean_division)]
/// let a: f32 = 7.0;
///
/// Using this function is generally faster than using `powf`
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Raises a number to a floating point power.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
///
/// Returns NaN if `self` is a negative number.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns `e^(self)`, (the exponential function).
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns `2^(self)`.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns the natural logarithm of the number.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// `self.log2()` can produce more accurate results for base 2, and
/// `self.log10()` can produce more accurate results for base 10.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns the base 2 logarithm of the number.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns the base 10 logarithm of the number.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// * If `self <= other`: `0:0`
/// * Else: `self - other`
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Takes the cubic root of a number.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Calculates the length of the hypotenuse of a right-angle triangle given
/// legs of length `x` and `y`.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Computes the sine of a number (in radians).
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Computes the cosine of a number (in radians).
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Computes the tangent of a number (in radians).
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// the range [-pi/2, pi/2] or NaN if the number is outside the range
/// [-1, 1].
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// the range [0, pi] or NaN if the number is outside the range
/// [-1, 1].
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Computes the arctangent of a number. Return value is in radians in the
/// range [-pi/2, pi/2];
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
/// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Simultaneously computes the sine and cosine of the number, `x`. Returns
/// `(sin(x), cos(x))`.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns `e^(self) - 1` in a way that is accurate even if the
/// number is close to zero.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns `ln(1+n)` (natural logarithm) more accurately than if
/// the operations were performed separately.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Hyperbolic sine function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Hyperbolic cosine function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Hyperbolic tangent function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Inverse hyperbolic sine function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Inverse hyperbolic cosine function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Inverse hyperbolic tangent function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f32;
///
/// Returns the largest integer less than or equal to a number.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.99_f64;
/// let g = 3.0_f64;
/// Returns the smallest integer greater than or equal to a number.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.01_f64;
/// let g = 4.0_f64;
/// Returns the nearest integer to a number. Round half-way cases away from
/// `0.0`.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.3_f64;
/// let g = -3.3_f64;
/// Returns the integer part of a number.
///
+ /// # Examples
+ ///
/// ```
/// let f = 3.3_f64;
/// let g = -3.7_f64;
/// Returns the fractional part of a number.
///
+ /// # Examples
+ ///
/// ```
/// let x = 3.5_f64;
/// let y = -3.5_f64;
/// Computes the absolute value of `self`. Returns `NAN` if the
/// number is `NAN`.
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// - `NAN` if the number is `NAN`
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
+ /// # Examples
+ ///
/// ```
/// let m = 10.0_f64;
/// let x = 4.0_f64;
/// In other words, the result is `self / rhs` rounded to the integer `n`
/// such that `self >= n * rhs`.
///
+ /// # Examples
+ ///
/// ```
/// #![feature(euclidean_division)]
/// let a: f64 = 7.0;
///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
///
+ /// # Examples
+ ///
/// ```
/// #![feature(euclidean_division)]
/// let a: f64 = 7.0;
///
/// Using this function is generally faster than using `powf`
///
+ /// # Examples
+ ///
/// ```
/// let x = 2.0_f64;
/// let abs_difference = (x.powi(2) - x*x).abs();
/// Raises a number to a floating point power.
///
+ /// # Examples
+ ///
/// ```
/// let x = 2.0_f64;
/// let abs_difference = (x.powf(2.0) - x*x).abs();
///
/// Returns NaN if `self` is a negative number.
///
+ /// # Examples
+ ///
/// ```
/// let positive = 4.0_f64;
/// let negative = -4.0_f64;
/// Returns `e^(self)`, (the exponential function).
///
+ /// # Examples
+ ///
/// ```
/// let one = 1.0_f64;
/// // e^1
/// Returns `2^(self)`.
///
+ /// # Examples
+ ///
/// ```
/// let f = 2.0_f64;
///
/// Returns the natural logarithm of the number.
///
+ /// # Examples
+ ///
/// ```
/// let one = 1.0_f64;
/// // e^1
/// `self.log2()` can produce more accurate results for base 2, and
/// `self.log10()` can produce more accurate results for base 10.
///
+ /// # Examples
+ ///
/// ```
/// let five = 5.0_f64;
///
/// Returns the base 2 logarithm of the number.
///
+ /// # Examples
+ ///
/// ```
/// let two = 2.0_f64;
///
/// Returns the base 10 logarithm of the number.
///
+ /// # Examples
+ ///
/// ```
/// let ten = 10.0_f64;
///
/// * If `self <= other`: `0:0`
/// * Else: `self - other`
///
+ /// # Examples
+ ///
/// ```
/// let x = 3.0_f64;
/// let y = -3.0_f64;
/// Takes the cubic root of a number.
///
+ /// # Examples
+ ///
/// ```
/// let x = 8.0_f64;
///
/// Calculates the length of the hypotenuse of a right-angle triangle given
/// legs of length `x` and `y`.
///
+ /// # Examples
+ ///
/// ```
/// let x = 2.0_f64;
/// let y = 3.0_f64;
/// Computes the sine of a number (in radians).
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Computes the cosine of a number (in radians).
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Computes the tangent of a number (in radians).
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// the range [-pi/2, pi/2] or NaN if the number is outside the range
/// [-1, 1].
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// the range [0, pi] or NaN if the number is outside the range
/// [-1, 1].
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Computes the arctangent of a number. Return value is in radians in the
/// range [-pi/2, pi/2];
///
+ /// # Examples
+ ///
/// ```
/// let f = 1.0_f64;
///
/// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
/// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Simultaneously computes the sine and cosine of the number, `x`. Returns
/// `(sin(x), cos(x))`.
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Returns `e^(self) - 1` in a way that is accurate even if the
/// number is close to zero.
///
+ /// # Examples
+ ///
/// ```
/// let x = 7.0_f64;
///
/// Returns `ln(1+n)` (natural logarithm) more accurately than if
/// the operations were performed separately.
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Hyperbolic sine function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Hyperbolic cosine function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Hyperbolic tangent function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Inverse hyperbolic sine function.
///
+ /// # Examples
+ ///
/// ```
/// let x = 1.0_f64;
/// let f = x.sinh().asinh();
/// Inverse hyperbolic cosine function.
///
+ /// # Examples
+ ///
/// ```
/// let x = 1.0_f64;
/// let f = x.cosh().acosh();
/// Inverse hyperbolic tangent function.
///
+ /// # Examples
+ ///
/// ```
/// use std::f64;
///
/// Whether this expression would be valid somewhere that expects a value, for example, an `if`
/// condition.
pub fn returns(&self) -> bool {
- if let ExprKind::Block(ref block) = self.node {
+ if let ExprKind::Block(ref block, _) = self.node {
match block.stmts.last().map(|last_stmt| &last_stmt.node) {
// implicit return
Some(&StmtKind::Expr(_)) => true,
///
/// The final span is the span of the argument block `|...|`
Closure(CaptureBy, Movability, P<FnDecl>, P<Expr>, Span),
- /// A block (`{ ... }`)
- Block(P<Block>),
+ /// A block (`'label: { ... }`)
+ Block(P<Block>, Option<Label>),
/// A catch block (`catch { ... }`)
Catch(P<Block>),
Token::Ident(ident, false) if ident.name == "true" => Some(LitKind::Bool(true)),
Token::Ident(ident, false) if ident.name == "false" => Some(LitKind::Bool(false)),
Token::Interpolated(ref nt) => match nt.0 {
- token::NtExpr(ref v) => match v.node {
+ token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
ExprKind::Lit(ref lit) => Some(lit.node.clone()),
_ => None,
},
self.expr(span, ast::ExprKind::MethodCall(segment, args))
}
fn expr_block(&self, b: P<ast::Block>) -> P<ast::Expr> {
- self.expr(b.span, ast::ExprKind::Block(b))
+ self.expr(b.span, ast::ExprKind::Block(b, None))
}
fn field_imm(&self, span: Span, ident: Ident, e: P<ast::Expr>) -> ast::Field {
ast::Field {
token::Pound => "Pound",
token::Dollar => "Dollar",
token::Question => "Question",
+ token::SingleQuote => "SingleQuote",
token::Eof => "Eof",
token::Whitespace | token::Comment | token::Shebang(_) => {
"expr" => token.can_begin_expr(),
"ty" => token.can_begin_type(),
"ident" => get_macro_ident(token).is_some(),
+ "literal" => token.can_begin_literal_or_bool(),
"vis" => match *token {
// The follow-set of :vis + "priv" keyword + interpolated
Token::Comma | Token::Ident(..) | Token::Interpolated(_) => true,
},
"pat" => token::NtPat(panictry!(p.parse_pat())),
"expr" => token::NtExpr(panictry!(p.parse_expr())),
+ "literal" => token::NtLiteral(panictry!(p.parse_literal_maybe_minus())),
"ty" => token::NtTy(panictry!(p.parse_ty())),
// this could be handled like a token, since it is one
"ident" => if let Some((ident, is_raw)) = get_macro_ident(&p.token) {
let msg = format!("invalid fragment specifier `{}`", bad_frag);
sess.span_diagnostic.struct_span_err(token.span(), &msg)
.help("valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, \
- `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`")
+ `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis`")
.emit();
// (This eliminates false positives and duplicates
// from error messages.)
"item" | // always terminated by `}` or `;`
"block" | // exactly one token tree
"ident" | // exactly one token tree
+ "literal" | // exactly one token tree
"meta" | // exactly one token tree
"lifetime" | // exactly one token tree
"tt" => // exactly one token tree
// being a single token, idents and lifetimes are harmless
Ok(true)
},
+ "literal" => {
+ // literals may be of a single token, or two tokens (negative numbers)
+ Ok(true)
+ },
"meta" | "tt" => {
// being either a single token or a delimited sequence, tt is
// harmless
_ => Err((format!("invalid fragment specifier `{}`", frag),
"valid fragment specifiers are `ident`, `block`, \
`stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, \
- `item` and `vis`"))
+ `literal`, `item` and `vis`"))
}
}
}
frag_name: &str,
frag_span: Span) -> bool {
match frag_name {
- "item" | "block" | "stmt" | "expr" | "pat" |
+ "item" | "block" | "stmt" | "expr" | "pat" | "lifetime" |
"path" | "ty" | "ident" | "meta" | "tt" | "" => true,
- "lifetime" => {
- if !features.macro_lifetime_matcher &&
+ "literal" => {
+ if !features.macro_literal_matcher &&
!attr::contains_name(attrs, "allow_internal_unstable") {
- let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER;
+ let explain = feature_gate::EXPLAIN_LITERAL_MATCHER;
emit_feature_err(sess,
- "macro_lifetime_matcher",
+ "macro_literal_matcher",
frag_span,
GateIssue::Language,
explain);
// Termination trait in tests (RFC 1937)
(active, termination_trait_test, "1.24.0", Some(48854), Some(Edition::Edition2018)),
- // Allows use of the :lifetime macro fragment specifier
- (active, macro_lifetime_matcher, "1.24.0", Some(46895), None),
-
// `extern` in paths
(active, extern_in_paths, "1.23.0", Some(44660), None),
// Scoped attributes
(active, tool_attributes, "1.25.0", Some(44690), None),
+
+ // Allows use of the :literal macro fragment specifier (RFC 1576)
+ (active, macro_literal_matcher, "1.27.0", Some(35625), None),
+
+ // inconsistent bounds in where clauses
+ (active, trivial_bounds, "1.28.0", Some(48214), None),
+
+ // 'a: { break 'a; }
+ (active, label_break_value, "1.28.0", Some(48594), None),
);
declare_features! (
(accepted, dyn_trait, "1.27.0", Some(44662), None),
// allow `#[must_use]` on functions; and, must-use operators (RFC 1940)
(accepted, fn_must_use, "1.27.0", Some(43302), None),
+ // Allows use of the :lifetime macro fragment specifier
+ (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
);
// If you change this, please modify src/doc/unstable-book as well. You must
pub const EXPLAIN_VIS_MATCHER: &'static str =
":vis fragment specifier is experimental and subject to change";
-pub const EXPLAIN_LIFETIME_MATCHER: &'static str =
- ":lifetime fragment specifier is experimental and subject to change";
+pub const EXPLAIN_LITERAL_MATCHER: &'static str =
+ ":literal fragment specifier is experimental and subject to change";
pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
"Unsized tuple coercion is not stable enough for use and is subject to change";
"multiple patterns in `if let` and `while let` are unstable");
}
}
+ ast::ExprKind::Block(_, opt_label) => {
+ if let Some(label) = opt_label {
+ gate_feature_post!(&self, label_break_value, label.ident.span,
+ "labels on blocks are unstable");
+ }
+ }
_ => {}
}
visit::walk_expr(self, e);
token::NtTy(ty) => token::NtTy(fld.fold_ty(ty)),
token::NtIdent(ident, is_raw) => token::NtIdent(fld.fold_ident(ident), is_raw),
token::NtLifetime(ident) => token::NtLifetime(fld.fold_ident(ident)),
+ token::NtLiteral(expr) => token::NtLiteral(fld.fold_expr(expr)),
token::NtMeta(meta) => token::NtMeta(fld.fold_meta_item(meta)),
token::NtPath(path) => token::NtPath(fld.fold_path(path)),
token::NtTT(tt) => token::NtTT(fld.fold_tt(tt)),
folder.fold_expr(body),
folder.new_span(span))
}
- ExprKind::Block(blk) => ExprKind::Block(folder.fold_block(blk)),
+ ExprKind::Block(blk, opt_label) => {
+ ExprKind::Block(folder.fold_block(blk),
+ opt_label.map(|label| folder.fold_label(label)))
+ }
ExprKind::Assign(el, er) => {
ExprKind::Assign(folder.fold_expr(el), folder.fold_expr(er))
}
ast::ExprKind::If(..) |
ast::ExprKind::IfLet(..) |
ast::ExprKind::Match(..) |
- ast::ExprKind::Block(_) |
+ ast::ExprKind::Block(..) |
ast::ExprKind::While(..) |
ast::ExprKind::WhileLet(..) |
ast::ExprKind::Loop(..) |
(c > '\x7f' && c.is_xid_continue())
}
+// The string is a valid identifier or a lifetime identifier.
+pub fn is_valid_ident(s: &str) -> bool {
+ let mut chars = s.chars();
+ ident_start(chars.next()) && chars.all(|ch| ident_continue(Some(ch)))
+}
+
#[cfg(test)]
mod tests {
use super::*;
($p:expr) => {
if let token::Interpolated(nt) = $p.token.clone() {
match nt.0 {
- token::NtExpr(ref e) => {
+ token::NtExpr(ref e) | token::NtLiteral(ref e) => {
$p.bump();
return Ok((*e).clone());
}
token::NtBlock(ref block) => {
$p.bump();
let span = $p.span;
- let kind = ExprKind::Block((*block).clone());
+ let kind = ExprKind::Block((*block).clone(), None);
return Ok($p.mk_expr(span, kind, ThinVec::new()));
}
_ => {},
pub fn parse_lit_token(&mut self) -> PResult<'a, LitKind> {
let out = match self.token {
token::Interpolated(ref nt) => match nt.0 {
- token::NtExpr(ref v) => match v.node {
+ token::NtExpr(ref v) | token::NtLiteral(ref v) => match v.node {
ExprKind::Lit(ref lit) => { lit.node.clone() }
_ => { return self.unexpected_last(&self.token); }
},
}
/// matches '-' lit | lit (cf. ast_validation::AstValidator::check_expr_within_pat)
- pub fn parse_pat_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
+ pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
maybe_whole_expr!(self);
let minus_lo = self.span;
};
}
token::OpenDelim(token::Brace) => {
- return self.parse_block_expr(lo, BlockCheckMode::Default, attrs);
+ return self.parse_block_expr(None, lo, BlockCheckMode::Default, attrs);
}
token::BinOp(token::Or) | token::OrOr => {
return self.parse_lambda_expr(attrs);
if self.eat_keyword(keywords::Loop) {
return self.parse_loop_expr(Some(label), lo, attrs)
}
- let msg = "expected `while`, `for`, or `loop` after a label";
+ if self.token == token::OpenDelim(token::Brace) {
+ return self.parse_block_expr(Some(label),
+ lo,
+ BlockCheckMode::Default,
+ attrs);
+ }
+ let msg = "expected `while`, `for`, `loop` or `{` after a label";
let mut err = self.fatal(msg);
err.span_label(self.span, msg);
return Err(err);
}
if self.eat_keyword(keywords::Unsafe) {
return self.parse_block_expr(
+ None,
lo,
BlockCheckMode::Unsafe(ast::UserProvided),
attrs);
hi = pth.span;
ex = ExprKind::Path(None, pth);
} else {
- match self.parse_lit() {
- Ok(lit) => {
- hi = lit.span;
- ex = ExprKind::Lit(P(lit));
+ match self.parse_literal_maybe_minus() {
+ Ok(expr) => {
+ hi = expr.span;
+ ex = expr.node.clone();
}
Err(mut err) => {
self.cancel(&mut err);
}
/// Parse a block or unsafe block
- pub fn parse_block_expr(&mut self, lo: Span, blk_mode: BlockCheckMode,
+ pub fn parse_block_expr(&mut self, opt_label: Option<Label>,
+ lo: Span, blk_mode: BlockCheckMode,
outer_attrs: ThinVec<Attribute>)
-> PResult<'a, P<Expr>> {
self.expect(&token::OpenDelim(token::Brace))?;
attrs.extend(self.parse_inner_attributes()?);
let blk = self.parse_block_tail(lo, blk_mode)?;
- return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), attrs));
+ return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, opt_label), attrs));
}
/// parse a.b or a(13) or a[4] or just a
// If an explicit return type is given, require a
// block to appear (RFC 968).
let body_lo = self.span;
- self.parse_block_expr(body_lo, BlockCheckMode::Default, ThinVec::new())?
+ self.parse_block_expr(None, body_lo, BlockCheckMode::Default, ThinVec::new())?
}
};
return self.parse_if_expr(ThinVec::new());
} else {
let blk = self.parse_block()?;
- return Ok(self.mk_expr(blk.span, ExprKind::Block(blk), ThinVec::new()));
+ return Ok(self.mk_expr(blk.span, ExprKind::Block(blk, None), ThinVec::new()));
}
}
let hi = self.prev_span;
Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path), ThinVec::new()))
} else {
- self.parse_pat_literal_maybe_minus()
+ self.parse_literal_maybe_minus()
}
}
}
} else {
// Try to parse everything else as literal with optional minus
- match self.parse_pat_literal_maybe_minus() {
+ match self.parse_literal_maybe_minus() {
Ok(begin) => {
if self.eat(&token::DotDotDot) {
let end = self.parse_pat_range_end()?;
Pound,
Dollar,
Question,
+ /// Used by proc macros for representing lifetimes, not generated by lexer right now.
+ SingleQuote,
/// An opening delimiter, eg. `{`
OpenDelim(DelimToken),
/// A closing delimiter, eg. `}`
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
Interpolated(ref nt) => match nt.0 {
- NtIdent(..) | NtExpr(..) | NtBlock(..) | NtPath(..) | NtLifetime(..) => true,
+ NtLiteral(..) |
+ NtIdent(..) |
+ NtExpr(..) |
+ NtBlock(..) |
+ NtPath(..) |
+ NtLifetime(..) => true,
_ => false,
},
_ => false,
}
}
+ /// Returns `true` if the token is any literal, a minus (which can follow a literal,
+ /// for example a '-42', or one of the boolean idents).
+ pub fn can_begin_literal_or_bool(&self) -> bool {
+ match *self {
+ Literal(..) => true,
+ BinOp(Minus) => true,
+ Ident(ident, false) if ident.name == keywords::True.name() => true,
+ Ident(ident, false) if ident.name == keywords::False.name() => true,
+ _ => false,
+ }
+ }
+
/// Returns an identifier if this token is an identifier.
pub fn ident(&self) -> Option<(ast::Ident, /* is_raw */ bool)> {
match *self {
Colon => ModSep,
_ => return None,
},
+ SingleQuote => match joint {
+ Ident(ident, false) => Lifetime(ident),
+ _ => return None,
+ },
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotEq |
DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar |
NtTy(P<ast::Ty>),
NtIdent(ast::Ident, /* is_raw */ bool),
NtLifetime(ast::Ident),
+ NtLiteral(P<ast::Expr>),
/// Stuff inside brackets for attributes
NtMeta(ast::MetaItem),
NtPath(ast::Path),
NtExpr(..) => f.pad("NtExpr(..)"),
NtTy(..) => f.pad("NtTy(..)"),
NtIdent(..) => f.pad("NtIdent(..)"),
+ NtLiteral(..) => f.pad("NtLiteral(..)"),
NtMeta(..) => f.pad("NtMeta(..)"),
NtPath(..) => f.pad("NtPath(..)"),
NtTT(..) => f.pad("NtTT(..)"),
token::Pound => "#".to_string(),
token::Dollar => "$".to_string(),
token::Question => "?".to_string(),
+ token::SingleQuote => "'".to_string(),
/* Literals */
token::Literal(lit, suf) => {
token::NtIdent(e, false) => ident_to_string(e),
token::NtIdent(e, true) => format!("r#{}", ident_to_string(e)),
token::NtLifetime(e) => ident_to_string(e),
+ token::NtLiteral(ref e) => expr_to_string(e),
token::NtTT(ref tree) => tt_to_string(tree.clone()),
token::NtArm(ref e) => arm_to_string(e),
token::NtImplItem(ref e) => impl_item_to_string(e),
self.print_else(e.as_ref().map(|e| &**e))
}
// "final else"
- ast::ExprKind::Block(ref b) => {
+ ast::ExprKind::Block(ref b, _) => {
self.cbox(INDENT_UNIT - 1)?;
self.ibox(0)?;
self.s.word(" else ")?;
// empty box to satisfy the close.
self.ibox(0)?;
}
- ast::ExprKind::Block(ref blk) => {
+ ast::ExprKind::Block(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident)?;
+ self.word_space(":")?;
+ }
// containing cbox, will be closed by print-block at }
self.cbox(INDENT_UNIT)?;
// head-box, will be closed by print-block after {
self.word_space("=>")?;
match arm.body.node {
- ast::ExprKind::Block(ref blk) => {
+ ast::ExprKind::Block(ref blk, opt_label) => {
+ if let Some(label) = opt_label {
+ self.print_ident(label.ident)?;
+ self.word_space(":")?;
+ }
+
// the block will close the pattern's ibox
self.print_block_unclosed_indent(blk, INDENT_UNIT)?;
expression.span,
expression.id)
}
- ExprKind::Block(ref block) => visitor.visit_block(block),
+ ExprKind::Block(ref block, ref opt_label) => {
+ walk_list!(visitor, visit_label, opt_label);
+ visitor.visit_block(block);
+ }
ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => {
visitor.visit_expr(left_hand_expression);
visitor.visit_expr(right_hand_expression);
// as the outermost one, and the last as the innermost.
false,
|cx, span, old, self_f, other_fs| {
- // match new {
- // Some(::std::cmp::Ordering::Equal) => old,
- // cmp => cmp
- // }
+ // match new {
+ // Some(::std::cmp::Ordering::Equal) => old,
+ // cmp => cmp
+ // }
- let new = {
- let other_f = match (other_fs.len(), other_fs.get(0)) {
- (1, Some(o_f)) => o_f,
- _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
- };
+ let new = {
+ let other_f = match (other_fs.len(), other_fs.get(0)) {
+ (1, Some(o_f)) => o_f,
+ _ => {
+ cx.span_bug(span,
+ "not exactly 2 arguments in `derive(PartialOrd)`")
+ }
+ };
- let args = vec![
- cx.expr_addr_of(span, self_f),
- cx.expr_addr_of(span, other_f.clone()),
- ];
+ let args = vec![
+ cx.expr_addr_of(span, self_f),
+ cx.expr_addr_of(span, other_f.clone()),
+ ];
- cx.expr_call_global(span, partial_cmp_path.clone(), args)
- };
+ cx.expr_call_global(span, partial_cmp_path.clone(), args)
+ };
- let eq_arm = cx.arm(span,
- vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
- old);
- let neq_arm = cx.arm(span,
- vec![cx.pat_ident(span, test_id)],
- cx.expr_ident(span, test_id));
+ let eq_arm = cx.arm(span,
+ vec![cx.pat_some(span, cx.pat_path(span, ordering.clone()))],
+ old);
+ let neq_arm = cx.arm(span,
+ vec![cx.pat_ident(span, test_id)],
+ cx.expr_ident(span, test_id));
- cx.expr_match(span, new, vec![eq_arm, neq_arm])
- },
+ cx.expr_match(span, new, vec![eq_arm, neq_arm])
+ },
equals_expr.clone(),
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
}
/// Strict inequality.
-fn cs_op(less: bool, equal: bool, cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<Expr> {
- let strict_op = if less { BinOpKind::Lt } else { BinOpKind::Gt };
- cs_fold1(false, // need foldr,
+fn cs_op(less: bool,
+ inclusive: bool,
+ cx: &mut ExtCtxt,
+ span: Span,
+ substr: &Substructure) -> P<Expr> {
+ let ordering_path = |cx: &mut ExtCtxt, name: &str| {
+ cx.expr_path(cx.path_global(span, cx.std_path(&["cmp", "Ordering", name])))
+ };
+
+ let par_cmp = |cx: &mut ExtCtxt, span, self_f: P<Expr>, other_fs: &[P<Expr>], default| {
+ let other_f = match (other_fs.len(), other_fs.get(0)) {
+ (1, Some(o_f)) => o_f,
+ _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
+ };
+
+ // `PartialOrd::partial_cmp(self.fi, other.fi)`
+ let cmp_path = cx.expr_path(cx.path_global(span, cx.std_path(&["cmp",
+ "PartialOrd",
+ "partial_cmp"])));
+ let cmp = cx.expr_call(span,
+ cmp_path,
+ vec![cx.expr_addr_of(span, self_f),
+ cx.expr_addr_of(span, other_f.clone())]);
+
+ let default = ordering_path(cx, default);
+ // `Option::unwrap_or(_, Ordering::Equal)`
+ let unwrap_path = cx.expr_path(cx.path_global(span, cx.std_path(&["option",
+ "Option",
+ "unwrap_or"])));
+ cx.expr_call(span, unwrap_path, vec![cmp, default])
+ };
+
+ let fold = cs_fold1(false, // need foldr
|cx, span, subexpr, self_f, other_fs| {
- // build up a series of chain ||'s and &&'s from the inside
+ // build up a series of `partial_cmp`s from the inside
// out (hence foldr) to get lexical ordering, i.e. for op ==
// `ast::lt`
//
// ```
- // self.f1 < other.f1 || (!(other.f1 < self.f1) &&
- // self.f2 < other.f2
+ // Ordering::then_with(
+ // Option::unwrap_or(
+ // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
+ // ),
+ // Option::unwrap_or(
+ // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
+ // )
// )
+ // == Ordering::Less
// ```
//
// and for op ==
// `ast::le`
//
// ```
- // self.f1 < other.f1 || (self.f1 == other.f1 &&
- // self.f2 <= other.f2
+ // Ordering::then_with(
+ // Option::unwrap_or(
+ // PartialOrd::partial_cmp(self.f1, other.f1), Ordering::Equal)
+ // ),
+ // Option::unwrap_or(
+ // PartialOrd::partial_cmp(self.f2, other.f2), Ordering::Greater)
+ // )
// )
+ // != Ordering::Greater
// ```
//
// The optimiser should remove the redundancy. We explicitly
// get use the binops to avoid auto-deref dereferencing too many
// layers of pointers, if the type includes pointers.
- //
- let other_f = match (other_fs.len(), other_fs.get(0)) {
- (1, Some(o_f)) => o_f,
- _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
- };
- let strict_ineq = cx.expr_binary(span, strict_op, self_f.clone(), other_f.clone());
+ // `Option::unwrap_or(PartialOrd::partial_cmp(self.fi, other.fi), Ordering::Equal)`
+ let par_cmp = par_cmp(cx, span, self_f, other_fs, "Equal");
- let deleg_cmp = if !equal {
- cx.expr_unary(span,
- ast::UnOp::Not,
- cx.expr_binary(span, strict_op, other_f.clone(), self_f))
- } else {
- cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone())
- };
-
- let and = cx.expr_binary(span, BinOpKind::And, deleg_cmp, subexpr);
- cx.expr_binary(span, BinOpKind::Or, strict_ineq, and)
+ // `Ordering::then_with(Option::unwrap_or(..), ..)`
+ let then_with_path = cx.expr_path(cx.path_global(span,
+ cx.std_path(&["cmp",
+ "Ordering",
+ "then_with"])));
+ cx.expr_call(span, then_with_path, vec![par_cmp, cx.lambda0(span, subexpr)])
},
|cx, args| {
match args {
Some((span, self_f, other_fs)) => {
- // Special-case the base case to generate cleaner code with
- // fewer operations (e.g. `<=` instead of `<` and `==`).
- let other_f = match (other_fs.len(), other_fs.get(0)) {
- (1, Some(o_f)) => o_f,
- _ => cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`"),
- };
-
- let op = match (less, equal) {
- (false, false) => BinOpKind::Gt,
- (false, true) => BinOpKind::Ge,
- (true, false) => BinOpKind::Lt,
- (true, true) => BinOpKind::Le,
- };
-
- cx.expr_binary(span, op, self_f, other_f.clone())
- }
- None => cx.expr_bool(span, equal)
+ let opposite = if less { "Greater" } else { "Less" };
+ par_cmp(cx, span, self_f, other_fs, opposite)
+ },
+ None => cx.expr_bool(span, inclusive)
}
},
Box::new(|cx, span, (self_args, tag_tuple), _non_self_args| {
if self_args.len() != 2 {
cx.span_bug(span, "not exactly 2 arguments in `derive(PartialOrd)`")
} else {
- let op = match (less, equal) {
+ let op = match (less, inclusive) {
(false, false) => GtOp,
(false, true) => GeOp,
(true, false) => LtOp,
}),
cx,
span,
- substr)
+ substr);
+
+ match *substr.fields {
+ EnumMatching(.., ref all_fields) |
+ Struct(.., ref all_fields) if !all_fields.is_empty() => {
+ let ordering = ordering_path(cx, if less ^ inclusive { "Less" } else { "Greater" });
+ let comp_op = if inclusive { BinOpKind::Ne } else { BinOpKind::Eq };
+
+ cx.expr_binary(span, comp_op, fold, ordering)
+ }
+ _ => fold
+ }
}
//! `[1]` Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler. 2012.
//! *Macros that work together: Compile-time bindings, partial expansion,
//! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
-//! DOI=10.1017/S0956796812000093 <http://dx.doi.org/10.1017/S0956796812000093>
+//! DOI=10.1017/S0956796812000093 <https://doi.org/10.1017/S0956796812000093>
use GLOBALS;
use Span;
-Subproject commit fd7dd99edf371ac502ae4e70288c027f6692ace0
+Subproject commit 1abfd0e562cc8f7a9577d97ee92246699093b954
LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
const char* PGOGenPath, const char* PGOUsePath) {
- // Ignore mergefunc for now as enabling it causes crashes.
- // unwrap(PMBR)->MergeFunctions = MergeFunctions;
+#if LLVM_RUSTLLVM
+ unwrap(PMBR)->MergeFunctions = MergeFunctions;
+#endif
unwrap(PMBR)->SLPVectorize = SLPVectorize;
unwrap(PMBR)->OptLevel = fromRust(OptLevel);
unwrap(PMBR)->LoopVectorize = LoopVectorize;
-Subproject commit 2f86c75a2479cf051b92fc98273daaf7f151e7a1
+Subproject commit a19ca1cd91cf97777af8268a6136bd2e4648e189
fn assert_inline(slice: &mut &[TokenTree]) {
match &slice[0] {
- TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
+ TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
_ => panic!("expected '#' char"),
}
match &slice[1] {
fn assert_doc(slice: &mut &[TokenTree]) {
match &slice[0] {
- TokenTree::Op(tt) => {
- assert_eq!(tt.op(), '#');
+ TokenTree::Punct(tt) => {
+ assert_eq!(tt.as_char(), '#');
assert_eq!(tt.spacing(), Spacing::Alone);
}
_ => panic!("expected #"),
}
match &tokens[0] {
- TokenTree::Term(tt) => assert_eq!("doc", &*tt.to_string()),
+ TokenTree::Ident(tt) => assert_eq!("doc", &*tt.to_string()),
_ => panic!("expected `doc`"),
}
match &tokens[1] {
- TokenTree::Op(tt) => {
- assert_eq!(tt.op(), '=');
+ TokenTree::Punct(tt) => {
+ assert_eq!(tt.as_char(), '=');
assert_eq!(tt.spacing(), Spacing::Alone);
}
_ => panic!("expected equals"),
fn assert_invoc(slice: &mut &[TokenTree]) {
match &slice[0] {
- TokenTree::Op(tt) => assert_eq!(tt.op(), '#'),
+ TokenTree::Punct(tt) => assert_eq!(tt.as_char(), '#'),
_ => panic!("expected '#' char"),
}
match &slice[1] {
fn assert_foo(slice: &mut &[TokenTree]) {
match &slice[0] {
- TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "fn"),
+ TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "fn"),
_ => panic!("expected fn"),
}
match &slice[1] {
- TokenTree::Term(tt) => assert_eq!(&*tt.to_string(), "foo"),
+ TokenTree::Ident(tt) => assert_eq!(&*tt.to_string(), "foo"),
_ => panic!("expected foo"),
}
match &slice[2] {
TokenTree::Group(b) => {
TokenTree::Group(Group::new(b.delimiter(), fold_stream(b.stream())))
}
- TokenTree::Op(b) => TokenTree::Op(b),
- TokenTree::Term(a) => TokenTree::Term(a),
+ TokenTree::Punct(b) => TokenTree::Punct(b),
+ TokenTree::Ident(a) => TokenTree::Ident(a),
TokenTree::Literal(a) => {
if a.to_string() != "\"foo\"" {
TokenTree::Literal(a)
// force-host
// no-prefer-dynamic
-#![feature(proc_macro, proc_macro_lib)]
#![crate_type = "proc-macro"]
extern crate proc_macro;
--- /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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro, proc_macro_lib)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Derive)]
+pub fn derive(_: TokenStream) -> TokenStream {
+ let code = "
+ fn one(r: Restricted) {
+ r.field;
+ }
+ fn two(r: Restricted) {
+ r.field;
+ }
+ ";
+
+ code.parse().unwrap()
+}
// aux-build:issue_38586.rs
// ignore-stage1
-#![feature(proc_macro)]
-
#[macro_use]
extern crate issue_38586;
--- /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.
+
+// aux-build:issue_50493.rs
+// ignore-stage1
+
+#![feature(proc_macro)]
+
+#[macro_use]
+extern crate issue_50493;
+
+#[derive(Derive)] //~ ERROR field `field` of struct `Restricted` is private
+struct Restricted {
+ pub(in restricted) field: usize, //~ visibilities can only be restricted to ancestor modules
+}
+
+mod restricted {}
+
+fn main() {}
+
// aux-build:bang_proc_macro2.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
#![allow(unused_macros)]
extern crate bang_proc_macro2;
// aux-build:bang_proc_macro.rs
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
#[macro_use]
extern crate bang_proc_macro;
// aux-build:proc-macro-gates.rs
-#![feature(proc_macro, stmt_expr_attributes)]
+#![feature(use_extern_macros, stmt_expr_attributes)]
extern crate proc_macro_gates as foo;
}
fn array_a() {
- // Accepted: return is coerced to `!` just fine, and then `22` can be
- // because we already diverged.
- let x: [!; 2] = [return, 22];
+ // Return is coerced to `!` just fine, but `22` cannot be.
+ let x: [!; 2] = [return, 22]; //~ ERROR mismatched types
}
fn array_b() {
// Check that when there are vacuous predicates in the environment
// (which make a fn uncallable) we don't erroneously cache those and
// then consider them satisfied elsewhere. The current technique for
-// doing this is just to filter "global" predicates out of the
-// environment, which means that we wind up with an error in the
-// function `vacuous`, because even though `i32: Bar<u32>` is implied
-// by its where clause, that where clause never holds.
+// doing this is to not use global caches when there is a chance that
+// the environment contains such a predicate.
+// We still error for `i32: Bar<u32>` pending #48214
trait Foo<X,Y>: Bar<X> {
}
enum Enum {
A {
x: Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
}
}
enum Enum {
A(
Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
)
}
#[derive(PartialOrd,PartialEq)]
struct Struct {
x: Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
}
fn main() {}
#[derive(PartialOrd,PartialEq)]
struct Struct(
Error //~ ERROR
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-//~^^^^ ERROR
);
fn main() {}
}
pub fn poison<S>(victim: String) where <String as Mirror<S>>::Image: Copy {
- loop { drop(victim); } //~ ERROR use of moved value
+ loop { drop(victim); }
}
fn main() {
a: Range<usize>,
//~^ ERROR PartialOrd
//~^^ ERROR Ord
- //~^^^ ERROR binary operation `<` cannot be applied to type
- //~^^^^ ERROR binary operation `>` cannot be applied to type
b: RangeTo<usize>,
//~^ ERROR PartialOrd
//~^^ ERROR Ord
- //~^^^ ERROR binary operation `<` cannot be applied to type
- //~^^^^ ERROR binary operation `>` cannot be applied to type
c: RangeFrom<usize>,
//~^ ERROR PartialOrd
//~^^ ERROR Ord
- //~^^^ ERROR binary operation `<` cannot be applied to type
- //~^^^^ ERROR binary operation `>` cannot be applied to type
d: RangeFull,
//~^ ERROR PartialOrd
//~^^ ERROR Ord
- //~^^^ ERROR binary operation `<` cannot be applied to type
- //~^^^^ ERROR binary operation `>` cannot be applied to type
e: RangeInclusive<usize>,
//~^ ERROR PartialOrd
//~^^ ERROR Ord
- //~^^^ ERROR binary operation `<` cannot be applied to type
- //~^^^^ ERROR binary operation `>` cannot be applied to type
f: RangeToInclusive<usize>,
//~^ ERROR PartialOrd
//~^^ ERROR Ord
- //~^^^ ERROR binary operation `<` cannot be applied to type
- //~^^^^ ERROR binary operation `>` cannot be applied to type
- //~^^^^^ ERROR binary operation `<=` cannot be applied to type
- //~^^^^^^ ERROR binary operation `>=` cannot be applied to type
}
fn main() {}
panic!("Invalid macro usage in cond: {}", cond);
}
let is_else = match test {
- TokenTree::Term(word) => &*word.to_string() == "else",
+ TokenTree::Ident(ref word) => &*word.to_string() == "else",
_ => false,
};
conds.push(if is_else || input.peek().is_none() {
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro;
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib, proc_macro_non_items)]
+#![feature(proc_macro, proc_macro_non_items)]
extern crate proc_macro;
// aux-build:cond_plugin.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
extern crate cond_plugin;
// aux-build:hello_macro.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
extern crate hello_macro;
let mut count = 0;
for token in input {
match &token {
- TokenTree::Op(tt) if tt.spacing() == Spacing::Alone => {
+ TokenTree::Punct(tt) if tt.spacing() == Spacing::Alone => {
count += 1;
}
TokenTree::Group(tt) => {
// except according to those terms.
// no-prefer-dynamic
-#![feature(proc_macro)]
+
#![crate_type = "proc-macro"]
extern crate proc_macro;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
extern crate hygiene_example_codegen;
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn lifetimes_bang(input: TokenStream) -> TokenStream {
+ // Roundtrip through token trees
+ input.into_iter().collect()
+}
+
+#[proc_macro_attribute]
+pub fn lifetimes_attr(_: TokenStream, input: TokenStream) -> TokenStream {
+ // Roundtrip through AST
+ input
+}
+
+#[proc_macro_derive(Lifetimes)]
+pub fn lifetimes_derive(input: TokenStream) -> TokenStream {
+ // Roundtrip through a string
+ format!("mod m {{ {} }}", input).parse().unwrap()
+}
assert_eq!(a.delimiter(), b.delimiter());
assert_eq(a.stream(), b.stream());
}
- (TokenTree::Op(a), TokenTree::Op(b)) => {
- assert_eq!(a.op(), b.op());
+ (TokenTree::Punct(a), TokenTree::Punct(b)) => {
+ assert_eq!(a.as_char(), b.as_char());
assert_eq!(a.spacing(), b.spacing());
}
(TokenTree::Literal(a), TokenTree::Literal(b)) => {
assert_eq!(a.to_string(), b.to_string());
}
- (TokenTree::Term(a), TokenTree::Term(b)) => {
+ (TokenTree::Ident(a), TokenTree::Ident(b)) => {
assert_eq!(a.to_string(), b.to_string());
}
(a, b) => panic!("{:?} != {:?}", a, b),
// aux-build:bang-macro.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
extern crate bang_macro;
use bang_macro::rewrite;
// aux-build:count_compound_ops.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
extern crate count_compound_ops;
use count_compound_ops::count_compound_ops;
// aux-build:derive-attr-cfg.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
extern crate derive_attr_cfg;
use derive_attr_cfg::Foo;
// aux-build:hygiene_example.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
extern crate hygiene_example;
use hygiene_example::hello;
// aux-build:issue-39889.rs
// ignore-stage1
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
#![allow(unused)]
extern crate issue_39889;
// aux-build:issue-40001-plugin.rs
// ignore-stage1
-#![feature(proc_macro, plugin)]
+#![feature(plugin)]
#![plugin(issue_40001_plugin)]
#[whitelisted_attr]
--- /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.
+
+// aux-build:lifetimes.rs
+// ignore-stage1
+
+#![feature(proc_macro)]
+
+extern crate lifetimes;
+use lifetimes::*;
+
+lifetimes_bang! {
+ fn bang<'a>() -> &'a u8 { &0 }
+}
+
+#[lifetimes_attr]
+fn attr<'a>() -> &'a u8 { &1 }
+
+#[derive(Lifetimes)]
+pub struct Lifetimes<'a> {
+ pub field: &'a u8,
+}
+
+fn main() {
+ assert_eq!(bang::<'static>(), &0);
+ assert_eq!(attr::<'static>(), &1);
+ let l1 = Lifetimes { field: &0 };
+ let l2 = m::Lifetimes { field: &1 };
+}
// aux-build:negative-token.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(proc_macro_non_items)]
extern crate negative_token;
// ignore-pretty
-#![feature(proc_macro)]
+#![feature(use_extern_macros)]
#[macro_use]
extern crate span_test_macros;
--- /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 for nested self-reference which caused a stack overflow.
+
+use std::fmt::Debug;
+use std::ops::*;
+
+fn gen() -> impl PartialOrd + PartialEq + Debug { }
+
+struct Bar {}
+trait Foo<T = Self> {}
+impl Foo for Bar {}
+
+fn foo() -> impl Foo {
+ Bar {}
+}
+
+fn test_impl_ops() -> impl Add + Sub + Mul + Div { 1 }
+fn test_impl_assign_ops() -> impl AddAssign + SubAssign + MulAssign + DivAssign { 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 Void {}
+fn foo(_: Result<(Void, u32), (Void, String)>) {}
+fn main() {
+ let _: fn(_) = foo;
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(label_break_value)]
+
+// Test control flow to follow label_break_value semantics
+fn label_break(a: bool, b: bool) -> u32 {
+ let mut v = 0;
+ 'b: {
+ v = 1;
+ if a {
+ break 'b;
+ }
+ v = 2;
+ if b {
+ break 'b;
+ }
+ v = 3;
+ }
+ return v;
+}
+
+// Test that values can be returned
+fn break_value(a: bool, b: bool) -> u32 {
+ let result = 'block: {
+ if a { break 'block 1; }
+ if b { break 'block 2; }
+ 3
+ };
+ result
+}
+
+// Test nesting of labeled blocks
+// here we only check that it compiles
+fn label_break_nested() {
+ 'b: {
+ println!("hi");
+ if false {
+ break 'b;
+ }
+ 'c: {
+ if false {
+ break 'b;
+ }
+ break 'c;
+ }
+ println!("hello");
+ if true {
+ break 'b;
+ }
+ }
+}
+
+// Tests for mixing labeled blocks with loop constructs
+// This function should be the identity function
+fn label_break_mixed(v: u32) -> u32 {
+ let mut r = 0;
+ 'b: {
+ // Unlabeled break still works
+ // (only crossing boundaries is an error)
+ loop {
+ break;
+ }
+ if v == 0 {
+ break 'b;
+ }
+ // Labeled breaking an inner loop still works
+ 'c: loop {
+ if r == 1 {
+ break 'c;
+ }
+ r += 1;
+ }
+ assert_eq!(r, 1);
+ if v == 1 {
+ break 'b;
+ }
+ // Labeled breaking an outer loop still works
+ 'd: loop {
+ 'e: {
+ if v == r {
+ break 'b;
+ }
+ if r == 5 {
+ break 'd;
+ }
+ r += 1;
+ }
+ }
+ assert_eq!(r, 5);
+ assert!(v > r);
+ // Here we test return from inside a labeled block
+ return v;
+ }
+ r
+}
+
+pub fn main() {
+ assert_eq!(label_break(true, false), 1);
+ assert_eq!(label_break(false, true), 2);
+ assert_eq!(label_break(false, false), 3);
+
+ assert_eq!(break_value(true, false), 1);
+ assert_eq!(break_value(false, true), 2);
+ assert_eq!(break_value(false, false), 3);
+
+ assert_eq!(label_break_mixed(0), 0);
+ assert_eq!(label_break_mixed(1), 1);
+ assert_eq!(label_break_mixed(2), 2);
+ assert_eq!(label_break_mixed(3), 3);
+ assert_eq!(label_break_mixed(4), 4);
+ assert_eq!(label_break_mixed(5), 5);
+ assert_eq!(label_break_mixed(6), 6);
+
+ // FIXME: ensure that labeled blocks work if produced by macros and in match arms
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(macro_lifetime_matcher)]
-
macro_rules! foo {
($l:lifetime, $l2:lifetime) => {
fn f<$l: $l2, $l2>(arg: &$l str, arg2: &$l2 str) -> &$l str {
// except according to those terms.
#![allow(unreachable_code)]
-#![feature(macro_lifetime_matcher)]
macro_rules! x {
($a:lifetime) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(macro_lifetime_matcher)]
-
macro_rules! foo {
($l:lifetime) => {
fn f(arg: &$l str) -> &$l str {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(macro_lifetime_matcher)]
-
macro_rules! foo {
($l:lifetime) => {
fn f<$l>(arg: &$l str) -> &$l str {
--- /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(macro_literal_matcher)]
+
+macro_rules! mtester {
+ ($l:literal) => {
+ &format!("macro caught literal: {}", $l)
+ };
+ ($e:expr) => {
+ &format!("macro caught expr: {}", $e)
+ };
+}
+
+macro_rules! two_negative_literals {
+ ($l1:literal $l2:literal) => {
+ &format!("macro caught literals: {}, {}", $l1, $l2)
+ };
+}
+
+macro_rules! only_expr {
+ ($e:expr) => {
+ &format!("macro caught expr: {}", $e)
+ };
+}
+
+macro_rules! mtester_dbg {
+ ($l:literal) => {
+ &format!("macro caught literal: {:?}", $l)
+ };
+ ($e:expr) => {
+ &format!("macro caught expr: {:?}", $e)
+ };
+}
+
+macro_rules! catch_range {
+ ($s:literal ... $e:literal) => {
+ &format!("macro caught literal: {} ... {}", $s, $e)
+ };
+ (($s:expr) ... ($e:expr)) => { // Must use ')' before '...'
+ &format!("macro caught expr: {} ... {}", $s, $e)
+ };
+}
+
+macro_rules! pat_match {
+ ($s:literal ... $e:literal) => {
+ match 3 {
+ $s ... $e => "literal, in range",
+ _ => "literal, other",
+ }
+ };
+ ($s:pat) => {
+ match 3 {
+ $s => "pat, single",
+ _ => "pat, other",
+ }
+ };
+}
+
+macro_rules! match_attr {
+ (#[$attr:meta] $e:literal) => {
+ "attr matched literal"
+ };
+ (#[$attr:meta] $e:expr) => {
+ "attr matched expr"
+ };
+}
+
+macro_rules! match_produced_attr {
+ ($lit: literal) => {
+ // Struct with doc comment passed via $literal
+ #[doc = $lit]
+ struct LiteralProduced;
+ };
+ ($expr: expr) => {
+ struct ExprProduced;
+ };
+}
+
+macro_rules! test_user {
+ ($s:literal, $e:literal) => {
+ {
+ let mut v = Vec::new();
+ for i in $s .. $e {
+ v.push(i);
+ }
+ "literal"
+ }
+ };
+ ($s:expr, $e: expr) => {
+ {
+ let mut v = Vec::new();
+ for i in $s .. $e {
+ v.push(i);
+ }
+ "expr"
+ }
+ };
+}
+
+pub fn main() {
+ // Cases where 'literal' catches
+ assert_eq!(mtester!("str"), "macro caught literal: str");
+ assert_eq!(mtester!(2), "macro caught literal: 2");
+ assert_eq!(mtester!(2.2), "macro caught literal: 2.2");
+ assert_eq!(mtester!(1u32), "macro caught literal: 1");
+ assert_eq!(mtester!(0x32), "macro caught literal: 50");
+ assert_eq!(mtester!('c'), "macro caught literal: c");
+ assert_eq!(mtester!(-1.2), "macro caught literal: -1.2");
+ assert_eq!(two_negative_literals!(-2 -3), "macro caught literals: -2, -3");
+ assert_eq!(catch_range!(2 ... 3), "macro caught literal: 2 ... 3");
+ assert_eq!(match_attr!(#[attr] 1), "attr matched literal");
+ assert_eq!(test_user!(10, 20), "literal");
+ assert_eq!(mtester!(false), "macro caught literal: false");
+ assert_eq!(mtester!(true), "macro caught literal: true");
+ match_produced_attr!("a");
+ let _a = LiteralProduced;
+ assert_eq!(pat_match!(1 ... 3), "literal, in range");
+ assert_eq!(pat_match!(4 ... 6), "literal, other");
+
+ // Cases where 'expr' catches
+ assert_eq!(mtester!((-1.2)), "macro caught expr: -1.2");
+ assert_eq!(only_expr!(-1.2), "macro caught expr: -1.2");
+ assert_eq!(mtester!((1 + 3)), "macro caught expr: 4");
+ assert_eq!(mtester_dbg!(()), "macro caught expr: ()");
+ assert_eq!(catch_range!((1 + 1) ... (2 + 2)), "macro caught expr: 2 ... 4");
+ assert_eq!(match_attr!(#[attr] (1 + 2)), "attr matched expr");
+ assert_eq!(test_user!(10, (20 + 2)), "expr");
+
+ match_produced_attr!((3 + 2));
+ let _b = ExprProduced;
+
+ // Cases where 'pat' matched
+ assert_eq!(pat_match!(3), "pat, single");
+ assert_eq!(pat_match!(6), "pat, other");
+}
--- /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-order
+
+const QUERY = 'is_nan';
+
+const EXPECTED = {
+ 'others': [
+ { 'path': 'std::f32', 'name': 'is_nan' },
+ { 'path': 'std::f64', 'name': 'is_nan' },
+ { 'path': 'std::option::Option', 'name': 'is_none' },
+ ],
+};
--- /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
+
+// compile-flags: --document-private-items
+
+#![feature(crate_visibility_modifier)]
+
+#![crate_name = "foo"]
+
+// @has 'foo/struct.FooPublic.html' '//pre' 'pub struct FooPublic'
+pub struct FooPublic;
+// @has 'foo/struct.FooJustCrate.html' '//pre' 'pub(crate) struct FooJustCrate'
+crate struct FooJustCrate;
+// @has 'foo/struct.FooPubCrate.html' '//pre' 'pub(crate) struct FooPubCrate'
+pub(crate) struct FooPubCrate;
+// @has 'foo/struct.FooSelf.html' '//pre' 'pub(self) struct FooSelf'
+pub(self) struct FooSelf;
+// @has 'foo/struct.FooInSelf.html' '//pre' 'pub(self) struct FooInSelf'
+pub(in self) struct FooInSelf;
+mod a {
+ // @has 'foo/a/struct.FooSuper.html' '//pre' 'pub(super) struct FooSuper'
+ pub(super) struct FooSuper;
+ // @has 'foo/a/struct.FooInSuper.html' '//pre' 'pub(super) struct FooInSuper'
+ pub(in super) struct FooInSuper;
+ // @has 'foo/a/struct.FooInA.html' '//pre' 'pub(in a) struct FooInA'
+ pub(in a) struct FooInA;
+ mod b {
+ // @has 'foo/a/b/struct.FooInSelfSuperB.html' '//pre' 'pub(in self::super::b) struct FooInSelfSuperB'
+ pub(in self::super::b) struct FooInSelfSuperB;
+ // @has 'foo/a/b/struct.FooInSuperSuper.html' '//pre' 'pub(in super::super) struct FooInSuperSuper'
+ pub(in super::super) struct FooInSuperSuper;
+ // @has 'foo/a/b/struct.FooInAB.html' '//pre' 'pub(in a::b) struct FooInAB'
+ pub(in a::b) struct FooInAB;
+ }
+}
--- /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.
+
+// force-host
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn invalid_punct(_: TokenStream) -> TokenStream {
+ TokenTree::from(Punct::new('`', Spacing::Alone)).into()
+}
+
+#[proc_macro]
+pub fn invalid_ident(_: TokenStream) -> TokenStream {
+ TokenTree::from(Ident::new("*", Span::call_site())).into()
+}
+
+#[proc_macro]
+pub fn invalid_raw_ident(_: TokenStream) -> TokenStream {
+ TokenTree::from(Ident::new_raw("self", Span::call_site())).into()
+}
+
+#[proc_macro]
+pub fn lexer_failure(_: TokenStream) -> TokenStream {
+ "a b ) c".parse().expect("parsing failed without panic")
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![feature(proc_macro)]
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro]
+pub fn single_quote_alone(_: TokenStream) -> TokenStream {
+ // `&'a u8`, but the `'` token is not joint
+ let trees: Vec<TokenTree> = vec![
+ Punct::new('&', Spacing::Alone).into(),
+ Punct::new('\'', Spacing::Alone).into(),
+ Ident::new("a", Span::call_site()).into(),
+ Ident::new("u8", Span::call_site()).into(),
+ ];
+ trees.into_iter().collect()
+}
// no-prefer-dynamic
#![crate_type = "proc-macro"]
-#![feature(proc_macro, proc_macro_lib)]
extern crate proc_macro;
// aux-build:plugin.rs
// ignore-stage1
-#![feature(proc_macro)]
-
#[macro_use] extern crate plugin;
#[derive(Foo, Bar)] //~ ERROR proc-macro derive panicked
error: proc-macro derive panicked
- --> $DIR/issue-36935.rs:18:15
+ --> $DIR/issue-36935.rs:16:15
|
LL | #[derive(Foo, Bar)] //~ ERROR proc-macro derive panicked
| ^^^
--- /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:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+invalid_punct!(); //~ ERROR proc macro panicked
--- /dev/null
+error: proc macro panicked
+ --> $DIR/invalid-punct-ident-1.rs:16:1
+ |
+LL | invalid_punct!(); //~ ERROR proc macro panicked
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: message: unsupported character `'`'`
+
+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.
+
+// aux-build:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+invalid_ident!(); //~ ERROR proc macro panicked
--- /dev/null
+error: proc macro panicked
+ --> $DIR/invalid-punct-ident-2.rs:16:1
+ |
+LL | invalid_ident!(); //~ ERROR proc macro panicked
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: message: `"*"` is not a valid identifier
+
+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.
+
+// aux-build:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+invalid_raw_ident!(); //~ ERROR proc macro panicked
--- /dev/null
+error: proc macro panicked
+ --> $DIR/invalid-punct-ident-3.rs:16:1
+ |
+LL | invalid_raw_ident!(); //~ ERROR proc macro panicked
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: message: `"self"` is not a valid raw identifier
+
+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.
+
+// aux-build:invalid-punct-ident.rs
+
+#[macro_use]
+extern crate invalid_punct_ident;
+
+lexer_failure!(); //~ ERROR proc macro panicked
+ //~| ERROR unexpected close delimiter: `)`
--- /dev/null
+error: unexpected close delimiter: `)`
+ --> $DIR/invalid-punct-ident-4.rs:16:1
+ |
+LL | lexer_failure!(); //~ ERROR proc macro panicked
+ | ^^^^^^^^^^^^^^^^^
+
+error: proc macro panicked
+ --> $DIR/invalid-punct-ident-4.rs:16:1
+ |
+LL | lexer_failure!(); //~ ERROR proc macro panicked
+ | ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lifetimes.rs
+
+#![feature(proc_macro, proc_macro_non_items)]
+
+extern crate lifetimes;
+
+use lifetimes::*;
+
+type A = single_quote_alone!(); //~ ERROR expected type, found `'`
--- /dev/null
+error: expected type, found `'`
+ --> $DIR/lifetimes.rs:19:10
+ |
+LL | type A = single_quote_alone!(); //~ ERROR expected type, found `'`
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
.help("input must be: `===`"))
}
- if let TokenTree::Op(tt) = tree {
- if tt.op() == '=' {
+ if let TokenTree::Punct(ref tt) = tree {
+ if tt.as_char() == '=' {
count += 1;
last_span = span;
continue
// aux-build:parent-source-spans.rs
// ignore-stage1
-#![feature(proc_macro, decl_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, decl_macro, proc_macro_non_items)]
extern crate parent_source_spans;
// aux-build:three-equals.rs
// ignore-stage1
-#![feature(proc_macro, proc_macro_non_items)]
+#![feature(use_extern_macros, proc_macro_non_items)]
extern crate three_equals;
// aux-build:bang_proc_macro.rs
#![feature(proc_macro)]
-#![allow(unused_macros)]
#[macro_use]
extern crate derive_foo;
error: cannot find derive macro `FooWithLongNan` in this scope
- --> $DIR/resolve-error.rs:37:10
+ --> $DIR/resolve-error.rs:36:10
|
LL | #[derive(FooWithLongNan)]
| ^^^^^^^^^^^^^^ help: try: `FooWithLongName`
error: cannot find attribute macro `attr_proc_macra` in this scope
- --> $DIR/resolve-error.rs:41:3
+ --> $DIR/resolve-error.rs:40:3
|
LL | #[attr_proc_macra]
| ^^^^^^^^^^^^^^^ help: try: `attr_proc_macro`
error: cannot find attribute macro `FooWithLongNan` in this scope
- --> $DIR/resolve-error.rs:45:3
+ --> $DIR/resolve-error.rs:44:3
|
LL | #[FooWithLongNan]
| ^^^^^^^^^^^^^^
error: cannot find derive macro `Dlone` in this scope
- --> $DIR/resolve-error.rs:49:10
+ --> $DIR/resolve-error.rs:48:10
|
LL | #[derive(Dlone)]
| ^^^^^ help: try: `Clone`
error: cannot find derive macro `Dlona` in this scope
- --> $DIR/resolve-error.rs:53:10
+ --> $DIR/resolve-error.rs:52:10
|
LL | #[derive(Dlona)]
| ^^^^^ help: try: `Clona`
error: cannot find derive macro `attr_proc_macra` in this scope
- --> $DIR/resolve-error.rs:57:10
+ --> $DIR/resolve-error.rs:56:10
|
LL | #[derive(attr_proc_macra)]
| ^^^^^^^^^^^^^^^
error: cannot find macro `FooWithLongNama!` in this scope
- --> $DIR/resolve-error.rs:62:5
+ --> $DIR/resolve-error.rs:61:5
|
LL | FooWithLongNama!();
| ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam`
error: cannot find macro `attr_proc_macra!` in this scope
- --> $DIR/resolve-error.rs:65:5
+ --> $DIR/resolve-error.rs:64:5
|
LL | attr_proc_macra!();
| ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac`
error: cannot find macro `Dlona!` in this scope
- --> $DIR/resolve-error.rs:68:5
+ --> $DIR/resolve-error.rs:67:5
|
LL | Dlona!();
| ^^^^^
error: cannot find macro `bang_proc_macrp!` in this scope
- --> $DIR/resolve-error.rs:71:5
+ --> $DIR/resolve-error.rs:70:5
|
LL | bang_proc_macrp!();
| ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro`
--> $DIR/unnecessary-extern-crate.rs:19:1
|
LL | extern crate alloc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:25:1
|
LL | pub extern crate test as y;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:28:1
|
LL | pub extern crate libc;
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:34:5
|
LL | extern crate alloc;
- | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+ | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:37:5
|
LL | extern crate alloc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:40:5
|
LL | pub extern crate test;
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:43:5
|
LL | pub extern crate test as y;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:47:9
|
LL | extern crate alloc;
- | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+ | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;`
error: `extern crate` is unnecessary in the new edition
--> $DIR/unnecessary-extern-crate.rs:50:9
|
LL | extern crate alloc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
error: aborting due to 10 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.
+
+pub fn main() {
+ 'a: { //~ ERROR labels on blocks are unstable
+ break 'a;
+ }
+}
--- /dev/null
+error[E0658]: labels on blocks are unstable (see issue #48594)
+ --> $DIR/feature-gate-label_break_value.rs:12:5
+ |
+LL | 'a: { //~ ERROR labels on blocks are unstable
+ | ^^
+ |
+ = help: add #![feature(label_break_value)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// Copyright 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.
-
-// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher
-// feature gate is not used.
-
-macro_rules! m { ($lt:lifetime) => {} }
-//~^ ERROR :lifetime fragment specifier is experimental and subject to change
-
-fn main() {
- m!('a);
-}
+++ /dev/null
-error[E0658]: :lifetime fragment specifier is experimental and subject to change (see issue #46895)
- --> $DIR/feature-gate-macro-lifetime-matcher.rs:14:19
- |
-LL | macro_rules! m { ($lt:lifetime) => {} }
- | ^^^^^^^^^^^^
- |
- = help: add #![feature(macro_lifetime_matcher)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the :lifetime macro fragment cannot be used when macro_lifetime_matcher
+// feature gate is not used.
+
+macro_rules! m { ($lt:literal) => {} }
+//~^ ERROR :literal fragment specifier is experimental and subject to change
+
+fn main() {
+ m!("some string literal");
+}
--- /dev/null
+error[E0658]: :literal fragment specifier is experimental and subject to change (see issue #35625)
+ --> $DIR/feature-gate-macro-literal-matcher.rs:14:19
+ |
+LL | macro_rules! m { ($lt:literal) => {} }
+ | ^^^^^^^^^^^
+ |
+ = help: add #![feature(macro_literal_matcher)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// run-pass
+
+#![allow(unused)]
+#![deny(trivial_bounds)] // Ignored without the trivial_bounds feature flag.
+
+struct A where i32: Copy;
+
+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.
+
+#![allow(unused)]
+#![allow(type_alias_bounds)]
+
+pub trait Foo {
+ fn test(&self);
+}
+
+fn generic_function<X: Foo>(x: X) {}
+
+enum E where i32: Foo { V } //~ ERROR
+
+struct S where i32: Foo; //~ ERROR
+
+trait T where i32: Foo {} //~ ERROR
+
+union U where i32: Foo { f: i32 } //~ ERROR
+
+type Y where i32: Foo = (); // OK - bound is ignored
+
+impl Foo for () where i32: Foo { //~ ERROR
+ fn test(&self) {
+ 3i32.test();
+ Foo::test(&4i32);
+ generic_function(5i32);
+ }
+}
+
+fn f() where i32: Foo //~ ERROR
+{
+ let s = S;
+ 3i32.test();
+ Foo::test(&4i32);
+ generic_function(5i32);
+}
+
+fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
+ -s
+}
+
+fn use_for() where i32: Iterator { //~ ERROR
+ for _ in 2i32 {}
+}
+
+trait A {}
+
+impl A for i32 {}
+
+struct Dst<X: ?Sized> {
+ x: X,
+}
+
+struct TwoStrs(str, str) where str: Sized; //~ ERROR
+
+fn unsized_local() where Dst<A>: Sized { //~ ERROR
+ let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+}
+
+fn return_str() -> str where str: Sized { //~ ERROR
+ *"Sized".to_string().into_boxed_str()
+}
+
+// This is currently accepted because the function pointer isn't
+// considered global.
+fn global_hr(x: fn(&())) where fn(&()): Foo { // OK
+ x.test();
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:20:1
+ |
+LL | enum E where i32: Foo { V } //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+ |
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:22:1
+ |
+LL | struct S where i32: Foo; //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+ |
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:24:1
+ |
+LL | trait T where i32: Foo {} //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+ |
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:26:1
+ |
+LL | union U where i32: Foo { f: i32 } //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+ |
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:30:1
+ |
+LL | / impl Foo for () where i32: Foo { //~ ERROR
+LL | | fn test(&self) {
+LL | | 3i32.test();
+LL | | Foo::test(&4i32);
+LL | | generic_function(5i32);
+LL | | }
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `i32`
+ |
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:38:1
+ |
+LL | / fn f() where i32: Foo //~ ERROR
+LL | | {
+LL | | let s = S;
+LL | | 3i32.test();
+LL | | Foo::test(&4i32);
+LL | | generic_function(5i32);
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `i32`
+ |
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:46:1
+ |
+LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> { //~ ERROR
+LL | | -s
+LL | | }
+ | |_^ the trait `std::ops::Neg` is not implemented for `std::string::String`
+ |
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:50:1
+ |
+LL | / fn use_for() where i32: Iterator { //~ ERROR
+LL | | for _ in 2i32 {}
+LL | | }
+ | |_^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+ |
+ = help: the trait `std::iter::Iterator` is not implemented for `i32`
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:62:1
+ |
+LL | struct TwoStrs(str, str) where str: Sized; //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `str` does not have a constant size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `A + 'static: std::marker::Sized` is not satisfied in `Dst<A + 'static>`
+ --> $DIR/feature-gate-trivial_bounds.rs:64:1
+ |
+LL | / fn unsized_local() where Dst<A>: Sized { //~ ERROR
+LL | | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+LL | | }
+ | |_^ `A + 'static` does not have a constant size known at compile-time
+ |
+ = help: within `Dst<A + 'static>`, the trait `std::marker::Sized` is not implemented for `A + 'static`
+ = note: required because it appears within the type `Dst<A + 'static>`
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ --> $DIR/feature-gate-trivial_bounds.rs:68:1
+ |
+LL | / fn return_str() -> str where str: Sized { //~ ERROR
+LL | | *"Sized".to_string().into_boxed_str()
+LL | | }
+ | |_^ `str` does not have a constant size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+ = help: see issue #48214
+ = help: add #![feature(trivial_bounds)] to the crate attributes to enable
+
+error: aborting due to 11 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
...
LL | impl<T: Clone + ?Sized> Clone for Node<[T]> {
| ------------------------------------------- first implementation here
+ |
+ = note: upstream crates may add new impl of trait `std::clone::Clone` for type `[_]` in future versions
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(label_break_value)]
+
+// Simple continue pointing to an unlabeled break should yield in an error
+fn continue_simple() {
+ 'b: {
+ continue; //~ ERROR unlabeled `continue` inside of a labeled block
+ }
+}
+
+// Labeled continue pointing to an unlabeled break should yield in an error
+fn continue_labeled() {
+ 'b: {
+ continue 'b; //~ ERROR `continue` pointing to a labeled block
+ }
+}
+
+// Simple continue that would cross a labeled block should yield in an error
+fn continue_crossing() {
+ loop {
+ 'b: {
+ continue; //~ ERROR unlabeled `continue` inside of a labeled block
+ }
+ }
+}
+
+pub fn main() {}
--- /dev/null
+error[E0695]: unlabeled `continue` inside of a labeled block
+ --> $DIR/label_break_value_continue.rs:16:9
+ |
+LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block
+ | ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
+
+error[E0696]: `continue` pointing to a labeled block
+ --> $DIR/label_break_value_continue.rs:23:9
+ |
+LL | continue 'b; //~ ERROR `continue` pointing to a labeled block
+ | ^^^^^^^^^^^ labeled blocks cannot be `continue`'d
+ |
+note: labeled block the continue points to
+ --> $DIR/label_break_value_continue.rs:22:5
+ |
+LL | / 'b: {
+LL | | continue 'b; //~ ERROR `continue` pointing to a labeled block
+LL | | }
+ | |_____^
+
+error[E0695]: unlabeled `continue` inside of a labeled block
+ --> $DIR/label_break_value_continue.rs:31:13
+ |
+LL | continue; //~ ERROR unlabeled `continue` inside of a labeled block
+ | ^^^^^^^^ `continue` statements that would diverge to or through a labeled block need to bear a label
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0695, E0696.
+For more information about an error, try `rustc --explain E0695`.
--- /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(label_break_value)]
+
+// These are forbidden occurences of label-break-value
+
+fn labeled_unsafe() {
+ unsafe 'b: {} //~ ERROR expected one of `extern`, `fn`, or `{`
+}
+
+fn labeled_if() {
+ if true 'b: {} //~ ERROR expected `{`, found `'b`
+}
+
+fn labeled_else() {
+ if true {} else 'b: {} //~ ERROR expected `{`, found `'b`
+}
+
+fn labeled_match() {
+ match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator
+}
+
+pub fn main() {}
--- /dev/null
+error: expected one of `extern`, `fn`, or `{`, found `'b`
+ --> $DIR/label_break_value_illegal_uses.rs:16:12
+ |
+LL | unsafe 'b: {} //~ ERROR expected one of `extern`, `fn`, or `{`
+ | ^^ expected one of `extern`, `fn`, or `{` here
+
+error: expected `{`, found `'b`
+ --> $DIR/label_break_value_illegal_uses.rs:20:13
+ |
+LL | if true 'b: {} //~ ERROR expected `{`, found `'b`
+ | -- ^^----
+ | | |
+ | | help: try placing this code inside a block: `{ 'b: { } }`
+ | this `if` statement has a condition, but no block
+
+error: expected `{`, found `'b`
+ --> $DIR/label_break_value_illegal_uses.rs:24:21
+ |
+LL | if true {} else 'b: {} //~ ERROR expected `{`, found `'b`
+ | ^^----
+ | |
+ | help: try placing this code inside a block: `{ 'b: { } }`
+
+error: expected one of `.`, `?`, `{`, or an operator, found `'b`
+ --> $DIR/label_break_value_illegal_uses.rs:28:17
+ |
+LL | match false 'b: {} //~ ERROR expected one of `.`, `?`, `{`, or an operator
+ | ^^ expected one of `.`, `?`, `{`, or an operator here
+
+error: aborting due to 4 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(label_break_value)]
+
+// Simple unlabeled break should yield in an error
+fn unlabeled_break_simple() {
+ 'b: {
+ break; //~ ERROR unlabeled `break` inside of a labeled block
+ }
+}
+
+// Unlabeled break that would cross a labeled block should yield in an error
+fn unlabeled_break_crossing() {
+ loop {
+ 'b: {
+ break; //~ ERROR unlabeled `break` inside of a labeled block
+ }
+ }
+}
+
+pub fn main() {}
--- /dev/null
+error[E0695]: unlabeled `break` inside of a labeled block
+ --> $DIR/label_break_value_unlabeled_break.rs:16:9
+ |
+LL | break; //~ ERROR unlabeled `break` inside of a labeled block
+ | ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label
+
+error[E0695]: unlabeled `break` inside of a labeled block
+ --> $DIR/label_break_value_unlabeled_break.rs:24:13
+ |
+LL | break; //~ ERROR unlabeled `break` inside of a labeled block
+ | ^^^^^ `break` statements that would diverge to or through a labeled block need to bear a label
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0695`.
endless_and_singing: true
};
+ let mut mut_unused_var = 1;
+
+ let (mut var, unused_var) = (1, 2);
+
if let SoulHistory { corridors_of_light,
mut hours_are_suns,
endless_and_singing: true } = who_from_the_womb_remembered {
| ^^^^^^
= note: #[warn(unused_variables)] implied by #[warn(unused)]
+warning: unused variable: `mut_unused_var`
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:13
+ |
+LL | let mut mut_unused_var = 1;
+ | ^^^^^^^^^^^^^^ help: consider using `_mut_unused_var` instead
+
+warning: unused variable: `var`
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:14
+ |
+LL | let (mut var, unused_var) = (1, 2);
+ | ^^^ help: consider using `_var` instead
+
+warning: unused variable: `unused_var`
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:19
+ |
+LL | let (mut var, unused_var) = (1, 2);
+ | ^^^^^^^^^^ help: consider using `_unused_var` instead
+
warning: unused variable: `corridors_of_light`
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:26
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:42:26
|
LL | if let SoulHistory { corridors_of_light,
| ^^^^^^^^^^^^^^^^^^ help: try ignoring the field: `corridors_of_light: _`
warning: variable `hours_are_suns` is assigned to, but never used
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:39:26
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:43:30
|
LL | mut hours_are_suns,
- | ^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^
|
= note: consider using `_hours_are_suns` instead
warning: value assigned to `hours_are_suns` is never read
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:41:9
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:45:9
|
LL | hours_are_suns = false;
| ^^^^^^^^^^^^^^
= note: #[warn(unused_assignments)] implied by #[warn(unused)]
warning: unused variable: `case`
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:50:23
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:54:23
|
LL | Large::Suit { case } => {}
| ^^^^ help: try ignoring the field: `case: _`
warning: unused variable: `case`
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:55:24
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:59:24
|
LL | &Large::Suit { case } => {}
| ^^^^ help: try ignoring the field: `case: _`
warning: unused variable: `case`
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:60:27
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:64:27
|
LL | box Large::Suit { case } => {}
| ^^^^ help: try ignoring the field: `case: _`
warning: unused variable: `case`
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:65:24
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:69:24
|
LL | (Large::Suit { case },) => {}
| ^^^^ help: try ignoring the field: `case: _`
warning: unused variable: `case`
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:70:24
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:74:24
|
LL | [Large::Suit { case }] => {}
| ^^^^ help: try ignoring the field: `case: _`
warning: unused variable: `case`
- --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:75:29
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:79:29
|
LL | Tuple(Large::Suit { case }, ()) => {}
| ^^^^ help: try ignoring the field: `case: _`
+warning: variable does not need to be mutable
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:38:9
+ |
+LL | let mut mut_unused_var = 1;
+ | ----^^^^^^^^^^^^^^
+ | |
+ | help: remove this `mut`
+ |
+note: lint level defined here
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:15:9
+ |
+LL | #![warn(unused)] // UI tests pass `-A unused` (#43896)
+ | ^^^^^^
+ = note: #[warn(unused_mut)] implied by #[warn(unused)]
+
+warning: variable does not need to be mutable
+ --> $DIR/issue-47390-unused-variable-in-struct-pattern.rs:40:10
+ |
+LL | let (mut var, unused_var) = (1, 2);
+ | ----^^^
+ | |
+ | help: remove this `mut`
+
--> $DIR/loop-break-value-no-repeat.rs:22:9
|
LL | break 22 //~ ERROR `break` with value from a `for` loop
- | ^^^^^^^^ can only break with a value inside `loop`
+ | ^^^^^^^^ can only break with a value inside `loop` or breakable block
help: instead, use `break` on its own without a value inside this `for` loop
|
LL | break //~ ERROR `break` with value from a `for` loop
LL | ($x:foo) => ()
| ^^^^^^
|
- = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `path`, `meta`, `tt`, `item` and `vis`
+ = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
error: aborting due to previous error
// Check that we are refusing to match on complex nonterminals for which tokens are
// unavailable and we'd have to go through AST comparisons.
-#![feature(decl_macro, macro_lifetime_matcher)]
+#![feature(decl_macro)]
macro simple_nonterminal($nt_ident: ident, $nt_lifetime: lifetime, $nt_tt: tt) {
macro n(a $nt_ident b $nt_lifetime c $nt_tt d) {
{}
#[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
-//~^ ERROR there is no type parameter C on trait BadAnnotation2
+//~^ ERROR there is no parameter C on trait BadAnnotation2
trait BadAnnotation2<A,B>
{}
|
= note: eg `#[rustc_on_unimplemented = "foo"]`
-error[E0230]: there is no type parameter C on trait BadAnnotation2
+error[E0230]: there is no parameter C on trait BadAnnotation2
--> $DIR/bad-annotation.rs:30:1
|
LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
| - consider giving `x` a type
LL | x.unwrap().method_that_could_exist_on_some_type();
| ^^^^^^^^^^ cannot infer type for `T`
+ |
+ = note: type must be known at this point
error[E0282]: type annotations needed
--> $DIR/issue-42234-unknown-receiver-type.rs:22:5
LL | / data.iter() //~ ERROR 22:5: 23:20: type annotations needed
LL | | .sum::<_>()
| |___________________^ cannot infer type for `_`
+ |
+ = note: type must be known at this point
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.
+
+// Test that spans get only base in eager type resolution (structurally_resolve_type).
+
+fn main() {
+ let mut x = Default::default();
+ x.0;
+ //~^ ERROR type annotations needed
+ x = 1;
+}
+
+fn foo() {
+ let mut x = Default::default();
+ x[0];
+ //~^ ERROR type annotations needed
+ x = 1;
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/method-and-field-eager-resolution.rs:15:5
+ |
+LL | let mut x = Default::default();
+ | ----- consider giving `x` a type
+LL | x.0;
+ | ^ cannot infer type for `_`
+ |
+ = note: type must be known at this point
+
+error[E0282]: type annotations needed
+ --> $DIR/method-and-field-eager-resolution.rs:22:5
+ |
+LL | let mut x = Default::default();
+ | ----- consider giving `x` a type
+LL | x[0];
+ | ^ cannot infer type for `_`
+ |
+ = note: type must be known at this point
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// intentionally blank
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition 2018
+// aux-build:removing-extern-crate.rs
+// run-rustfix
+// compile-pass
+
+#![warn(rust_2018_idioms)]
+#![allow(unused_imports)]
+
+use std as foo;
+
+
+mod another {
+ use std as foo;
+ use std;
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: --edition 2018
+// aux-build:removing-extern-crate.rs
+// run-rustfix
+// compile-pass
+
+#![warn(rust_2018_idioms)]
+#![allow(unused_imports)]
+
+extern crate std as foo;
+extern crate core;
+
+mod another {
+ extern crate std as foo;
+ extern crate std;
+}
+
+fn main() {}
--- /dev/null
+warning: `extern crate` is unnecessary in the new edition
+ --> $DIR/removing-extern-crate.rs:19:1
+ |
+LL | extern crate std as foo;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;`
+ |
+note: lint level defined here
+ --> $DIR/removing-extern-crate.rs:16:9
+ |
+LL | #![warn(rust_2018_idioms)]
+ | ^^^^^^^^^^^^^^^^
+ = note: #[warn(unnecessary_extern_crate)] implied by #[warn(rust_2018_idioms)]
+
+warning: `extern crate` is unnecessary in the new edition
+ --> $DIR/removing-extern-crate.rs:20:1
+ |
+LL | extern crate core;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
+
+warning: `extern crate` is unnecessary in the new edition
+ --> $DIR/removing-extern-crate.rs:23:5
+ |
+LL | extern crate std as foo;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use std as foo;`
+
+warning: `extern crate` is unnecessary in the new edition
+ --> $DIR/removing-extern-crate.rs:24:5
+ |
+LL | extern crate std;
+ | ^^^^^^^^^^^^^^^^^ help: use `use`: `use std;`
+
--- /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.
+
+// run-pass
+// Inconsistent bounds with trait implementations
+
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+trait A {
+ fn foo(&self) -> Self where Self: Copy;
+}
+
+impl A for str {
+ fn foo(&self) -> Self where Self: Copy { *"" }
+}
+
+impl A for i32 {
+ fn foo(&self) -> Self { 3 }
+}
+
+fn main() {}
--- /dev/null
+error[E0596]: cannot borrow immutable item `**t` as mutable
+ --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5
+ |
+LL | *t //~ ERROR
+ | ^^ cannot borrow as mutable
+ |
+ = note: the value which is causing this path not to be mutable is...: `*t`
+
+error[E0596]: cannot borrow immutable item `**t` as mutable
+ --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6
+ |
+LL | {*t} //~ ERROR
+ | ^^ cannot borrow as mutable
+ |
+ = note: the value which is causing this path not to be mutable is...: `*t`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that reborrows are still illegal with Copy mutable references
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+ *t //~ ERROR
+}
+
+fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+ {*t} //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+error[E0389]: cannot borrow data mutably in a `&` reference
+ --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:16:5
+ |
+LL | fn reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+ | --------------- use `&'a mut &'a mut i32` here to make mutable
+LL | *t //~ ERROR
+ | ^^ assignment into an immutable reference
+
+error[E0389]: cannot borrow data mutably in a `&` reference
+ --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:20:6
+ |
+LL | fn copy_reborrow_mut<'a>(t: &'a &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy {
+ | --------------- use `&'a mut &'a mut i32` here to make mutable
+LL | {*t} //~ ERROR
+ | ^^ assignment into an immutable reference
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0389`.
--- /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.
+
+// run-pass
+// Check tautalogically false `Copy` bounds
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+fn copy_string(t: String) -> String where String: Copy {
+ is_copy(&t);
+ let x = t;
+ drop(t);
+ t
+}
+
+fn copy_out_string(t: &String) -> String where String: Copy {
+ *t
+}
+
+fn copy_string_with_param<T>(x: String) where String: Copy {
+ let y = x;
+ let z = x;
+}
+
+// Check that no reborrowing occurs
+fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy {
+ is_copy(t);
+ let x = *t;
+ drop(x);
+ x
+}
+
+fn is_copy<T: Copy>(t: &T) {}
+
+
+fn main() {}
--- /dev/null
+warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-copy.rs:16:1
+ |
+LL | / fn copy_string(t: String) -> String where String: Copy {
+LL | | is_copy(&t);
+LL | | let x = t;
+LL | | drop(t);
+LL | | t
+LL | | }
+ | |_^
+ |
+ = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-copy.rs:23:1
+ |
+LL | / fn copy_out_string(t: &String) -> String where String: Copy {
+LL | | *t
+LL | | }
+ | |_^
+
+warning: Trait bound std::string::String: std::marker::Copy does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-copy.rs:27:1
+ |
+LL | / fn copy_string_with_param<T>(x: String) where String: Copy {
+LL | | let y = x;
+LL | | let z = x;
+LL | | }
+ | |_^
+
+warning: Trait bound for<'b> &'b mut i32: std::marker::Copy does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-copy.rs:33:1
+ |
+LL | / fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy {
+LL | | is_copy(t);
+LL | | let x = *t;
+LL | | drop(x);
+LL | | x
+LL | | }
+ | |_^
+
--- /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.
+
+// run-pass
+// Check tautalogically false `Sized` bounds
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+trait A {}
+
+impl A for i32 {}
+
+struct T<X: ?Sized> {
+ x: X,
+}
+
+struct S(str, str) where str: Sized;
+
+fn unsized_local() where for<'a> T<A + 'a>: Sized {
+ let x: T<A> = *(Box::new(T { x: 1 }) as Box<T<A>>);
+}
+
+fn return_str() -> str where str: Sized {
+ *"Sized".to_string().into_boxed_str()
+}
+
+fn main() {}
--- /dev/null
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-sized.rs:24:1
+ |
+LL | struct S(str, str) where str: Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound for<'a> T<A + 'a>: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-sized.rs:26:1
+ |
+LL | / fn unsized_local() where for<'a> T<A + 'a>: Sized {
+LL | | let x: T<A> = *(Box::new(T { x: 1 }) as Box<T<A>>);
+LL | | }
+ | |_^
+
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-sized.rs:30:1
+ |
+LL | / fn return_str() -> str where str: Sized {
+LL | | *"Sized".to_string().into_boxed_str()
+LL | | }
+ | |_^
+
--- /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.
+
+// run-pass
+// Test that inconsistent bounds are used in well-formedness checks
+#![feature(trivial_bounds)]
+
+use std::fmt::Debug;
+
+pub fn foo() where Vec<str>: Debug, str: Copy {
+ let x = vec![*"1"];
+ println!("{:?}", x);
+}
+
+fn main() {}
--- /dev/null
+warning: Trait bound std::vec::Vec<str>: std::fmt::Debug does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-well-formed.rs:17:1
+ |
+LL | / pub fn foo() where Vec<str>: Debug, str: Copy {
+LL | | let x = vec![*"1"];
+LL | | println!("{:?}", x);
+LL | | }
+ | |_^
+ |
+ = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound str: std::marker::Copy does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent-well-formed.rs:17:1
+ |
+LL | / pub fn foo() where Vec<str>: Debug, str: Copy {
+LL | | let x = vec![*"1"];
+LL | | println!("{:?}", x);
+LL | | }
+ | |_^
+
--- /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.
+
+// run-pass
+
+// Check that tautalogically false bounds are accepted, and are used
+// in type inference.
+#![feature(trivial_bounds)]
+#![allow(unused)]
+
+pub trait Foo {
+ fn test(&self);
+}
+
+fn generic_function<X: Foo>(x: X) {}
+
+enum E where i32: Foo { V }
+
+struct S where i32: Foo;
+
+trait T where i32: Foo {}
+
+union U where i32: Foo { f: i32 }
+
+type Y where i32: Foo = ();
+
+impl Foo for () where i32: Foo {
+ fn test(&self) {
+ 3i32.test();
+ Foo::test(&4i32);
+ generic_function(5i32);
+ }
+}
+
+fn f() where i32: Foo {
+ let s = S;
+ 3i32.test();
+ Foo::test(&4i32);
+ generic_function(5i32);
+}
+
+fn g() where &'static str: Foo {
+ "Foo".test();
+ Foo::test(&"Foo");
+ generic_function("Foo");
+}
+
+trait A {}
+
+impl A for i32 {}
+
+struct Dst<X: ?Sized> {
+ x: X,
+}
+
+struct TwoStrs(str, str) where str: Sized;
+
+fn unsized_local() where for<'a> Dst<A + 'a>: Sized {
+ let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+}
+
+fn return_str() -> str where str: Sized {
+ *"Sized".to_string().into_boxed_str()
+}
+
+fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> {
+ -s
+}
+
+fn use_for() where i32: Iterator {
+ for _ in 2i32 {}
+}
+
+fn main() {}
--- /dev/null
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:24:1
+ |
+LL | enum E where i32: Foo { V }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(trivial_bounds)] on by default
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:26:1
+ |
+LL | struct S where i32: Foo;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:28:1
+ |
+LL | trait T where i32: Foo {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:30:1
+ |
+LL | union U where i32: Foo { f: i32 }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: where clauses are not enforced in type aliases
+ --> $DIR/trivial-bounds-inconsistent.rs:32:14
+ |
+LL | type Y where i32: Foo = ();
+ | ^^^^^^^^
+ |
+ = note: #[warn(type_alias_bounds)] on by default
+ = help: the clause will not be checked when the type alias is used, and should be removed
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:32:1
+ |
+LL | type Y where i32: Foo = ();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:34:1
+ |
+LL | / impl Foo for () where i32: Foo {
+LL | | fn test(&self) {
+LL | | 3i32.test();
+LL | | Foo::test(&4i32);
+LL | | generic_function(5i32);
+LL | | }
+LL | | }
+ | |_^
+
+warning: Trait bound i32: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:42:1
+ |
+LL | / fn f() where i32: Foo {
+LL | | let s = S;
+LL | | 3i32.test();
+LL | | Foo::test(&4i32);
+LL | | generic_function(5i32);
+LL | | }
+ | |_^
+
+warning: Trait bound &'static str: Foo does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:49:1
+ |
+LL | / fn g() where &'static str: Foo {
+LL | | "Foo".test();
+LL | | Foo::test(&"Foo");
+LL | | generic_function("Foo");
+LL | | }
+ | |_^
+
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:63:1
+ |
+LL | struct TwoStrs(str, str) where str: Sized;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: Trait bound for<'a> Dst<A + 'a>: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:65:1
+ |
+LL | / fn unsized_local() where for<'a> Dst<A + 'a>: Sized {
+LL | | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+LL | | }
+ | |_^
+
+warning: Trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:69:1
+ |
+LL | / fn return_str() -> str where str: Sized {
+LL | | *"Sized".to_string().into_boxed_str()
+LL | | }
+ | |_^
+
+warning: Trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:73:1
+ |
+LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg<Output=String> {
+LL | | -s
+LL | | }
+ | |_^
+
+warning: Trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-inconsistent.rs:77:1
+ |
+LL | / fn use_for() where i32: Iterator {
+LL | | for _ in 2i32 {}
+LL | | }
+ | |_^
+
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that false Copy bounds don't leak
+#![feature(trivial_bounds)]
+
+fn copy_out_string(t: &String) -> String where String: Copy {
+ *t
+}
+
+fn move_out_string(t: &String) -> String {
+ *t //~ ERROR
+}
+
+fn main() {}
--- /dev/null
+error[E0507]: cannot move out of borrowed content
+ --> $DIR/trivial-bounds-leak-copy.rs:19:5
+ |
+LL | *t //~ ERROR
+ | ^^ cannot move out of borrowed content
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that false bounds don't leak
+#![feature(trivial_bounds)]
+
+pub trait Foo {
+ fn test(&self);
+}
+
+fn return_str() -> str where str: Sized {
+ *"Sized".to_string().into_boxed_str()
+}
+
+fn cant_return_str() -> str { //~ ERROR
+ *"Sized".to_string().into_boxed_str()
+}
+
+fn my_function() where i32: Foo
+{
+ 3i32.test();
+ Foo::test(&4i32);
+ generic_function(5i32);
+}
+
+fn foo() {
+ 3i32.test(); //~ ERROR
+ Foo::test(&4i32); //~ ERROR
+ generic_function(5i32); //~ ERROR
+}
+
+fn generic_function<T: Foo>(t: T) {}
+
+fn main() {}
+
--- /dev/null
+error[E0277]: the trait bound `str: std::marker::Sized` is not satisfied
+ --> $DIR/trivial-bounds-leak.rs:22:25
+ |
+LL | fn cant_return_str() -> str { //~ ERROR
+ | ^^^ `str` does not have a constant size known at compile-time
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `str`
+ = note: the return type of a function must have a statically known size
+
+error[E0599]: no method named `test` found for type `i32` in the current scope
+ --> $DIR/trivial-bounds-leak.rs:34:10
+ |
+LL | 3i32.test(); //~ ERROR
+ | ^^^^
+ |
+ = help: items from traits can only be used if the trait is implemented and in scope
+ = note: the following trait defines an item `test`, perhaps you need to implement it:
+ candidate #1: `Foo`
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/trivial-bounds-leak.rs:35:5
+ |
+LL | Foo::test(&4i32); //~ ERROR
+ | ^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+ |
+note: required by `Foo::test`
+ --> $DIR/trivial-bounds-leak.rs:15:5
+ |
+LL | fn test(&self);
+ | ^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `i32: Foo` is not satisfied
+ --> $DIR/trivial-bounds-leak.rs:36:5
+ |
+LL | generic_function(5i32); //~ ERROR
+ | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `i32`
+ |
+note: required by `generic_function`
+ --> $DIR/trivial-bounds-leak.rs:39:1
+ |
+LL | fn generic_function<T: Foo>(t: T) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors occurred: E0277, E0599.
+For more information about an error, try `rustc --explain E0277`.
--- /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(trivial_bounds)]
+#![allow(unused)]
+#![deny(trivial_bounds)]
+
+struct A where i32: Copy; //~ ERROR
+
+trait X<T: Copy> {}
+
+trait Y<T>: Copy {}
+
+trait Z {
+ type S: Copy;
+}
+
+// Check only the bound the user writes trigger the lint
+fn trivial_elaboration<T>() where T: X<i32> + Z<S = i32>, i32: Y<T> {} // OK
+
+fn global_param() where i32: X<()> {} //~ ERROR
+
+// Should only error on the trait bound, not the implicit
+// projection bound <i32 as Z>::S == i32.
+fn global_projection() where i32: Z<S = i32> {} //~ ERROR
+
+impl A {
+ fn new() -> A { A }
+}
+
+// Lifetime bounds should be linted as well
+fn global_lifetimes() where i32: 'static, &'static str: 'static {}
+//~^ ERROR
+//~| ERROR
+
+fn local_lifetimes<'a>() where i32: 'a, &'a str: 'a {} // OK
+
+fn global_outlives() where 'static: 'static {} //~ ERROR
+
+// Check that each bound is checked individually
+fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
+
+fn main() {}
--- /dev/null
+error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-lint.rs:15:1
+ |
+LL | struct A where i32: Copy; //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: lint level defined here
+ --> $DIR/trivial-bounds-lint.rs:13:9
+ |
+LL | #![deny(trivial_bounds)]
+ | ^^^^^^^^^^^^^^
+
+error: Trait bound i32: X<()> does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-lint.rs:28:1
+ |
+LL | fn global_param() where i32: X<()> {} //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Trait bound i32: Z does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-lint.rs:32:1
+ |
+LL | fn global_projection() where i32: Z<S = i32> {} //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Lifetime bound i32 : 'static does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-lint.rs:39:1
+ |
+LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Lifetime bound &'static str : 'static does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-lint.rs:39:1
+ |
+LL | fn global_lifetimes() where i32: 'static, &'static str: 'static {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Lifetime bound 'static : 'static does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-lint.rs:45:1
+ |
+LL | fn global_outlives() where 'static: 'static {} //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Trait bound i32: std::marker::Copy does not depend on any type or lifetime parameters
+ --> $DIR/trivial-bounds-lint.rs:48:1
+ |
+LL | fn mixed_bounds<T: Copy>() where i32: X<T> + Copy {} //~ ERROR
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
-Subproject commit 7a4c00c669b3bf0ffb24c7aa89a776cd48f1e2d0
+Subproject commit c658fc8cbcd1f199edd445a49cb43139ebdc5f02
-Subproject commit d2ade31a52a417257742de72c5936a8a342a34b5
+Subproject commit 3e3df0485004bc1343bc8200b68c67ac7c479b28
const TEST_FOLDER = 'src/test/rustdoc-js/';
+function getNextStep(content, pos, stop) {
+ while (pos < content.length && content[pos] !== stop &&
+ (content[pos] === ' ' || content[pos] === '\t' || content[pos] === '\n')) {
+ pos += 1;
+ }
+ if (pos >= content.length) {
+ return null;
+ }
+ if (content[pos] !== stop) {
+ return pos * -1;
+ }
+ return pos;
+}
+
// Stupid function extractor based on indent.
function extractFunction(content, functionName) {
- var x = content.split('\n');
- var in_func = false;
var indent = 0;
- var lines = [];
-
- for (var i = 0; i < x.length; ++i) {
- if (in_func === false) {
- var splitter = "function " + functionName + "(";
- if (x[i].trim().startsWith(splitter)) {
- in_func = true;
- indent = x[i].split(splitter)[0].length;
- lines.push(x[i]);
- }
- } else {
- lines.push(x[i]);
- if (x[i].trim() === "}" && x[i].split("}")[0].length === indent) {
- return lines.join("\n");
+ var splitter = "function " + functionName + "(";
+
+ while (true) {
+ var start = content.indexOf(splitter);
+ if (start === -1) {
+ break;
+ }
+ var pos = start;
+ while (pos < content.length && content[pos] !== ')') {
+ pos += 1;
+ }
+ if (pos >= content.length) {
+ break;
+ }
+ pos = getNextStep(content, pos + 1, '{');
+ if (pos === null) {
+ break;
+ } else if (pos < 0) {
+ content = content.slice(-pos);
+ continue;
+ }
+ while (pos < content.length) {
+ if (content[pos] === '"' || content[pos] === "'") {
+ var stop = content[pos];
+ var is_escaped = false;
+ do {
+ if (content[pos] === '\\') {
+ pos += 2;
+ } else {
+ pos += 1;
+ }
+ } while (pos < content.length &&
+ (content[pos] !== stop || content[pos - 1] === '\\'));
+ } else if (content[pos] === '{') {
+ indent += 1;
+ } else if (content[pos] === '}') {
+ indent -= 1;
+ if (indent === 0) {
+ return content.slice(start, pos + 1);
+ }
}
+ pos += 1;
}
+ content = content.slice(start + 1);
}
return null;
}
// Stupid function extractor for array.
function extractArrayVariable(content, arrayName) {
- var x = content.split('\n');
- var found_var = false;
- var lines = [];
-
- for (var i = 0; i < x.length; ++i) {
- if (found_var === false) {
- var splitter = "var " + arrayName + " = [";
- if (x[i].trim().startsWith(splitter)) {
- found_var = true;
- i -= 1;
- }
- } else {
- lines.push(x[i]);
- if (x[i].endsWith('];')) {
- return lines.join("\n");
+ var splitter = "var " + arrayName;
+ while (true) {
+ var start = content.indexOf(splitter);
+ if (start === -1) {
+ break;
+ }
+ var pos = getNextStep(content, start, '=');
+ if (pos === null) {
+ break;
+ } else if (pos < 0) {
+ content = content.slice(-pos);
+ continue;
+ }
+ pos = getNextStep(content, pos, '[');
+ if (pos === null) {
+ break;
+ } else if (pos < 0) {
+ content = content.slice(-pos);
+ continue;
+ }
+ while (pos < content.length) {
+ if (content[pos] === '"' || content[pos] === "'") {
+ var stop = content[pos];
+ do {
+ if (content[pos] === '\\') {
+ pos += 2;
+ } else {
+ pos += 1;
+ }
+ } while (pos < content.length &&
+ (content[pos] !== stop || content[pos - 1] === '\\'));
+ } else if (content[pos] === ']' &&
+ pos + 1 < content.length &&
+ content[pos + 1] === ';') {
+ return content.slice(start, pos + 2);
}
+ pos += 1;
}
+ content = content.slice(start + 1);
}
return null;
}
// Stupid function extractor for variable.
function extractVariable(content, varName) {
- var x = content.split('\n');
- var found_var = false;
- var lines = [];
-
- for (var i = 0; i < x.length; ++i) {
- if (found_var === false) {
- var splitter = "var " + varName + " = ";
- if (x[i].trim().startsWith(splitter)) {
- found_var = true;
- i -= 1;
- }
- } else {
- lines.push(x[i]);
- if (x[i].endsWith(';')) {
- return lines.join("\n");
+ var splitter = "var " + varName;
+ while (true) {
+ var start = content.indexOf(splitter);
+ if (start === -1) {
+ break;
+ }
+ var pos = getNextStep(content, start, '=');
+ if (pos === null) {
+ break;
+ } else if (pos < 0) {
+ content = content.slice(-pos);
+ continue;
+ }
+ while (pos < content.length) {
+ if (content[pos] === '"' || content[pos] === "'") {
+ var stop = content[pos];
+ do {
+ if (content[pos] === '\\') {
+ pos += 2;
+ } else {
+ pos += 1;
+ }
+ } while (pos < content.length &&
+ (content[pos] !== stop || content[pos - 1] === '\\'));
+ } else if (content[pos] === ';') {
+ return content.slice(start, pos + 1);
}
+ pos += 1;
}
+ content = content.slice(start + 1);
}
return null;
}
for (var i = 0; i < thingsToLoad.length; ++i) {
var tmp = funcToCall(fileContent, thingsToLoad[i]);
if (tmp === null) {
- console.error('enable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
+ console.error('unable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"');
process.exit(1);
}
content += tmp;
// execQuery first parameter is built in getQuery (which takes in the search input).
// execQuery last parameter is built in buildIndex.
// buildIndex requires the hashmap from search-index.
- var functionsToLoad = ["levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery",
- "execSearch"];
+ var functionsToLoad = ["buildHrefAndPath", "pathSplitter", "levenshtein", "validateResult",
+ "getQuery", "buildIndex", "execQuery", "execSearch"];
finalJS += 'window = { "currentCrate": "std" };\n';
+ finalJS += 'var rootPath = "../";\n';
finalJS += ALIASES;
finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs);
finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs);
-Subproject commit 0f8029f251b569a010cb5cfc5a8bff8bf3c949ac
+Subproject commit db8cb0b8d6942d42a322b1d36b2504977404f362