# 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
- set NO_CCACHE=1
- sh src/ci/run.sh
+on_failure:
+ # Dump crash log
+ - set PATH=%PATH%;"C:\Program Files (x86)\Windows Kits\10\Debuggers\X64"
+ - if exist %LOCALAPPDATA%\CrashDumps for %%f in (%LOCALAPPDATA%\CrashDumps\*) do cdb -c "k;q" -G -z "%%f"
+
branches:
only:
- auto
[[package]]
name = "assert_cli"
-version = "0.5.4"
+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)",
- "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "build_helper"
version = "0.1.0"
-[[package]]
-name = "bytecount"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "byteorder"
version = "1.2.2"
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "cargo_metadata"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "cargo_metadata"
version = "0.5.4"
[[package]]
name = "clippy"
-version = "0.0.197"
+version = "0.0.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.197",
+ "clippy_lints 0.0.200",
"compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
- "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "clippy_lints"
-version = "0.0.197"
+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)",
"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)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "derive-new"
-version = "0.5.2"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "difference"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
[[package]]
name = "difference"
version = "2.0.0"
[[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)",
"serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
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"
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "proc-macro2"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "proc-macro2"
version = "0.3.6"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "quote"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "quote"
version = "0.5.1"
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "regex"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "regex-syntax"
version = "0.5.5"
"ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "regex-syntax"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "remote-test-client"
version = "0.1.0"
[[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",
+ "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.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "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)",
]
"rustc_target 0.0.0",
]
+[[package]]
+name = "rustc-rayon"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc-rayon-core"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustc-serialize"
version = "0.3.24"
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_cratesio_shim 0.0.0",
"serialize 0.0.0",
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
+ "rustc-rayon 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_allocator 0.0.0",
"rustc_borrowck 0.0.0",
"rustc_data_structures 0.0.0",
"rustc_traits 0.0.0",
"rustc_trans_utils 0.0.0",
"rustc_typeck 0.0.0",
+ "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",
"syntax 0.0.0",
"syntax_ext 0.0.0",
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)",
"syntax_pos 0.0.0",
]
+[[package]]
+name = "rustc_version"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "rustdoc"
version = "0.0.0"
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.4 (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.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "same-file"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "same-file"
version = "1.0.2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "semver"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "semver"
version = "0.9.0"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "skeptic"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
- "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "smallvec"
version = "0.6.0"
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "syn"
-version = "0.12.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "syn"
version = "0.13.1"
name = "syntax_pos"
version = "0.0.0"
dependencies = [
+ "arena 0.0.0",
"rustc_data_structures 0.0.0",
"scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",
[[package]]
name = "tempfile"
-version = "3.0.1"
+version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-[[package]]
-name = "walkdir"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "walkdir"
version = "2.1.4"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
-"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930"
+"checksum assert_cli 0.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 bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
-"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de"
"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87"
-"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
"checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3"
"checksum cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0ebb87d1116151416c0cf66a0e3fb6430cccd120fd6300794b4dfaa050ac40ba"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
"checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0"
"checksum curl-sys 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71c63a540a9ee4e15e56c3ed9b11a2f121239b9f6d7b7fe30f616e048148df9a"
"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3"
-"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71"
+"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a"
"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
-"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
"checksum 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 pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
-"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0"
"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118"
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
"checksum quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
-"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
"checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d"
"checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb"
+"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3"
"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb"
+"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
-"checksum rls-analysis 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a41488cf5dc99d6ce383319d2978756567b70d4ed0539eb0d9ce07763e732e46"
+"checksum rls-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"
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
+"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a"
"checksum rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85"
-"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637"
"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade"
"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
-"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248"
"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
-"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a"
"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9"
"checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d"
"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b"
"checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545"
"checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
-"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5"
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
"checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde"
"checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
-"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c"
+"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b"
"checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508"
"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
"checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561"
"checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
-"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
"checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
cmd.arg(format!("-Clinker={}", host_linker));
}
+
+ if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
+ if s == "true" {
+ cmd.arg("-C").arg("target-feature=+crt-static");
+ }
+ if s == "false" {
+ cmd.arg("-C").arg("target-feature=-crt-static");
+ }
+ }
}
if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() {
"""
return os.path.join(self.build_dir, self.build, "stage0")
- def get_toml(self, key):
+ def get_toml(self, key, section=None):
"""Returns the value of the given key in config.toml, otherwise returns None
>>> rb = RustBuild()
>>> rb.get_toml("key3") is None
True
+
+ Optionally also matches the section the key appears in
+
+ >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"'
+ >>> rb.get_toml('key', 'a')
+ 'value1'
+ >>> rb.get_toml('key', 'b')
+ 'value2'
+ >>> rb.get_toml('key', 'c') is None
+ True
"""
+
+ cur_section = None
for line in self.config_toml.splitlines():
+ section_match = re.match(r'^\s*\[(.*)\]\s*$', line)
+ if section_match is not None:
+ cur_section = section_match.group(1)
+
match = re.match(r'^{}\s*=(.*)$'.format(key), line)
if match is not None:
value = match.group(1)
- return self.get_string(value) or value.strip()
+ if section is None or section == cur_section:
+ return self.get_string(value) or value.strip()
return None
def cargo(self):
env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
(os.pathsep + env["LIBRARY_PATH"]) \
if "LIBRARY_PATH" in env else ""
- env["RUSTFLAGS"] = "-Cdebuginfo=2"
+ env["RUSTFLAGS"] = "-Cdebuginfo=2 "
+
+ build_section = "target.{}".format(self.build_triple())
+ target_features = []
+ if self.get_toml("crt-static", build_section) == "true":
+ target_features += ["+crt-static"]
+ elif self.get_toml("crt-static", build_section) == "false":
+ target_features += ["-crt-static"]
+ if target_features:
+ env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " "
+
env["PATH"] = os.path.join(self.bin_root(), "bin") + \
os.pathsep + env["PATH"]
if not os.path.isfile(self.cargo()):
cargo.env("RUSTC_CRT_STATIC", x.to_string());
}
+ if let Some(x) = self.crt_static(compiler.host) {
+ cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
+ }
+
// Enable usage of unstable features
cargo.env("RUSTC_BOOTSTRAP", "1");
self.add_rust_test_threads(&mut cargo);
};
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
s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum"
echo "Attempting to download $s3url"
+ rm -f /tmp/rustci_docker_cache
set +e
- loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/')
+ retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url"
+ loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/')
set -e
echo "Downloaded containers:\n$loaded_images"
fi
touch "$TOOLSTATE_FILE"
+# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE
+
set +e
python2.7 "$X_PY" test --no-fail-fast \
src/doc/book \
cat "$TOOLSTATE_FILE"
echo
+# This function checks that if a tool's submodule changed, the tool's state must improve
verify_status() {
echo "Verifying status of $1..."
if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
fi
}
+# deduplicates the submodule check and the assertion that on beta some tools MUST be passing
+check_dispatch() {
+ if [ "$1" = submodule_changed ]; then
+ # ignore $2 (branch id)
+ verify_status $3 $4
+ elif [ "$2" = beta ]; then
+ echo "Requiring test passing for $3..."
+ if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then
+ exit 4
+ fi
+ fi
+}
+
+# list all tools here
+status_check() {
+ check_dispatch $1 beta book src/doc/book
+ check_dispatch $1 beta nomicon src/doc/nomicon
+ check_dispatch $1 beta reference src/doc/reference
+ check_dispatch $1 beta rust-by-example src/doc/rust-by-example
+ check_dispatch $1 beta rls src/tool/rls
+ check_dispatch $1 beta rustfmt src/tool/rustfmt
+ # these tools are not required for beta to successfully branch
+ check_dispatch $1 nightly clippy-driver src/tool/clippy
+ check_dispatch $1 nightly miri src/tool/miri
+}
+
# If this PR is intended to update one of these tools, do not let the build pass
# when they do not test-pass.
-verify_status book src/doc/book
-verify_status nomicon src/doc/nomicon
-verify_status reference src/doc/reference
-verify_status rust-by-example src/doc/rust-by-example
-verify_status rls src/tool/rls
-verify_status rustfmt src/tool/rustfmt
-verify_status clippy-driver src/tool/clippy
-verify_status miri src/tool/miri
+status_check "submodule_changed"
if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
. "$(dirname $0)/repo.sh"
exit 0
fi
-if grep -q fail "$TOOLSTATE_FILE"; then
- exit 4
-fi
+# abort compilation if an important tool doesn't build
+# (this code is reachable if not on the nightly channel)
+status_check "beta_required"
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" \
while true; do
"$@" && break || {
if [[ $n -lt $max ]]; then
+ sleep $n # don't retry immediately
((n++))
echo "Command failed. Attempt $n/$max:"
else
echo "The command has failed after $n attempts."
- exit 1
+ return 1
fi
}
done
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),
}
fn replace(&mut self, key: K) -> Option<K> {
+ self.ensure_root_is_owned();
match search::search_tree::<marker::Mut, K, (), K>(self.root.as_mut(), &key) {
Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
GoDown(handle) => {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> BTreeMap<K, V> {
BTreeMap {
- root: node::Root::new_leaf(),
+ root: node::Root::shared_empty_root(),
length: 0,
}
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn clear(&mut self) {
- // FIXME(gereeter) .clear() allocates
*self = BTreeMap::new();
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn entry(&mut self, key: K) -> Entry<K, V> {
+ // FIXME(@porglezomp) Avoid allocating if we don't insert
+ self.ensure_root_is_owned();
match search::search_tree(self.root.as_mut(), &key) {
Found(handle) => {
Occupied(OccupiedEntry {
}
fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
+ self.ensure_root_is_owned();
let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node();
// Iterate through all key-value pairs, pushing them into nodes at the right level.
for (key, value) in iter {
let total_num = self.len();
let mut right = Self::new();
+ right.root = node::Root::new_leaf();
for _ in 0..(self.root.as_ref().height()) {
right.root.push_level();
}
self.fix_top();
}
+
+ /// If the root node is the shared root node, allocate our own node.
+ fn ensure_root_is_owned(&mut self) {
+ if self.root.is_shared_root() {
+ self.root = node::Root::new_leaf();
+ }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
self.for_each(drop);
unsafe {
let leaf_node = ptr::read(&self.front).into_node();
+ if leaf_node.is_shared_root() {
+ return;
+ }
+
if let Some(first_parent) = leaf_node.deallocate_and_ascend() {
let mut cur_node = first_parent.into_node();
while let Some(parent) = cur_node.deallocate_and_ascend() {
///
/// See also rust-lang/rfcs#197, which would make this structure significantly more safe by
/// avoiding accidentally dropping unused and uninitialized keys and values.
+///
+/// We put the metadata first so that its position is the same for every `K` and `V`, in order
+/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to
+/// prevent them from being reordered.
+#[repr(C)]
struct LeafNode<K, V> {
- /// The arrays storing the actual data of the node. Only the first `len` elements of each
- /// array are initialized and valid.
- keys: [K; CAPACITY],
- vals: [V; CAPACITY],
-
/// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`.
/// This either points to an actual node or is null.
parent: *const InternalNode<K, V>,
/// The number of keys and values this node stores.
///
- /// This is at the end of the node's representation and next to `parent_idx` to encourage
- /// the compiler to join `len` and `parent_idx` into the same 32-bit word, reducing space
- /// overhead.
+ /// This next to `parent_idx` to encourage the compiler to join `len` and
+ /// `parent_idx` into the same 32-bit word, reducing space overhead.
len: u16,
+
+ /// The arrays storing the actual data of the node. Only the first `len` elements of each
+ /// array are initialized and valid.
+ keys: [K; CAPACITY],
+ vals: [V; CAPACITY],
}
impl<K, V> LeafNode<K, V> {
len: 0
}
}
+
+ fn is_shared_root(&self) -> bool {
+ self as *const _ == &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V>
+ }
}
+// We need to implement Sync here in order to make a static instance.
+unsafe impl Sync for LeafNode<(), ()> {}
+
+// An empty node used as a placeholder for the root node, to avoid allocations.
+// We use () in order to save space, since no operation on an empty tree will
+// ever take a pointer past the first key.
+static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode {
+ parent: ptr::null(),
+ parent_idx: 0,
+ len: 0,
+ keys: [(); CAPACITY],
+ vals: [(); CAPACITY],
+};
+
/// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden
/// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an
/// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the
unsafe impl<K: Send, V: Send> Send for Root<K, V> { }
impl<K, V> Root<K, V> {
+ pub fn is_shared_root(&self) -> bool {
+ self.as_ref().is_shared_root()
+ }
+
+ pub fn shared_empty_root() -> Self {
+ Root {
+ node: unsafe {
+ BoxedNode::from_ptr(NonNull::new_unchecked(
+ &EMPTY_ROOT_NODE as *const _ as *const LeafNode<K, V> as *mut _
+ ))
+ },
+ height: 0,
+ }
+ }
+
pub fn new_leaf() -> Self {
Root {
node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })),
/// new node the root. This increases the height by 1 and is the opposite of `pop_level`.
pub fn push_level(&mut self)
-> NodeRef<marker::Mut, K, V, marker::Internal> {
+ debug_assert!(!self.is_shared_root());
let mut new_node = Box::new(unsafe { InternalNode::new() });
new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) };
}
}
+ pub fn is_shared_root(&self) -> bool {
+ self.as_leaf().is_shared_root()
+ }
+
pub fn keys(&self) -> &[K] {
- self.reborrow().into_slices().0
+ self.reborrow().into_key_slice()
}
- pub fn vals(&self) -> &[V] {
- self.reborrow().into_slices().1
+ fn vals(&self) -> &[V] {
+ self.reborrow().into_val_slice()
}
/// Finds the parent of the current node. Returns `Ok(handle)` if the current
marker::Edge
>
> {
+ debug_assert!(!self.is_shared_root());
let node = self.node;
let ret = self.ascend().ok();
Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>());
}
}
- pub fn keys_mut(&mut self) -> &mut [K] {
- unsafe { self.reborrow_mut().into_slices_mut().0 }
+ fn keys_mut(&mut self) -> &mut [K] {
+ unsafe { self.reborrow_mut().into_key_slice_mut() }
}
- pub fn vals_mut(&mut self) -> &mut [V] {
- unsafe { self.reborrow_mut().into_slices_mut().1 }
+ fn vals_mut(&mut self) -> &mut [V] {
+ unsafe { self.reborrow_mut().into_val_slice_mut() }
}
}
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Immut<'a>, K, V, Type> {
- pub fn into_slices(self) -> (&'a [K], &'a [V]) {
- unsafe {
- (
+ fn into_key_slice(self) -> &'a [K] {
+ // When taking a pointer to the keys, if our key has a stricter
+ // alignment requirement than the shared root does, then the pointer
+ // would be out of bounds, which LLVM assumes will not happen. If the
+ // alignment is more strict, we need to make an empty slice that doesn't
+ // use an out of bounds pointer.
+ if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+ &[]
+ } else {
+ // Here either it's not the root, or the alignment is less strict,
+ // in which case the keys pointer will point "one-past-the-end" of
+ // the node, which is allowed by LLVM.
+ unsafe {
slice::from_raw_parts(
self.as_leaf().keys.as_ptr(),
self.len()
- ),
- slice::from_raw_parts(
- self.as_leaf().vals.as_ptr(),
- self.len()
)
+ }
+ }
+ }
+
+ fn into_val_slice(self) -> &'a [V] {
+ debug_assert!(!self.is_shared_root());
+ unsafe {
+ slice::from_raw_parts(
+ self.as_leaf().vals.as_ptr(),
+ self.len()
)
}
}
+
+ fn into_slices(self) -> (&'a [K], &'a [V]) {
+ let k = unsafe { ptr::read(&self) };
+ (k.into_key_slice(), self.into_val_slice())
+ }
}
impl<'a, K: 'a, V: 'a, Type> NodeRef<marker::Mut<'a>, K, V, Type> {
}
}
- pub fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) {
- unsafe {
- (
+ fn into_key_slice_mut(mut self) -> &'a mut [K] {
+ if mem::align_of::<K>() > mem::align_of::<LeafNode<(), ()>>() && self.is_shared_root() {
+ &mut []
+ } else {
+ unsafe {
slice::from_raw_parts_mut(
&mut self.as_leaf_mut().keys as *mut [K] as *mut K,
self.len()
- ),
- slice::from_raw_parts_mut(
- &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
- self.len()
)
+ }
+ }
+ }
+
+ fn into_val_slice_mut(mut self) -> &'a mut [V] {
+ debug_assert!(!self.is_shared_root());
+ unsafe {
+ slice::from_raw_parts_mut(
+ &mut self.as_leaf_mut().vals as *mut [V] as *mut V,
+ self.len()
)
}
}
+
+ fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) {
+ let k = unsafe { ptr::read(&self) };
+ (k.into_key_slice_mut(), self.into_val_slice_mut())
+ }
}
impl<'a, K, V> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
pub fn push(&mut self, key: K, val: V) {
// Necessary for correctness, but this is an internal module
debug_assert!(self.len() < CAPACITY);
+ debug_assert!(!self.is_shared_root());
let idx = self.len();
pub fn push_front(&mut self, key: K, val: V) {
// Necessary for correctness, but this is an internal module
debug_assert!(self.len() < CAPACITY);
+ debug_assert!(!self.is_shared_root());
unsafe {
slice_insert(self.keys_mut(), 0, key);
fn insert_fit(&mut self, key: K, val: V) -> *mut V {
// Necessary for correctness, but in a private module
debug_assert!(self.node.len() < CAPACITY);
+ debug_assert!(!self.node.is_shared_root());
unsafe {
slice_insert(self.node.keys_mut(), self.idx, key);
/// allocated node.
pub fn split(mut self)
-> (NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, K, V, Root<K, V>) {
+ debug_assert!(!self.node.is_shared_root());
unsafe {
let mut new_node = Box::new(LeafNode::new());
/// now adjacent key/value pairs to the left and right of this handle.
pub fn remove(mut self)
-> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
+ debug_assert!(!self.node.is_shared_root());
unsafe {
let k = slice_remove(self.node.keys_mut(), self.idx);
let v = slice_remove(self.node.vals_mut(), self.idx);
}
}
- /// Ensures that the buffer contains at least enough space to hold
- /// `used_cap + needed_extra_cap` elements. If it doesn't already,
- /// will reallocate the minimum possible amount of memory necessary.
- /// Generally this will be exactly the amount of memory necessary,
- /// but in principle the allocator is free to give back more than
- /// we asked for.
- ///
- /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
- /// the requested space. This is not really unsafe, but the unsafe
- /// code *you* write that relies on the behavior of this function may break.
- ///
- /// # Panics
- ///
- /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
- /// * Panics on 32-bit platforms if the requested capacity exceeds
- /// `isize::MAX` bytes.
- ///
- /// # Aborts
- ///
- /// Aborts on OOM
+ /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting.
pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize)
-> Result<(), CollectionAllocErr> {
}
}
+ /// Ensures that the buffer contains at least enough space to hold
+ /// `used_cap + needed_extra_cap` elements. If it doesn't already,
+ /// will reallocate the minimum possible amount of memory necessary.
+ /// Generally this will be exactly the amount of memory necessary,
+ /// but in principle the allocator is free to give back more than
+ /// we asked for.
+ ///
+ /// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
+ /// the requested space. This is not really unsafe, but the unsafe
+ /// code *you* write that relies on the behavior of this function may break.
+ ///
+ /// # Panics
+ ///
+ /// * Panics if the requested capacity exceeds `usize::MAX` bytes.
+ /// * Panics on 32-bit platforms if the requested capacity exceeds
+ /// `isize::MAX` bytes.
+ ///
+ /// # Aborts
+ ///
+ /// Aborts on OOM
pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve_exact(used_cap, needed_extra_cap) {
Err(CapacityOverflow) => capacity_overflow(),
Ok(cmp::max(double_cap, required_cap))
}
+ /// The same as `reserve`, but returns on errors instead of panicking or aborting.
+ pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
+ -> Result<(), CollectionAllocErr> {
+ unsafe {
+ // NOTE: we don't early branch on ZSTs here because we want this
+ // to actually catch "asking for more than usize::MAX" in that case.
+ // If we make it past the first branch then we are guaranteed to
+ // panic.
+
+ // Don't actually need any more capacity.
+ // Wrapping in case they give a bad `used_cap`
+ if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
+ return Ok(());
+ }
+
+ let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?;
+ let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
+
+ // FIXME: may crash and burn on over-reserve
+ alloc_guard(new_layout.size())?;
+
+ let res = match self.current_layout() {
+ Some(layout) => {
+ debug_assert!(new_layout.align() == layout.align());
+ self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
+ }
+ None => self.a.alloc(new_layout),
+ };
+
+ self.ptr = res?.cast().into();
+ self.cap = new_cap;
+
+ Ok(())
+ }
+ }
+
/// Ensures that the buffer contains at least enough space to hold
/// `used_cap + needed_extra_cap` elements. If it doesn't already have
/// enough capacity, will reallocate enough space plus comfortable slack
/// # vector.push_all(&[1, 3, 5, 7, 9]);
/// # }
/// ```
- pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize)
- -> Result<(), CollectionAllocErr> {
- unsafe {
- // NOTE: we don't early branch on ZSTs here because we want this
- // to actually catch "asking for more than usize::MAX" in that case.
- // If we make it past the first branch then we are guaranteed to
- // panic.
-
- // Don't actually need any more capacity.
- // Wrapping in case they give a bad `used_cap`
- if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
- return Ok(());
- }
-
- let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?;
- let new_layout = Layout::array::<T>(new_cap).map_err(|_| CapacityOverflow)?;
-
- // FIXME: may crash and burn on over-reserve
- alloc_guard(new_layout.size())?;
-
- let res = match self.current_layout() {
- Some(layout) => {
- debug_assert!(new_layout.align() == layout.align());
- self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
- }
- None => self.a.alloc(new_layout),
- };
-
- self.ptr = res?.cast().into();
- self.cap = new_cap;
-
- Ok(())
- }
- }
-
- /// The same as try_reserve, but errors are lowered to a call to oom().
pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) {
match self.try_reserve(used_cap, needed_extra_cap) {
Err(CapacityOverflow) => capacity_overflow(),
//! A dynamically-sized view into a contiguous sequence, `[T]`.
//!
+//! *[See also the slice primitive type](../../std/primitive.slice.html).*
+//!
//! Slices are a view into a block of memory represented as a pointer and a
//! length.
//!
//! * Further methods that return iterators are [`.split`], [`.splitn`],
//! [`.chunks`], [`.windows`] and more.
//!
-//! *[See also the slice primitive type](../../std/primitive.slice.html).*
-//!
//! [`Clone`]: ../../std/clone/trait.Clone.html
//! [`Eq`]: ../../std/cmp/trait.Eq.html
//! [`Ord`]: ../../std/cmp/trait.Ord.html
//! Unicode string slices.
//!
+//! *[See also the `str` primitive type](../../std/primitive.str.html).*
+//!
//! The `&str` type is one of the two main string types, the other being `String`.
//! Unlike its `String` counterpart, its contents are borrowed.
//!
//! ```
//! let hello_world: &'static str = "Hello, world!";
//! ```
-//!
-//! *[See also the `str` primitive type](../../std/primitive.str.html).*
#![stable(feature = "rust1", since = "1.0.0")]
assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ");
}
-#[test]
-fn test_slice() {
- assert_eq!("ab", &"abc"[0..2]);
- assert_eq!("bc", &"abc"[1..3]);
- assert_eq!("", &"abc"[1..1]);
- assert_eq!("\u{65e5}", &"\u{65e5}\u{672c}"[0..3]);
+// The current implementation of SliceIndex fails to handle methods
+// orthogonally from range types; therefore, it is worth testing
+// all of the indexing operations on each input.
+mod slice_index {
+ // Test a slicing operation **that should succeed,**
+ // testing it on all of the indexing methods.
+ //
+ // This is not suitable for testing failure on invalid inputs.
+ macro_rules! assert_range_eq {
+ ($s:expr, $range:expr, $expected:expr)
+ => {
+ let mut s: String = $s.to_owned();
+ let mut expected: String = $expected.to_owned();
+ {
+ let s: &str = &s;
+ let expected: &str = &expected;
+
+ assert_eq!(&s[$range], expected, "(in assertion for: index)");
+ assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
+ unsafe {
+ assert_eq!(
+ s.get_unchecked($range), expected,
+ "(in assertion for: get_unchecked)",
+ );
+ }
+ }
+ {
+ let s: &mut str = &mut s;
+ let expected: &mut str = &mut expected;
+
+ assert_eq!(
+ &mut s[$range], expected,
+ "(in assertion for: index_mut)",
+ );
+ assert_eq!(
+ s.get_mut($range), Some(&mut expected[..]),
+ "(in assertion for: get_mut)",
+ );
+ unsafe {
+ assert_eq!(
+ s.get_unchecked_mut($range), expected,
+ "(in assertion for: get_unchecked_mut)",
+ );
+ }
+ }
+ }
+ }
- let data = "ประเทศไทย中华";
- assert_eq!("ป", &data[0..3]);
- assert_eq!("ร", &data[3..6]);
- assert_eq!("", &data[3..3]);
- assert_eq!("华", &data[30..33]);
+ // Make sure the macro can actually detect bugs,
+ // because if it can't, then what are we even doing here?
+ //
+ // (Be aware this only demonstrates the ability to detect bugs
+ // in the FIRST method that panics, as the macro is not designed
+ // to be used in `should_panic`)
+ #[test]
+ #[should_panic(expected = "out of bounds")]
+ fn assert_range_eq_can_fail_by_panic() {
+ assert_range_eq!("abc", 0..5, "abc");
+ }
- fn a_million_letter_x() -> String {
- let mut i = 0;
- let mut rs = String::new();
- while i < 100000 {
- rs.push_str("华华华华华华华华华华");
- i += 1;
+ // (Be aware this only demonstrates the ability to detect bugs
+ // in the FIRST method it calls, as the macro is not designed
+ // to be used in `should_panic`)
+ #[test]
+ #[should_panic(expected = "==")]
+ fn assert_range_eq_can_fail_by_inequality() {
+ assert_range_eq!("abc", 0..2, "abc");
+ }
+
+ // Generates test cases for bad index operations.
+ //
+ // This generates `should_panic` test cases for Index/IndexMut
+ // and `None` test cases for get/get_mut.
+ macro_rules! panic_cases {
+ ($(
+ in mod $case_name:ident {
+ data: $data:expr;
+
+ // optional:
+ //
+ // a similar input for which DATA[input] succeeds, and the corresponding
+ // output str. This helps validate "critical points" where an input range
+ // straddles the boundary between valid and invalid.
+ // (such as the input `len..len`, which is just barely valid)
+ $(
+ good: data[$good:expr] == $output:expr;
+ )*
+
+ bad: data[$bad:expr];
+ message: $expect_msg:expr; // must be a literal
+ }
+ )*) => {$(
+ mod $case_name {
+ #[test]
+ fn pass() {
+ let mut v: String = $data.into();
+
+ $( assert_range_eq!(v, $good, $output); )*
+
+ {
+ let v: &str = &v;
+ assert_eq!(v.get($bad), None, "(in None assertion for get)");
+ }
+
+ {
+ let v: &mut str = &mut v;
+ assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
+ }
+ }
+
+ #[test]
+ #[should_panic(expected = $expect_msg)]
+ fn index_fail() {
+ let v: String = $data.into();
+ let v: &str = &v;
+ let _v = &v[$bad];
+ }
+
+ #[test]
+ #[should_panic(expected = $expect_msg)]
+ fn index_mut_fail() {
+ let mut v: String = $data.into();
+ let v: &mut str = &mut v;
+ let _v = &mut v[$bad];
+ }
+ }
+ )*};
+ }
+
+ #[test]
+ fn simple_ascii() {
+ assert_range_eq!("abc", .., "abc");
+
+ assert_range_eq!("abc", 0..2, "ab");
+ assert_range_eq!("abc", 0..=1, "ab");
+ assert_range_eq!("abc", ..2, "ab");
+ assert_range_eq!("abc", ..=1, "ab");
+
+ assert_range_eq!("abc", 1..3, "bc");
+ assert_range_eq!("abc", 1..=2, "bc");
+ assert_range_eq!("abc", 1..1, "");
+ assert_range_eq!("abc", 1..=0, "");
+ }
+
+ #[test]
+ fn simple_unicode() {
+ // 日本
+ assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}");
+
+ assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}");
+ assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}");
+ assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}");
+ assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}");
+
+ assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}");
+ assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}");
+ assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}");
+
+ let data = "ประเทศไทย中华";
+ assert_range_eq!(data, 0..3, "ป");
+ assert_range_eq!(data, 3..6, "ร");
+ assert_range_eq!(data, 3..3, "");
+ assert_range_eq!(data, 30..33, "华");
+
+ /*0: 中
+ 3: 华
+ 6: V
+ 7: i
+ 8: ệ
+ 11: t
+ 12:
+ 13: N
+ 14: a
+ 15: m */
+ let ss = "中华Việt Nam";
+ assert_range_eq!(ss, 3..6, "华");
+ assert_range_eq!(ss, 6..16, "Việt Nam");
+ assert_range_eq!(ss, 6..=15, "Việt Nam");
+ assert_range_eq!(ss, 6.., "Việt Nam");
+
+ assert_range_eq!(ss, 0..3, "中");
+ assert_range_eq!(ss, 3..7, "华V");
+ assert_range_eq!(ss, 3..=6, "华V");
+ assert_range_eq!(ss, 3..3, "");
+ assert_range_eq!(ss, 3..=2, "");
+ }
+
+ #[test]
+ #[cfg(not(target_arch = "asmjs"))] // hits an OOM
+ fn simple_big() {
+ fn a_million_letter_x() -> String {
+ let mut i = 0;
+ let mut rs = String::new();
+ while i < 100000 {
+ rs.push_str("华华华华华华华华华华");
+ i += 1;
+ }
+ rs
}
- rs
+ fn half_a_million_letter_x() -> String {
+ let mut i = 0;
+ let mut rs = String::new();
+ while i < 100000 {
+ rs.push_str("华华华华华");
+ i += 1;
+ }
+ rs
+ }
+ let letters = a_million_letter_x();
+ assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x());
}
- fn half_a_million_letter_x() -> String {
- let mut i = 0;
- let mut rs = String::new();
- while i < 100000 {
- rs.push_str("华华华华华");
- i += 1;
+
+ #[test]
+ #[should_panic]
+ fn test_slice_fail() {
+ &"中华Việt Nam"[0..2];
+ }
+
+ panic_cases! {
+ in mod rangefrom_len {
+ data: "abcdef";
+ good: data[6..] == "";
+ bad: data[7..];
+ message: "out of bounds";
+ }
+
+ in mod rangeto_len {
+ data: "abcdef";
+ good: data[..6] == "abcdef";
+ bad: data[..7];
+ message: "out of bounds";
+ }
+
+ in mod rangetoinclusive_len {
+ data: "abcdef";
+ good: data[..=5] == "abcdef";
+ bad: data[..=6];
+ message: "out of bounds";
+ }
+
+ in mod range_len_len {
+ data: "abcdef";
+ good: data[6..6] == "";
+ bad: data[7..7];
+ message: "out of bounds";
+ }
+
+ in mod rangeinclusive_len_len {
+ data: "abcdef";
+ good: data[6..=5] == "";
+ bad: data[7..=6];
+ message: "out of bounds";
}
- rs
}
- let letters = a_million_letter_x();
- assert_eq!(half_a_million_letter_x(), &letters[0..3 * 500000]);
-}
-#[test]
-fn test_slice_2() {
- let ss = "中华Việt Nam";
+ panic_cases! {
+ in mod range_neg_width {
+ data: "abcdef";
+ good: data[4..4] == "";
+ bad: data[4..3];
+ message: "begin <= end (4 <= 3)";
+ }
- assert_eq!("华", &ss[3..6]);
- assert_eq!("Việt Nam", &ss[6..16]);
+ in mod rangeinclusive_neg_width {
+ data: "abcdef";
+ good: data[4..=3] == "";
+ bad: data[4..=2];
+ message: "begin <= end (4 <= 3)";
+ }
+ }
- assert_eq!("ab", &"abc"[0..2]);
- assert_eq!("bc", &"abc"[1..3]);
- assert_eq!("", &"abc"[1..1]);
+ mod overflow {
+ panic_cases! {
+ in mod rangeinclusive {
+ data: "hello";
+ // note: using 0 specifically ensures that the result of overflowing is 0..0,
+ // so that `get` doesn't simply return None for the wrong reason.
+ bad: data[0..=usize::max_value()];
+ message: "maximum usize";
+ }
- assert_eq!("中", &ss[0..3]);
- assert_eq!("华V", &ss[3..7]);
- assert_eq!("", &ss[3..3]);
- /*0: 中
- 3: 华
- 6: V
- 7: i
- 8: ệ
- 11: t
- 12:
- 13: N
- 14: a
- 15: m */
-}
+ in mod rangetoinclusive {
+ data: "hello";
+ bad: data[..=usize::max_value()];
+ message: "maximum usize";
+ }
+ }
+ }
-#[test]
-#[should_panic]
-fn test_slice_fail() {
- &"中华Việt Nam"[0..2];
-}
+ mod boundary {
+ const DATA: &'static str = "abcαβγ";
+
+ const BAD_START: usize = 4;
+ const GOOD_START: usize = 3;
+ const BAD_END: usize = 6;
+ const GOOD_END: usize = 7;
+ const BAD_END_INCL: usize = BAD_END - 1;
+ const GOOD_END_INCL: usize = GOOD_END - 1;
+
+ // it is especially important to test all of the different range types here
+ // because some of the logic may be duplicated as part of micro-optimizations
+ // to dodge unicode boundary checks on half-ranges.
+ panic_cases! {
+ in mod range_1 {
+ data: super::DATA;
+ bad: data[super::BAD_START..super::GOOD_END];
+ message:
+ "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+ }
-#[test]
-#[should_panic]
-fn test_str_slice_rangetoinclusive_max_panics() {
- &"hello"[..=usize::max_value()];
-}
+ in mod range_2 {
+ data: super::DATA;
+ bad: data[super::GOOD_START..super::BAD_END];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
-#[test]
-#[should_panic]
-fn test_str_slice_rangeinclusive_max_panics() {
- &"hello"[1..=usize::max_value()];
-}
+ in mod rangefrom {
+ data: super::DATA;
+ bad: data[super::BAD_START..];
+ message:
+ "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+ }
-#[test]
-#[should_panic]
-fn test_str_slicemut_rangetoinclusive_max_panics() {
- let mut s = "hello".to_owned();
- let s: &mut str = &mut s;
- &mut s[..=usize::max_value()];
-}
+ in mod rangeto {
+ data: super::DATA;
+ bad: data[..super::BAD_END];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
-#[test]
-#[should_panic]
-fn test_str_slicemut_rangeinclusive_max_panics() {
- let mut s = "hello".to_owned();
- let s: &mut str = &mut s;
- &mut s[1..=usize::max_value()];
-}
+ in mod rangeinclusive_1 {
+ data: super::DATA;
+ bad: data[super::BAD_START..=super::GOOD_END_INCL];
+ message:
+ "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of";
+ }
-#[test]
-fn test_str_get_maxinclusive() {
- let mut s = "hello".to_owned();
- {
- let s: &str = &s;
- assert_eq!(s.get(..=usize::max_value()), None);
- assert_eq!(s.get(1..=usize::max_value()), None);
+ in mod rangeinclusive_2 {
+ data: super::DATA;
+ bad: data[super::GOOD_START..=super::BAD_END_INCL];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
+
+ in mod rangetoinclusive {
+ data: super::DATA;
+ bad: data[..=super::BAD_END_INCL];
+ message:
+ "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of";
+ }
+ }
}
- {
- let s: &mut str = &mut s;
- assert_eq!(s.get(..=usize::max_value()), None);
- assert_eq!(s.get(1..=usize::max_value()), None);
+
+ const LOREM_PARAGRAPH: &'static str = "\
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \
+ sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \
+ quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \
+ nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \
+ tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \
+ gravida nec quam.";
+
+ // check the panic includes the prefix of the sliced string
+ #[test]
+ #[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
+ fn test_slice_fail_truncated_1() {
+ &LOREM_PARAGRAPH[..1024];
+ }
+ // check the truncation in the panic message
+ #[test]
+ #[should_panic(expected="luctus, im`[...]")]
+ fn test_slice_fail_truncated_2() {
+ &LOREM_PARAGRAPH[..1024];
}
}
}
}
}
-const LOREM_PARAGRAPH: &'static str = "\
-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
-ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
-eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \
-sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \
-tempus vel, gravida nec quam.";
-
-// check the panic includes the prefix of the sliced string
-#[test]
-#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
-fn test_slice_fail_truncated_1() {
- &LOREM_PARAGRAPH[..1024];
-}
-// check the truncation in the panic message
-#[test]
-#[should_panic(expected="luctus, im`[...]")]
-fn test_slice_fail_truncated_2() {
- &LOREM_PARAGRAPH[..1024];
-}
-
-#[test]
-#[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")]
-fn test_slice_fail_boundary_1() {
- &"abcαβγ"[4..];
-}
-
-#[test]
-#[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")]
-fn test_slice_fail_boundary_2() {
- &"abcαβγ"[2..6];
-}
-
-#[test]
-fn test_slice_from() {
- assert_eq!(&"abcd"[0..], "abcd");
- assert_eq!(&"abcd"[2..], "cd");
- assert_eq!(&"abcd"[4..], "");
-}
-#[test]
-fn test_slice_to() {
- assert_eq!(&"abcd"[..0], "");
- assert_eq!(&"abcd"[..2], "ab");
- assert_eq!(&"abcd"[..4], "abcd");
-}
#[test]
fn test_trim_left_matches() {
// memmove back untouched tail, update to new length
let start = source_vec.len();
let tail = self.tail_start;
- let src = source_vec.as_ptr().offset(tail as isize);
- let dst = source_vec.as_mut_ptr().offset(start as isize);
- ptr::copy(src, dst, self.tail_len);
+ if tail != start {
+ let src = source_vec.as_ptr().offset(tail as isize);
+ let dst = source_vec.as_mut_ptr().offset(start as isize);
+ ptr::copy(src, dst, self.tail_len);
+ }
source_vec.set_len(start + self.tail_len);
}
}
-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.
///
//! This module provides constants which are specific to the implementation
//! of the `f32` floating point data type.
//!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
//! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]
//! This module provides constants which are specific to the implementation
//! of the `f64` floating point data type.
//!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
//! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]
pub fn end(&self) -> &Idx {
&self.end
}
+
+ /// Destructures the RangeInclusive into (lower bound, upper (inclusive) bound).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(inclusive_range_methods)]
+ ///
+ /// assert_eq!((3..=5).into_inner(), (3, 5));
+ /// ```
+ #[unstable(feature = "inclusive_range_methods", issue = "49022")]
+ #[inline]
+ pub fn into_inner(self) -> (Idx, Idx) {
+ (self.start, self.end)
+ }
}
#[stable(feature = "inclusive_range", since = "1.26.0")]
// 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
///
panic!("slice index starts at {} but ends at {}", index, end);
}
+#[inline(never)]
+#[cold]
+fn slice_index_overflow_fail() -> ! {
+ panic!("attempted to index slice up to maximum usize");
+}
+
/// A helper trait used for indexing operations.
#[unstable(feature = "slice_get_slice", issue = "35729")]
#[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"]
#[inline]
fn index(self, slice: &[T]) -> &[T] {
- assert!(self.end != usize::max_value(),
- "attempted to index slice up to maximum usize");
+ if self.end == usize::max_value() { slice_index_overflow_fail(); }
(self.start..self.end + 1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- assert!(self.end != usize::max_value(),
- "attempted to index slice up to maximum usize");
+ if self.end == usize::max_value() { slice_index_overflow_fail(); }
(self.start..self.end + 1).index_mut(slice)
}
}
}
}
+ #[inline(never)]
+ #[cold]
+ fn str_index_overflow_fail() -> ! {
+ panic!("attempted to index str up to maximum usize");
+ }
+
#[stable(feature = "str_checked_slicing", since = "1.20.0")]
impl SliceIndex<str> for ops::RangeFull {
type Output = str;
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
- if let Some(end) = self.end.checked_add(1) {
- (self.start..end).get(slice)
- } else {
- None
- }
+ if self.end == usize::max_value() { None }
+ else { (self.start..self.end+1).get(slice) }
}
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
- if let Some(end) = self.end.checked_add(1) {
- (self.start..end).get_mut(slice)
- } else {
- None
- }
+ if self.end == usize::max_value() { None }
+ else { (self.start..self.end+1).get_mut(slice) }
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
- assert!(self.end != usize::max_value(),
- "attempted to index str up to maximum usize");
+ if self.end == usize::max_value() { str_index_overflow_fail(); }
(self.start..self.end+1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
- assert!(self.end != usize::max_value(),
- "attempted to index str up to maximum usize");
+ if self.end == usize::max_value() { str_index_overflow_fail(); }
(self.start..self.end+1).index_mut(slice)
}
}
type Output = str;
#[inline]
fn get(self, slice: &str) -> Option<&Self::Output> {
- if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
- Some(unsafe { self.get_unchecked(slice) })
- } else {
- None
- }
+ if self.end == usize::max_value() { None }
+ else { (..self.end+1).get(slice) }
}
#[inline]
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
- if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
- Some(unsafe { self.get_unchecked_mut(slice) })
- } else {
- None
- }
+ if self.end == usize::max_value() { None }
+ else { (..self.end+1).get_mut(slice) }
}
#[inline]
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
- let ptr = slice.as_ptr();
- super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1))
+ (..self.end+1).get_unchecked(slice)
}
#[inline]
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
- let ptr = slice.as_ptr();
- super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
+ (..self.end+1).get_unchecked_mut(slice)
}
#[inline]
fn index(self, slice: &str) -> &Self::Output {
- assert!(self.end != usize::max_value(),
- "attempted to index str up to maximum usize");
+ if self.end == usize::max_value() { str_index_overflow_fail(); }
(..self.end+1).index(slice)
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
- assert!(self.end != usize::max_value(),
- "attempted to index str up to maximum usize");
+ if self.end == usize::max_value() { str_index_overflow_fail(); }
(..self.end+1).index_mut(slice)
}
}
assert_eq!(res, [14, 18, 22, 26]);
}
-#[test]
-fn get_range() {
- let v: &[i32] = &[0, 1, 2, 3, 4, 5];
- assert_eq!(v.get(..), Some(&[0, 1, 2, 3, 4, 5][..]));
- assert_eq!(v.get(..2), Some(&[0, 1][..]));
- assert_eq!(v.get(2..), Some(&[2, 3, 4, 5][..]));
- assert_eq!(v.get(1..4), Some(&[1, 2, 3][..]));
- assert_eq!(v.get(7..), None);
- assert_eq!(v.get(7..10), None);
-}
+// The current implementation of SliceIndex fails to handle methods
+// orthogonally from range types; therefore, it is worth testing
+// all of the indexing operations on each input.
+mod slice_index {
+ // This checks all six indexing methods, given an input range that
+ // should succeed. (it is NOT suitable for testing invalid inputs)
+ macro_rules! assert_range_eq {
+ ($arr:expr, $range:expr, $expected:expr)
+ => {
+ let mut arr = $arr;
+ let mut expected = $expected;
+ {
+ let s: &[_] = &arr;
+ let expected: &[_] = &expected;
+
+ assert_eq!(&s[$range], expected, "(in assertion for: index)");
+ assert_eq!(s.get($range), Some(expected), "(in assertion for: get)");
+ unsafe {
+ assert_eq!(
+ s.get_unchecked($range), expected,
+ "(in assertion for: get_unchecked)",
+ );
+ }
+ }
+ {
+ let s: &mut [_] = &mut arr;
+ let expected: &mut [_] = &mut expected;
+
+ assert_eq!(
+ &mut s[$range], expected,
+ "(in assertion for: index_mut)",
+ );
+ assert_eq!(
+ s.get_mut($range), Some(&mut expected[..]),
+ "(in assertion for: get_mut)",
+ );
+ unsafe {
+ assert_eq!(
+ s.get_unchecked_mut($range), expected,
+ "(in assertion for: get_unchecked_mut)",
+ );
+ }
+ }
+ }
+ }
-#[test]
-fn get_mut_range() {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
- assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..]));
- assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..]));
- assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..]));
- assert_eq!(v.get_mut(1..4), Some(&mut [1, 2, 3][..]));
- assert_eq!(v.get_mut(7..), None);
- assert_eq!(v.get_mut(7..10), None);
-}
+ // Make sure the macro can actually detect bugs,
+ // because if it can't, then what are we even doing here?
+ //
+ // (Be aware this only demonstrates the ability to detect bugs
+ // in the FIRST method that panics, as the macro is not designed
+ // to be used in `should_panic`)
+ #[test]
+ #[should_panic(expected = "out of range")]
+ fn assert_range_eq_can_fail_by_panic() {
+ assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]);
+ }
-#[test]
-fn get_unchecked_range() {
- unsafe {
- let v: &[i32] = &[0, 1, 2, 3, 4, 5];
- assert_eq!(v.get_unchecked(..), &[0, 1, 2, 3, 4, 5][..]);
- assert_eq!(v.get_unchecked(..2), &[0, 1][..]);
- assert_eq!(v.get_unchecked(2..), &[2, 3, 4, 5][..]);
- assert_eq!(v.get_unchecked(1..4), &[1, 2, 3][..]);
+ // (Be aware this only demonstrates the ability to detect bugs
+ // in the FIRST method it calls, as the macro is not designed
+ // to be used in `should_panic`)
+ #[test]
+ #[should_panic(expected = "==")]
+ fn assert_range_eq_can_fail_by_inequality() {
+ assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]);
}
-}
-#[test]
-fn get_unchecked_mut_range() {
- unsafe {
- let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5];
- assert_eq!(v.get_unchecked_mut(..), &mut [0, 1, 2, 3, 4, 5][..]);
- assert_eq!(v.get_unchecked_mut(..2), &mut [0, 1][..]);
- assert_eq!(v.get_unchecked_mut(2..), &mut[2, 3, 4, 5][..]);
- assert_eq!(v.get_unchecked_mut(1..4), &mut [1, 2, 3][..]);
+ // Test cases for bad index operations.
+ //
+ // This generates `should_panic` test cases for Index/IndexMut
+ // and `None` test cases for get/get_mut.
+ macro_rules! panic_cases {
+ ($(
+ // each test case needs a unique name to namespace the tests
+ in mod $case_name:ident {
+ data: $data:expr;
+
+ // optional:
+ //
+ // one or more similar inputs for which data[input] succeeds,
+ // and the corresponding output as an array. This helps validate
+ // "critical points" where an input range straddles the boundary
+ // between valid and invalid.
+ // (such as the input `len..len`, which is just barely valid)
+ $(
+ good: data[$good:expr] == $output:expr;
+ )*
+
+ bad: data[$bad:expr];
+ message: $expect_msg:expr;
+ }
+ )*) => {$(
+ mod $case_name {
+ #[test]
+ fn pass() {
+ let mut v = $data;
+
+ $( assert_range_eq!($data, $good, $output); )*
+
+ {
+ let v: &[_] = &v;
+ assert_eq!(v.get($bad), None, "(in None assertion for get)");
+ }
+
+ {
+ let v: &mut [_] = &mut v;
+ assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)");
+ }
+ }
+
+ #[test]
+ #[should_panic(expected = $expect_msg)]
+ fn index_fail() {
+ let v = $data;
+ let v: &[_] = &v;
+ let _v = &v[$bad];
+ }
+
+ #[test]
+ #[should_panic(expected = $expect_msg)]
+ fn index_mut_fail() {
+ let mut v = $data;
+ let v: &mut [_] = &mut v;
+ let _v = &mut v[$bad];
+ }
+ }
+ )*};
}
+
+ #[test]
+ fn simple() {
+ let v = [0, 1, 2, 3, 4, 5];
+
+ assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]);
+ assert_range_eq!(v, ..2, [0, 1]);
+ assert_range_eq!(v, ..=1, [0, 1]);
+ assert_range_eq!(v, 2.., [2, 3, 4, 5]);
+ assert_range_eq!(v, 1..4, [1, 2, 3]);
+ assert_range_eq!(v, 1..=3, [1, 2, 3]);
+ }
+
+ panic_cases! {
+ in mod rangefrom_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[6..] == [];
+ bad: data[7..];
+ message: "but ends at"; // perhaps not ideal
+ }
+
+ in mod rangeto_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[..6] == [0, 1, 2, 3, 4, 5];
+ bad: data[..7];
+ message: "out of range";
+ }
+
+ in mod rangetoinclusive_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[..=5] == [0, 1, 2, 3, 4, 5];
+ bad: data[..=6];
+ message: "out of range";
+ }
+
+ in mod range_len_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[6..6] == [];
+ bad: data[7..7];
+ message: "out of range";
+ }
+
+ in mod rangeinclusive_len_len {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[6..=5] == [];
+ bad: data[7..=6];
+ message: "out of range";
+ }
+ }
+
+ panic_cases! {
+ in mod range_neg_width {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[4..4] == [];
+ bad: data[4..3];
+ message: "but ends at";
+ }
+
+ in mod rangeinclusive_neg_width {
+ data: [0, 1, 2, 3, 4, 5];
+
+ good: data[4..=3] == [];
+ bad: data[4..=2];
+ message: "but ends at";
+ }
+ }
+
+ panic_cases! {
+ in mod rangeinclusive_overflow {
+ data: [0, 1];
+
+ // note: using 0 specifically ensures that the result of overflowing is 0..0,
+ // so that `get` doesn't simply return None for the wrong reason.
+ bad: data[0 ..= ::std::usize::MAX];
+ message: "maximum usize";
+ }
+
+ in mod rangetoinclusive_overflow {
+ data: [0, 1];
+
+ bad: data[..= ::std::usize::MAX];
+ message: "maximum usize";
+ }
+ } // panic_cases!
}
#[test]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// All `str` tests live in collectionstests::str
+// All `str` tests live in liballoc/tests
#[test]
fn secs() {
assert_eq!(Duration::new(0, 0).as_secs(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0);
+ assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1);
assert_eq!(Duration::from_secs(1).as_secs(), 1);
assert_eq!(Duration::from_millis(999).as_secs(), 0);
assert_eq!(Duration::from_millis(1001).as_secs(), 1);
+ assert_eq!(Duration::from_micros(999_999).as_secs(), 0);
+ assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0);
+ assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1);
+}
+
+#[test]
+fn millis() {
+ assert_eq!(Duration::new(0, 0).subsec_millis(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500);
+ assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50);
+ assert_eq!(Duration::from_secs(1).subsec_millis(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_millis(), 999);
+ assert_eq!(Duration::from_millis(1001).subsec_millis(), 1);
+ assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999);
+ assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999);
+ assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1);
+}
+
+#[test]
+fn micros() {
+ assert_eq!(Duration::new(0, 0).subsec_micros(), 0);
+ assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000);
+ assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000);
+ assert_eq!(Duration::from_secs(1).subsec_micros(), 0);
+ assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000);
+ assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000);
+ assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999);
+ assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999);
+ assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1);
}
#[test]
assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
- assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
- assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
+ assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000);
+ assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000);
+ assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000);
+ assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000);
+ assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999);
+ assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1);
}
#[test]
///
/// [`subsec_nanos`]: #method.subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn as_secs(&self) -> u64 { self.secs }
+ pub const fn as_secs(&self) -> u64 { self.secs }
/// Returns the fractional part of this `Duration`, in milliseconds.
///
/// assert_eq!(duration.subsec_millis(), 432);
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
+ pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI }
/// Returns the fractional part of this `Duration`, in microseconds.
///
/// assert_eq!(duration.subsec_micros(), 234_567);
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
+ pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO }
/// Returns the fractional part of this `Duration`, in nanoseconds.
///
/// assert_eq!(duration.subsec_nanos(), 10_000_000);
/// ```
#[stable(feature = "duration", since = "1.3.0")]
+ #[rustc_const_unstable(feature="duration_getters")]
#[inline]
- pub fn subsec_nanos(&self) -> u32 { self.nanos }
+ pub const fn subsec_nanos(&self) -> u32 { self.nanos }
/// Checked `Duration` addition. Computes `self + other`, returning [`None`]
/// if overflow occurred.
//! 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)
}
}
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),
}
}
}
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
[input] UsedCrateSource(CrateNum),
[input] PostorderCnums,
- // This query is not expected to have inputs -- as a result, it's
- // not a good candidate for "replay" because it's essentially a
- // pure function of its input (and hence the expectation is that
- // no caller would be green **apart** from just this
- // query). Making it anonymous avoids hashing the result, which
+ // These queries are not expected to have inputs -- as a result, they
+ // are not good candidates for "replay" because they are essentially
+ // pure functions of their input (and hence the expectation is that
+ // no caller would be green **apart** from just these
+ // queries). Making them anonymous avoids hashing the result, which
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
+ [anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },
[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
-use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock};
+use rustc_data_structures::small_vec::SmallVec;
+use rustc_data_structures::sync::{Lrc, Lock};
use std::env;
use std::hash::Hash;
use ty::{self, TyCtxt};
/// things available to us. If we find that they are not dirty, we
/// load the path to the file storing those work-products here into
/// this map. We can later look for and extract that data.
- previous_work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
-
- /// Work-products that we generate in this run.
- work_products: RwLock<FxHashMap<WorkProductId, WorkProduct>>,
+ previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
dep_node_debug: Lock<FxHashMap<DepNode, String>>,
impl DepGraph {
- pub fn new(prev_graph: PreviousDepGraph) -> DepGraph {
+ pub fn new(prev_graph: PreviousDepGraph,
+ prev_work_products: FxHashMap<WorkProductId, WorkProduct>) -> DepGraph {
// Pre-allocate the fingerprints array. We over-allocate a little so
// that we hopefully don't have to re-allocate during this compilation
// session.
(prev_graph_node_count * 115) / 100);
DepGraph {
data: Some(Lrc::new(DepGraphData {
- previous_work_products: RwLock::new(FxHashMap()),
- work_products: RwLock::new(FxHashMap()),
+ previous_work_products: prev_work_products,
dep_node_debug: Lock::new(FxHashMap()),
current: Lock::new(CurrentDepGraph::new()),
previous: prev_graph,
let mut edges = Vec::new();
for (index, edge_targets) in current_dep_graph.edges.iter_enumerated() {
let from = current_dep_graph.nodes[index];
- for &edge_target in edge_targets {
+ for &edge_target in edge_targets.iter() {
let to = current_dep_graph.nodes[edge_target];
edges.push((from, to));
}
self.with_task_impl(key, cx, arg, false, task,
|key| OpenTask::Regular(Lock::new(RegularOpenTask {
node: key,
- reads: Vec::new(),
+ reads: SmallVec::new(),
read_set: FxHashSet(),
})),
|data, key, task| data.borrow_mut().complete_task(key, task))
self.with_task_impl(key, cx, input, true, identity_fn,
|_| OpenTask::Ignore,
- |data, key, _| data.borrow_mut().alloc_node(key, Vec::new()))
+ |data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new()))
}
fn with_task_impl<'gcx, C, A, R>(
if let Some(ref data) = self.data {
let (result, open_task) = ty::tls::with_context(|icx| {
let task = OpenTask::Anon(Lock::new(AnonOpenTask {
- reads: Vec::new(),
+ reads: SmallVec::new(),
read_set: FxHashSet(),
}));
self.data.as_ref().unwrap().previous.node_to_index(dep_node)
}
- /// Indicates that a previous work product exists for `v`. This is
- /// invoked during initial start-up based on what nodes are clean
- /// (and what files exist in the incr. directory).
- pub fn insert_previous_work_product(&self, v: &WorkProductId, data: WorkProduct) {
- debug!("insert_previous_work_product({:?}, {:?})", v, data);
- self.data
- .as_ref()
- .unwrap()
- .previous_work_products
- .borrow_mut()
- .insert(v.clone(), data);
- }
-
- /// Indicates that we created the given work-product in this run
- /// for `v`. This record will be preserved and loaded in the next
- /// run.
- pub fn insert_work_product(&self, v: &WorkProductId, data: WorkProduct) {
- debug!("insert_work_product({:?}, {:?})", v, data);
- self.data
- .as_ref()
- .unwrap()
- .work_products
- .borrow_mut()
- .insert(v.clone(), data);
- }
-
/// Check whether a previous work product exists for `v` and, if
/// so, return the path that leads to it. Used to skip doing work.
pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> {
self.data
.as_ref()
.and_then(|data| {
- data.previous_work_products.borrow().get(v).cloned()
+ data.previous_work_products.get(v).cloned()
})
}
- /// Access the map of work-products created during this run. Only
- /// used during saving of the dep-graph.
- pub fn work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> {
- self.data.as_ref().unwrap().work_products.borrow()
- }
-
/// Access the map of work-products created during the cached run. Only
/// used during saving of the dep-graph.
- pub fn previous_work_products(&self) -> ReadGuard<FxHashMap<WorkProductId, WorkProduct>> {
- self.data.as_ref().unwrap().previous_work_products.borrow()
+ pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
+ &self.data.as_ref().unwrap().previous_work_products
}
#[inline(always)]
}
pub fn serialize(&self) -> SerializedDepGraph {
- let mut fingerprints = self.fingerprints.borrow_mut();
let current_dep_graph = self.data.as_ref().unwrap().current.borrow();
- // Make sure we don't run out of bounds below.
- if current_dep_graph.nodes.len() > fingerprints.len() {
- fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO);
- }
-
- let fingerprints = fingerprints.clone().convert_index_type();
+ let fingerprints = self.fingerprints.borrow().clone().convert_index_type();
let nodes = current_dep_graph.nodes.clone().convert_index_type();
let total_edge_count: usize = current_dep_graph.edges.iter()
debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none());
- let mut current_deps = Vec::new();
+ let mut current_deps = SmallVec::new();
for &dep_dep_node_index in prev_deps {
let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index);
pub(super) struct CurrentDepGraph {
nodes: IndexVec<DepNodeIndex, DepNode>,
- edges: IndexVec<DepNodeIndex, Vec<DepNodeIndex>>,
+ edges: IndexVec<DepNodeIndex, SmallVec<[DepNodeIndex; 8]>>,
node_to_node_index: FxHashMap<DepNode, DepNodeIndex>,
forbidden_edge: Option<EdgeFilter>,
} = task {
debug_assert_eq!(node, key);
let krate_idx = self.node_to_node_index[&DepNode::new_no_params(DepKind::Krate)];
- self.alloc_node(node, vec![krate_idx])
+ self.alloc_node(node, SmallVec::one(krate_idx))
} else {
bug!("complete_eval_always_task() - Expected eval always task to be popped");
}
fn alloc_node(&mut self,
dep_node: DepNode,
- edges: Vec<DepNodeIndex>)
+ edges: SmallVec<[DepNodeIndex; 8]>)
-> DepNodeIndex {
debug_assert_eq!(self.edges.len(), self.nodes.len());
debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len());
pub struct RegularOpenTask {
node: DepNode,
- reads: Vec<DepNodeIndex>,
+ reads: SmallVec<[DepNodeIndex; 8]>,
read_set: FxHashSet<DepNodeIndex>,
}
pub struct AnonOpenTask {
- reads: Vec<DepNodeIndex>,
+ reads: SmallVec<[DepNodeIndex; 8]>,
read_set: FxHashSet<DepNodeIndex>,
}
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(_) => {},
};
}
}
self.visitor.visit_impl_item(impl_item);
}
}
+
+/// A parallel variant of ItemLikeVisitor
+pub trait ParItemLikeVisitor<'hir> {
+ fn visit_item(&self, item: &'hir Item);
+ fn visit_trait_item(&self, trait_item: &'hir TraitItem);
+ fn visit_impl_item(&self, impl_item: &'hir ImplItem);
+}
+
+pub trait IntoVisitor<'hir> {
+ type Visitor: Visitor<'hir>;
+ fn into_visitor(&self) -> Self::Visitor;
+}
+
+pub struct ParDeepVisitor<V>(pub V);
+
+impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor<V>
+ where V: IntoVisitor<'hir>
+{
+ fn visit_item(&self, item: &'hir Item) {
+ self.0.into_visitor().visit_item(item);
+ }
+
+ fn visit_trait_item(&self, trait_item: &'hir TraitItem) {
+ self.0.into_visitor().visit_trait_item(trait_item);
+ }
+
+ fn visit_impl_item(&self, impl_item: &'hir ImplItem) {
+ self.0.into_visitor().visit_impl_item(impl_item);
+ }
+}
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
});
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),
),
use ty::maps::Providers;
use rustc_data_structures::indexed_vec;
+use rustc_data_structures::sync::{ParallelIterator, par_iter, Send, Sync, scope};
use serialize::{self, Encoder, Encodable, Decoder, Decodable};
use std::collections::BTreeMap;
}
}
+ /// A parallel version of visit_all_item_likes
+ pub fn par_visit_all_item_likes<'hir, V>(&'hir self, visitor: &V)
+ where V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send
+ {
+ scope(|s| {
+ s.spawn(|_| {
+ par_iter(&self.items).for_each(|(_, item)| {
+ visitor.visit_item(item);
+ });
+ });
+
+ s.spawn(|_| {
+ par_iter(&self.trait_items).for_each(|(_, trait_item)| {
+ visitor.visit_trait_item(trait_item);
+ });
+ });
+
+ s.spawn(|_| {
+ par_iter(&self.impl_items).for_each(|(_, impl_item)| {
+ visitor.visit_impl_item(impl_item);
+ });
+ });
+ });
+ }
+
pub fn body(&self, id: BodyId) -> &Body {
&self.bodies[&id]
}
}
}
-// 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![];
}
impl ::std::fmt::Display for Fingerprint {
- fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
+ fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(formatter, "{:x}-{:x}", self.0, self.1)
}
}
impl_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 => {}
}
}
+impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::ConstValue<'gcx> {
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use mir::interpret::ConstValue::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+
+ match *self {
+ ByVal(val) => {
+ val.hash_stable(hcx, hasher);
+ }
+ ByValPair(a, b) => {
+ a.hash_stable(hcx, hasher);
+ b.hash_stable(hcx, hasher);
+ }
+ ByRef(alloc) => {
+ alloc.hash_stable(hcx, hasher);
+ }
+ }
+ }
+}
+
impl_stable_hash_for!(enum mir::interpret::Value {
ByVal(v),
ByValPair(a, b),
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)]
declare_lint! {
pub SINGLE_USE_LIFETIME,
Allow,
- "detects single use lifetimes"
+ "detects lifetime parameters that are only used once"
+}
+
+declare_lint! {
+ pub UNUSED_LIFETIME,
+ Allow,
+ "detects lifetime parameters that are never used"
}
declare_lint! {
UNUSED_UNSAFE,
UNUSED_MUT,
SINGLE_USE_LIFETIME,
+ UNUSED_LIFETIME,
TYVAR_BEHIND_RAW_POINTER,
ELIDED_LIFETIME_IN_PATH,
BARE_TRAIT_OBJECT,
use hir::def_id::DefId;
use ty::{self, TyCtxt, layout};
use ty::subst::Substs;
-use mir::interpret::{Value, PrimVal};
+use mir::interpret::ConstValue;
use errors::DiagnosticBuilder;
use graphviz::IntoCow;
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
pub enum ConstVal<'tcx> {
Unevaluated(DefId, &'tcx Substs<'tcx>),
- Value(Value),
-}
-
-impl<'tcx> ConstVal<'tcx> {
- pub fn to_raw_bits(&self) -> Option<u128> {
- match *self {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
- Some(b)
- },
- _ => None,
- }
- }
- pub fn unwrap_u64(&self) -> u64 {
- match self.to_raw_bits() {
- Some(val) => {
- assert_eq!(val as u64 as u128, val);
- val as u64
- },
- None => bug!("expected constant u64, got {:#?}", self),
- }
- }
+ Value(ConstValue<'tcx>),
}
#[derive(Clone, Debug)]
use syntax::symbol::Symbol;
use syntax_pos::Span;
use rustc_target::spec::Target;
-use rustc_data_structures::sync::{MetadataRef, Lrc};
+use rustc_data_structures::sync::{self, MetadataRef, Lrc};
pub use self::NativeLibraryKind::*;
fn metadata_encoding_version(&self) -> &[u8];
}
+pub type CrateStoreDyn = CrateStore + sync::Sync;
+
// FIXME: find a better place for this?
pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
let mut err_count = 0;
}
}
- 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,
},
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,
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
let promotable = match expr_ty.sty {
- ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
+ ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
_ => promotable,
};
//! used between functions, and they operate in a purely top-down
//! way. Therefore we break lifetime name resolution into a separate pass.
-use hir::map::Map;
use hir::def::Def;
use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
+use hir::map::Map;
use hir::ItemLocalId;
use hir::LifetimeName;
-use ty::{self, TyCtxt};
+use ty::{self, TyCtxt, GenericParamDefKind};
+use errors::DiagnosticBuilder;
+use rustc::lint;
+use rustc_data_structures::sync::Lrc;
+use session::Session;
use std::cell::Cell;
use std::mem::replace;
-use rustc_data_structures::sync::Lrc;
+use std::slice;
use syntax::ast;
use syntax::attr;
use syntax::ptr::P;
use syntax_pos::Span;
-use errors::DiagnosticBuilder;
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet};
-use session::Session;
-use std::slice;
-use rustc::lint;
-use hir::{self, GenericParamsExt};
use hir::intravisit::{self, NestedVisitorMap, Visitor};
+use hir::{self, GenericParamsExt};
/// The origin of a named lifetime definition.
///
tcx: TyCtxt<'a, 'tcx, 'tcx>,
map: &'a mut NamedRegionMap,
scope: ScopeRef<'a>,
- // Deep breath. Our representation for poly trait refs contains a single
- // binder and thus we only allow a single level of quantification. However,
- // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
- // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
- // correct when representing these constraints, we should only introduce one
- // scope. However, we want to support both locations for the quantifier and
- // during lifetime resolution we want precise information (so we can't
- // desugar in an earlier phase).
-
- // SO, if we encounter a quantifier at the outer scope, we set
- // trait_ref_hack to true (and introduce a scope), and then if we encounter
- // a quantifier at the inner scope, we error. If trait_ref_hack is false,
- // then we introduce the scope at the inner quantifier.
-
- // I'm sorry.
+
+ /// Deep breath. Our representation for poly trait refs contains a single
+ /// binder and thus we only allow a single level of quantification. However,
+ /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>`
+ /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices
+ /// correct when representing these constraints, we should only introduce one
+ /// scope. However, we want to support both locations for the quantifier and
+ /// during lifetime resolution we want precise information (so we can't
+ /// desugar in an earlier phase).
+ ///
+ /// SO, if we encounter a quantifier at the outer scope, we set
+ /// trait_ref_hack to true (and introduce a scope), and then if we encounter
+ /// a quantifier at the inner scope, we error. If trait_ref_hack is false,
+ /// then we introduce the scope at the inner quantifier.
+ ///
+ /// I'm sorry.
trait_ref_hack: bool,
- // Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
+ /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
is_in_fn_syntax: bool,
- // List of labels in the function/method currently under analysis.
+ /// List of labels in the function/method currently under analysis.
labels_in_fn: Vec<(ast::Name, Span)>,
- // Cache for cross-crate per-definition object lifetime defaults.
+ /// Cache for cross-crate per-definition object lifetime defaults.
xcrate_object_lifetime_defaults: DefIdMap<Vec<ObjectLifetimeDefault>>,
- lifetime_uses: DefIdMap<LifetimeUseSet<'tcx>>,
+ lifetime_uses: &'a mut DefIdMap<LifetimeUseSet<'tcx>>,
}
#[derive(Debug)]
/// we should use for an early-bound region?
next_early_index: u32,
+ /// Flag is set to true if, in this binder, `'_` would be
+ /// equivalent to a "single-use region". This is true on
+ /// impls, but not other kinds of items.
+ track_lifetime_uses: bool,
+
/// Whether or not this binder would serve as the parent
/// binder for abstract types introduced within. For example:
///
is_in_fn_syntax: false,
labels_in_fn: vec![],
xcrate_object_lifetime_defaults: DefIdMap(),
- lifetime_uses: DefIdMap(),
+ lifetime_uses: &mut DefIdMap(),
};
for (_, item) in &krate.items {
visitor.visit_item(item);
| hir::ItemTrait(_, _, ref generics, ..)
| hir::ItemTraitAlias(ref generics, ..)
| hir::ItemImpl(_, _, _, ref generics, ..) => {
+ // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name".
+ // This is not true for other kinds of items.x
+ let track_lifetime_uses = match item.node {
+ hir::ItemImpl(..) => true,
+ _ => false,
+ };
// These kinds of items have only early bound lifetime parameters.
let mut index = if let hir::ItemTrait(..) = item.node {
1 // Self comes before lifetimes
lifetimes,
next_early_index,
abstract_type_parent: true,
+ track_lifetime_uses,
s: ROOT_SCOPE,
};
self.with(scope, |old_scope, this| {
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- debug!("visit_ty: ty={:?}", ty);
+ debug!("visit_ty: id={:?} ty={:?}", ty.id, ty);
match ty.node {
hir::TyBareFn(ref c) => {
let next_early_index = self.next_early_index();
.collect(),
s: self.scope,
next_early_index,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
self.with(scope, |old_scope, this| {
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);
lifetimes,
next_early_index,
s: this.scope,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
this.with(scope, |_old_scope, this| {
lifetimes,
next_early_index,
s: self.scope,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
self.with(scope, |_old_scope, this| {
lifetimes,
next_early_index,
s: self.scope,
+ track_lifetime_uses: true,
abstract_type_parent: true,
};
self.with(scope, |_old_scope, this| {
lifetimes,
next_early_index,
s: self.scope,
+ track_lifetime_uses: true,
abstract_type_parent: true,
};
self.with(scope, |_old_scope, this| {
.collect(),
s: self.scope,
next_early_index,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
let result = self.with(scope, |old_scope, this| {
.collect(),
s: self.scope,
next_early_index,
+ track_lifetime_uses: true,
abstract_type_parent: false,
};
self.with(scope, |old_scope, this| {
}
Scope::Binder {
- ref lifetimes,
- s,
- next_early_index: _,
- abstract_type_parent: _,
+ ref lifetimes, s, ..
} => {
// FIXME (#24278): non-hygienic comparison
if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) {
F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>),
{
let LifetimeContext {
- tcx, ref mut map, ..
- } = *self;
+ tcx,
+ map,
+ lifetime_uses,
+ ..
+ } = self;
let labels_in_fn = replace(&mut self.labels_in_fn, vec![]);
let xcrate_object_lifetime_defaults =
replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap());
let mut this = LifetimeContext {
- tcx,
- map: *map,
+ tcx: *tcx,
+ map: map,
scope: &wrap_scope,
trait_ref_hack: self.trait_ref_hack,
is_in_fn_syntax: self.is_in_fn_syntax,
labels_in_fn,
xcrate_object_lifetime_defaults,
- lifetime_uses: DefIdMap(),
+ lifetime_uses: lifetime_uses,
};
debug!("entering scope {:?}", this.scope);
f(self.scope, &mut this);
+ this.check_uses_for_lifetimes_defined_by_scope();
debug!("exiting scope {:?}", this.scope);
self.labels_in_fn = this.labels_in_fn;
self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults;
+ }
+
+ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
+ let defined_by = match self.scope {
+ Scope::Binder { lifetimes, .. } => lifetimes,
+ _ => {
+ debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope");
+ return;
+ }
+ };
- for (def_id, lifetimeuseset) in &this.lifetime_uses {
+ let mut def_ids: Vec<_> = defined_by.values()
+ .flat_map(|region| match region {
+ Region::EarlyBound(_, def_id, _)
+ | Region::LateBound(_, def_id, _)
+ | Region::Free(_, def_id) => Some(*def_id),
+
+ Region::LateBoundAnon(..) | Region::Static => None,
+ })
+ .collect();
+
+ // ensure that we issue lints in a repeatable order
+ def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id));
+
+ for def_id in def_ids {
+ debug!(
+ "check_uses_for_lifetimes_defined_by_scope: def_id = {:?}",
+ def_id,
+ );
+
+ let lifetimeuseset = self.lifetime_uses.remove(&def_id);
+ debug!(
+ "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}",
+ lifetimeuseset
+ );
match lifetimeuseset {
- &LifetimeUseSet::One(_) => {
- let node_id = this.tcx.hir.as_local_node_id(*def_id).unwrap();
+ Some(LifetimeUseSet::One(_)) => {
+ let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
debug!("node id first={:?}", node_id);
- if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) {
+ if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
let span = hir_lifetime.span;
let id = hir_lifetime.id;
debug!(
node_id, span, hir_lifetime
);
- this.tcx
+ self.tcx
.struct_span_lint_node(
lint::builtin::SINGLE_USE_LIFETIME,
id,
span,
&format!(
- "lifetime name `{}` only used once",
+ "lifetime parameter `{}` only used once",
hir_lifetime.name.name()
),
)
.emit();
}
}
- _ => {
+ Some(LifetimeUseSet::Many) => {
debug!("Not one use lifetime");
}
+ None => {
+ let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+ if let hir::map::NodeLifetime(hir_lifetime) = self.tcx.hir.get(node_id) {
+ let span = hir_lifetime.span;
+ let id = hir_lifetime.id;
+
+ self.tcx
+ .struct_span_lint_node(
+ lint::builtin::UNUSED_LIFETIME,
+ id,
+ span,
+ &format!(
+ "lifetime parameter `{}` never used",
+ hir_lifetime.name.name()
+ ),
+ )
+ .emit();
+ }
+ }
}
}
}
next_early_index,
s: self.scope,
abstract_type_parent: true,
+ track_lifetime_uses: false,
};
self.with(scope, move |old_scope, this| {
this.check_lifetime_params(old_scope, &generics.params);
}
Scope::Binder {
- ref lifetimes,
- s,
- next_early_index: _,
- abstract_type_parent: _,
+ ref lifetimes, s, ..
} => {
if let Some(&def) = lifetimes.get(&lifetime_ref.name) {
break Some(def.shifted(late_depth));
.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()
})
};
inputs: &'tcx [P<hir::Ty>],
output: Option<&'tcx P<hir::Ty>>,
) {
+ debug!("visit_fn_like_elision: enter");
let mut arg_elide = Elide::FreshLateAnon(Cell::new(0));
let arg_scope = Scope::Elision {
elide: arg_elide.clone(),
None => return,
};
+ debug!("visit_fn_like_elision: determine output");
+
// Figure out if there's a body we can get argument names from,
// and whether there's a `self` argument (treated specially).
let mut assoc_item_kind = None;
Elide::Error(arg_lifetimes)
};
+ debug!("visit_fn_like_elision: elide={:?}", elide);
+
let scope = Scope::Elision {
elide,
s: self.scope,
};
self.with(scope, |_, this| this.visit_ty(output));
+ debug!("visit_fn_like_elision: exit");
struct GatherLifetimes<'a> {
map: &'a NamedRegionMap,
);
err.emit();
}
- hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
- hir::LifetimeName::Name(_) => {}
+ hir::LifetimeName::Fresh(_)
+ | hir::LifetimeName::Implicit
+ | hir::LifetimeName::Name(_) => {}
}
}
))
.emit();
}
- hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
- hir::LifetimeName::Name(_) => {
+ hir::LifetimeName::Fresh(_)
+ | hir::LifetimeName::Implicit
+ | hir::LifetimeName::Name(_) => {
self.resolve_lifetime_ref(bound);
}
}
}
Scope::Binder {
- ref lifetimes,
- s,
- next_early_index: _,
- abstract_type_parent: _,
+ ref lifetimes, s, ..
} => {
if let Some(&def) = lifetimes.get(&lifetime.name) {
let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap();
}
}
+ /// Returns true if, in the current scope, replacing `'_` would be
+ /// equivalent to a single-use lifetime.
+ fn track_lifetime_uses(&self) -> bool {
+ let mut scope = self.scope;
+ loop {
+ match *scope {
+ Scope::Root => break false,
+
+ // Inside of items, it depends on the kind of item.
+ Scope::Binder {
+ track_lifetime_uses,
+ ..
+ } => break track_lifetime_uses,
+
+ // Inside a body, `'_` will use an inference variable,
+ // should be fine.
+ Scope::Body { .. } => break true,
+
+ // A lifetime only used in a fn argument could as well
+ // be replaced with `'_`, as that would generate a
+ // fresh name, too.
+ Scope::Elision {
+ elide: Elide::FreshLateAnon(_),
+ ..
+ } => break true,
+
+ // In the return type or other such place, `'_` is not
+ // going to make a fresh name, so we cannot
+ // necessarily replace a single-use lifetime with
+ // `'_`.
+ Scope::Elision {
+ elide: Elide::Exact(_),
+ ..
+ } => break false,
+ Scope::Elision {
+ elide: Elide::Error(_),
+ ..
+ } => break false,
+
+ Scope::ObjectLifetimeDefault { s, .. } => scope = s,
+ }
+ }
+ }
+
fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) {
if lifetime_ref.id == ast::DUMMY_NODE_ID {
span_bug!(
| Region::LateBound(_, def_id, _)
| Region::EarlyBound(_, def_id, _) => {
// A lifetime declared by the user.
- if !self.lifetime_uses.contains_key(&def_id) {
- self.lifetime_uses
- .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+ let def_local_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+ if def_local_id == lifetime_ref.id {
+ // This is weird. Because the HIR defines a
+ // lifetime *definition* as wrapping a Lifetime,
+ // we wind up invoking this method also for the
+ // definitions in some cases (notably
+ // higher-ranked types). This means that a
+ // lifetime with one use (e.g., `for<'a> fn(&'a
+ // u32)`) wind up being counted as two uses. To
+ // avoid that, we just ignore the lifetime that
+ // corresponds to the definition.
} else {
- self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+ let track_lifetime_uses = self.track_lifetime_uses();
+ debug!(
+ "insert_lifetime: track_lifetime_uses={}",
+ track_lifetime_uses
+ );
+ if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) {
+ debug!("insert_lifetime: first use of {:?}", def_id);
+ self.lifetime_uses
+ .insert(def_id, LifetimeUseSet::One(lifetime_ref));
+ } else {
+ debug!("insert_lifetime: many uses of {:?}", def_id);
+ self.lifetime_uses.insert(def_id, LifetimeUseSet::Many);
+ }
}
}
}
"unions with `Drop` implementations are unstable");
} else {
let param_env = self.tcx.param_env(def_id);
- if !param_env.can_type_implement_copy(self.tcx, ty, item.span).is_ok() {
+ if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() {
emit_feature_err(&self.tcx.sess.parse_sess,
"untagged_unions", item.span, GateIssue::Language,
"unions with non-`Copy` fields are unstable");
pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};
-pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
+pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue};
use std::collections::BTreeMap;
use std::fmt;
use ty::layout::{self, Align, HasDataLayout};
use middle::region;
use std::iter;
+use std::io;
use syntax::ast::Mutability;
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
+use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};
#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Lock {
}
}
-#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct Allocation {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer
}
impl Allocation {
- pub fn from_bytes(slice: &[u8]) -> Self {
+ pub fn from_bytes(slice: &[u8], align: Align) -> Self {
let mut undef_mask = UndefMask::new(0);
undef_mask.grow(slice.len() as u64, true);
Self {
bytes: slice.to_owned(),
relocations: BTreeMap::new(),
undef_mask,
- align: Align::from_bytes(1, 1).unwrap(),
+ align,
runtime_mutability: Mutability::Immutable,
}
}
+
+ pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
+ Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
+ }
+
+ pub fn undef(size: u64, align: Align) -> Self {
+ assert_eq!(size as usize as u64, size);
+ Allocation {
+ bytes: vec![0; size as usize],
+ relocations: BTreeMap::new(),
+ undef_mask: UndefMask::new(size),
+ align,
+ runtime_mutability: Mutability::Immutable,
+ }
+ }
+}
+
+impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
+
+////////////////////////////////////////////////////////////////////////////////
+// Methods to access integers in the target endianness
+////////////////////////////////////////////////////////////////////////////////
+
+pub fn write_target_uint(
+ endianness: layout::Endian,
+ mut target: &mut [u8],
+ data: u128,
+) -> Result<(), io::Error> {
+ let len = target.len();
+ match endianness {
+ layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
+ layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
+ }
+}
+
+pub fn write_target_int(
+ endianness: layout::Endian,
+ mut target: &mut [u8],
+ data: i128,
+) -> Result<(), io::Error> {
+ let len = target.len();
+ match endianness {
+ layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
+ layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
+ }
+}
+
+pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
+ match endianness {
+ layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
+ layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
+ }
}
////////////////////////////////////////////////////////////////////////////////
use ty::layout::{Align, HasDataLayout};
use ty;
-use super::{EvalResult, MemoryPointer, PointerArithmetic};
+use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};
+
+/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which
+/// matches Value's optimizations for easy conversions between these two types
+#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
+pub enum ConstValue<'tcx> {
+ // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
+ ByVal(PrimVal),
+ // Used only for types with layout::abi::ScalarPair
+ ByValPair(PrimVal, PrimVal),
+ // Used only for the remaining cases
+ ByRef(&'tcx Allocation),
+}
+
+impl<'tcx> ConstValue<'tcx> {
+ #[inline]
+ pub fn from_byval_value(val: Value) -> Self {
+ match val {
+ Value::ByRef(..) => bug!(),
+ Value::ByValPair(a, b) => ConstValue::ByValPair(a, b),
+ Value::ByVal(val) => ConstValue::ByVal(val),
+ }
+ }
+
+ #[inline]
+ pub fn to_byval_value(&self) -> Option<Value> {
+ match *self {
+ ConstValue::ByRef(..) => None,
+ ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)),
+ ConstValue::ByVal(val) => Some(Value::ByVal(val)),
+ }
+ }
+
+ #[inline]
+ pub fn from_primval(val: PrimVal) -> Self {
+ ConstValue::ByVal(val)
+ }
+
+ #[inline]
+ pub fn to_primval(&self) -> Option<PrimVal> {
+ match *self {
+ ConstValue::ByRef(..) => None,
+ ConstValue::ByValPair(..) => None,
+ ConstValue::ByVal(val) => Some(val),
+ }
+ }
+
+ #[inline]
+ pub fn to_bits(&self) -> Option<u128> {
+ match self.to_primval() {
+ Some(PrimVal::Bytes(val)) => Some(val),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_ptr(&self) -> Option<MemoryPointer> {
+ match self.to_primval() {
+ Some(PrimVal::Ptr(ptr)) => Some(ptr),
+ _ => None,
+ }
+ }
+}
/// A `Value` represents a single self-contained Rust value.
///
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html
use graphviz::IntoCow;
-use middle::const_val::ConstVal;
use middle::region;
use rustc_data_structures::sync::{Lrc};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
span,
ty,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty
- })
+ value: ty::Const::zero_sized(tcx, ty),
},
})
}
}
/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
-fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
- use middle::const_val::ConstVal::*;
+pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
+ use middle::const_val::ConstVal;
match const_val.val {
- Unevaluated(..) => write!(fmt, "{:?}", const_val),
- Value(val) => print_miri_value(val, const_val.ty, fmt),
+ ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
+ ConstVal::Value(val) => {
+ if let Some(value) = val.to_byval_value() {
+ print_miri_value(value, const_val.ty, fmt)
+ } else {
+ write!(fmt, "{:?}:{}", val, const_val.ty)
+ }
+ },
}
}
PlaceTy::Ty {
ty: match ty.sty {
ty::TyArray(inner, size) => {
- let size = size.val.unwrap_u64();
+ let size = size.unwrap_usize(tcx);
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}
Fat,
}
+#[derive(Clone, PartialEq, Hash)]
+pub enum CrossLangLto {
+ LinkerPlugin(PathBuf),
+ NoLink,
+ Disabled
+}
+
+impl CrossLangLto {
+ pub fn embed_bitcode(&self) -> bool {
+ match *self {
+ CrossLangLto::LinkerPlugin(_) |
+ CrossLangLto::NoLink => true,
+ CrossLangLto::Disabled => false,
+ }
+ }
+}
+
#[derive(Clone, Copy, PartialEq, Hash)]
pub enum DebugInfoLevel {
NoDebugInfo,
// Remap source path prefixes in all output (messages, object files, debug, etc)
remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
+
edition: Edition [TRACKED],
}
);
Some("`string` or `string=string`");
pub const parse_lto: Option<&'static str> =
Some("one of `thin`, `fat`, or omitted");
+ pub const parse_cross_lang_lto: Option<&'static str> =
+ Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \
+ or the path to the linker plugin");
}
#[allow(dead_code)]
mod $mod_set {
- use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
+ use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto,
+ CrossLangLto};
use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
use std::path::PathBuf;
true
}
+ fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool {
+ if v.is_some() {
+ let mut bool_arg = None;
+ if parse_opt_bool(&mut bool_arg, v) {
+ *slot = if bool_arg.unwrap() {
+ CrossLangLto::NoLink
+ } else {
+ CrossLangLto::Disabled
+ };
+ return true
+ }
+ }
+
+ *slot = match v {
+ None |
+ Some("no-link") => CrossLangLto::NoLink,
+ Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)),
+ };
+ true
+ }
}
) }
"make the current crate share its generic instantiations"),
chalk: bool = (false, parse_bool, [TRACKED],
"enable the experimental Chalk-based trait solving engine"),
- cross_lang_lto: bool = (false, parse_bool, [TRACKED],
+ cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED],
"generate build artifacts that are compatible with linker-based LTO."),
}
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes,
- Passes, Sanitizer};
+ Passes, Sanitizer, CrossLangLto};
use syntax::feature_gate::UnstableFeatures;
use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
use syntax::edition::Edition;
impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
impl_dep_tracking_hash_via_hash!(TargetTriple);
impl_dep_tracking_hash_via_hash!(Edition);
+ impl_dep_tracking_hash_via_hash!(CrossLangLto);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
use lint;
use middle::cstore;
use session::config::{build_configuration, build_session_options_and_crate_config};
- use session::config::Lto;
+ use session::config::{Lto, CrossLangLto};
use session::build_session;
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
opts = reference.clone();
opts.debugging_opts.relro_level = Some(RelroLevel::Full);
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
+ opts = reference.clone();
+ opts.debugging_opts.cross_lang_lto = CrossLangLto::NoLink;
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
}
#[test]
}
}
+ pub fn target_cpu(&self) -> &str {
+ match self.opts.cg.target_cpu {
+ Some(ref s) => &**s,
+ None => &*self.target.target.options.cpu
+ }
+ }
+
pub fn must_not_eliminate_frame_pointers(&self) -> bool {
if let Some(x) = self.opts.cg.force_frame_pointers {
x
ret
}
+ /// Returns the number of query threads that should be used for this
+ /// compilation
+ pub fn query_threads_from_opts(opts: &config::Options) -> usize {
+ opts.debugging_opts.query_threads.unwrap_or(1)
+ }
+
/// Returns the number of query threads that should be used for this
/// compilation
pub fn query_threads(&self) -> usize {
- self.opts.debugging_opts.query_threads.unwrap_or(1)
+ Self::query_threads_from_opts(&self.opts)
}
/// Returns the number of codegen units that should be used for this
});
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);
// we move over to lazy normalization *anyway*.
let fulfill_cx = FulfillmentContext::new_ignoring_regions();
- let predicates = match fully_normalize_with_fulfillcx(
+ let predicates = match fully_normalize(
&infcx,
fulfill_cx,
cause,
})
}
-pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- cause: ObligationCause<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- value: &T)
- -> Result<T, Vec<FulfillmentError<'tcx>>>
- where T : TypeFoldable<'tcx>
-{
- // FIXME (@jroesch) ISSUE 26721
- // I'm not sure if this is a bug or not, needs further investigation.
- // It appears that by reusing the fulfillment_cx here we incur more
- // obligations and later trip an assertion on regionck.rs line 337.
- //
- // The two possibilities I see is:
- // - normalization is not actually fully happening and we
- // have a bug else where
- // - we are adding a duplicate bound into the list causing
- // its size to change.
- //
- // I think we should probably land this refactor and then come
- // back to this is a follow-up patch.
- let fulfillcx = FulfillmentContext::new();
- fully_normalize_with_fulfillcx(infcx, fulfillcx, cause, param_env, value)
-}
-
-pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>(
+pub fn fully_normalize<'a, 'gcx, 'tcx, T>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
mut fulfill_cx: FulfillmentContext<'tcx>,
cause: ObligationCause<'tcx>,
}
debug!("fully_normalize: select_all_or_error start");
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => { }
- Err(e) => {
- debug!("fully_normalize: error={:?}", e);
- return Err(e);
- }
- }
+ fulfill_cx.select_all_or_error(infcx)?;
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
// 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
}
}
// that this always succeeds.
let impl1_trait_ref =
match traits::fully_normalize(&infcx,
+ FulfillmentContext::new(),
ObligationCause::dummy(),
penv,
&impl1_trait_ref) {
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 std::intrinsics;
use ty::{self, Ty, TyCtxt};
use ty::subst::Substs;
+use mir::interpret::Allocation;
/// The shorthand encoding uses an enum's variant index `usize`
/// and is offset by this value so it never matches a real variant.
Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
}
+#[inline]
+pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D)
+ -> Result<&'tcx Allocation, D::Error>
+ where D: TyDecoder<'a, 'tcx>,
+ 'tcx: 'a,
+{
+ Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+}
+
#[macro_export]
macro_rules! __impl_decoder_methods {
($($name:ident -> $ty:ty;)*) => {
decode_const(self)
}
}
+
+ impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
+ for $DecoderName<$($typaram),*> {
+ fn specialized_decode(
+ &mut self
+ ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> {
+ decode_allocation(self)
+ }
+ }
}
}
}
use ich::{StableHashingContext, NodeIdHashingMode};
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use infer::outlives::free_region_map::FreeRegionMap;
-use middle::const_val::ConstVal;
-use middle::cstore::{CrateStore, LinkMeta};
+use middle::cstore::{CrateStoreDyn, LinkMeta};
use middle::cstore::EncodedMetadata;
use middle::lang_items;
use middle::resolve_lifetime::{self, ObjectLifetimeDefault};
use middle::stability;
use mir::{self, Mir, interpret};
-use mir::interpret::{Value, PrimVal};
use ty::subst::{Kind, Substs, Subst};
use ty::ReprOptions;
use ty::Instance;
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;
}
}
- /// Intern a type. global_interners is Some only if this is
- /// a local interner and global_interners is its counterpart.
- fn intern_ty(&self, st: TypeVariants<'tcx>,
- global_interners: Option<&CtxtInterners<'gcx>>)
- -> Ty<'tcx> {
- let ty = {
- let mut interner = self.type_.borrow_mut();
+ /// Intern a type
+ fn intern_ty(
+ local: &CtxtInterners<'tcx>,
+ global: &CtxtInterners<'gcx>,
+ st: TypeVariants<'tcx>
+ ) -> Ty<'tcx> {
+ let flags = super::flags::FlagComputation::for_sty(&st);
+
+ // HACK(eddyb) Depend on flags being accurate to
+ // determine that all contents are in the global tcx.
+ // See comments on Lift for why we can't use that.
+ if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
+ let mut interner = local.type_.borrow_mut();
if let Some(&Interned(ty)) = interner.get(&st) {
return ty;
}
- let global_interner = global_interners.map(|interners| {
- (interners.type_.borrow_mut(), &interners.arena)
- });
- if let Some((ref type_, _)) = global_interner {
- if let Some(&Interned(ty)) = type_.get(&st) {
- return ty;
- }
- }
- let flags = super::flags::FlagComputation::for_sty(&st);
let ty_struct = TyS {
sty: st,
flags: flags.flags,
region_depth: flags.depth,
};
- // HACK(eddyb) Depend on flags being accurate to
- // determine that all contents are in the global tcx.
- // See comments on Lift for why we can't use that.
- if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
- if let Some((mut type_, arena)) = global_interner {
- let ty_struct: TyS<'gcx> = unsafe {
- mem::transmute(ty_struct)
- };
- let ty: Ty<'gcx> = arena.alloc(ty_struct);
- type_.insert(Interned(ty));
- return ty;
- }
- } else {
- // Make sure we don't end up with inference
- // types/regions in the global tcx.
- if global_interner.is_none() {
- drop(interner);
- bug!("Attempted to intern `{:?}` which contains \
- inference types/regions in the global type context",
- &ty_struct);
- }
+ // Make sure we don't end up with inference
+ // types/regions in the global interner
+ if local as *const _ as usize == global as *const _ as usize {
+ bug!("Attempted to intern `{:?}` which contains \
+ inference types/regions in the global type context",
+ &ty_struct);
}
// Don't be &mut TyS.
- let ty: Ty<'tcx> = self.arena.alloc(ty_struct);
+ let ty: Ty<'tcx> = local.arena.alloc(ty_struct);
interner.insert(Interned(ty));
ty
- };
+ } else {
+ let mut interner = global.type_.borrow_mut();
+ if let Some(&Interned(ty)) = interner.get(&st) {
+ return ty;
+ }
- debug!("Interned type: {:?} Pointer: {:?}",
- ty, ty as *const TyS);
- ty
- }
+ let ty_struct = TyS {
+ sty: st,
+ flags: flags.flags,
+ region_depth: flags.depth,
+ };
+
+ // This is safe because all the types the ty_struct can point to
+ // already is in the global arena
+ let ty_struct: TyS<'gcx> = unsafe {
+ mem::transmute(ty_struct)
+ };
+ // Don't be &mut TyS.
+ let ty: Ty<'gcx> = global.arena.alloc(ty_struct);
+ interner.insert(Interned(ty));
+ ty
+ }
+ }
}
pub struct CommonTypes<'tcx> {
impl<'tcx> CommonTypes<'tcx> {
fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
- let mk = |sty| interners.intern_ty(sty, None);
+ let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty);
let mk_region = |r| {
if let Some(r) = interners.region.borrow().get(&r) {
return r.0;
global_arenas: &'tcx GlobalArenas<'tcx>,
global_interners: CtxtInterners<'tcx>,
- cstore: &'tcx dyn CrateStore,
+ cstore: &'tcx CrateStoreDyn,
pub sess: &'tcx Session,
return alloc_id;
}
// create an allocation that just contains these bytes
- let alloc = interpret::Allocation::from_bytes(bytes);
+ let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes);
let alloc = self.intern_const_alloc(alloc);
// the next unique id
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
/// reference to the context, to allow formatting values that need it.
pub fn create_and_enter<F, R>(s: &'tcx Session,
- cstore: &'tcx dyn CrateStore,
+ cstore: &'tcx CrateStoreDyn,
local_providers: ty::maps::Providers<'tcx>,
extern_providers: ty::maps::Providers<'tcx>,
arenas: &'tcx AllArenas<'tcx>,
/// in librustc otherwise. It is used to when diagnostic messages are
/// emitted and stores them in the current query, if there is one.
fn track_diagnostic(diagnostic: &Diagnostic) {
- with_context(|context| {
- if let Some(ref query) = context.query {
- query.diagnostics.lock().push(diagnostic.clone());
+ with_context_opt(|icx| {
+ if let Some(icx) = icx {
+ if let Some(ref query) = icx.query {
+ query.diagnostics.lock().push(diagnostic.clone());
+ }
}
})
}
$keep_in_local_tcx:expr) -> $ty:ty) => {
impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> {
pub fn $method(self, v: $alloc) -> &$lt_tcx $ty {
- {
- let key = ($alloc_to_key)(&v);
- if let Some(i) = self.interners.$name.borrow().get(key) {
- return i.0;
- }
- if !self.is_global() {
- if let Some(i) = self.global_interners.$name.borrow().get(key) {
- return i.0;
- }
- }
- }
+ let key = ($alloc_to_key)(&v);
// HACK(eddyb) Depend on flags being accurate to
// determine that all contents are in the global tcx.
// See comments on Lift for why we can't use that.
- if !($keep_in_local_tcx)(&v) {
- if !self.is_global() {
- let v = unsafe {
- mem::transmute(v)
- };
- let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
- self.global_interners.$name.borrow_mut().insert(Interned(i));
- return i;
+ if ($keep_in_local_tcx)(&v) {
+ let mut interner = self.interners.$name.borrow_mut();
+ if let Some(&Interned(v)) = interner.get(key) {
+ return v;
}
- } else {
+
// Make sure we don't end up with inference
// types/regions in the global tcx.
if self.is_global() {
inference types/regions in the global type context",
v);
}
- }
- let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
- self.interners.$name.borrow_mut().insert(Interned(i));
- i
+ let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v));
+ interner.insert(Interned(i));
+ i
+ } else {
+ let mut interner = self.global_interners.$name.borrow_mut();
+ if let Some(&Interned(v)) = interner.get(key) {
+ return v;
+ }
+
+ // This transmutes $alloc<'tcx> to $alloc<'gcx>
+ let v = unsafe {
+ mem::transmute(v)
+ };
+ let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v));
+ interner.insert(Interned(i));
+ i
+ }
}
}
}
self.mk_fn_ptr(converted_sig)
}
- // Interns a type/name combination, stores the resulting box in cx.interners,
- // and returns the box as cast to an unsafe ptr (see comments for Ty above).
- pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
- let global_interners = if !self.is_global() {
- Some(&self.global_interners)
- } else {
- None
- };
- self.interners.intern_ty(st, global_interners)
+ pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> {
+ CtxtInterners::intern_ty(&self.interners, &self.global_interners, st)
}
pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
pub fn mk_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))
}
}
pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> {
- self.mk_ty(TyArray(ty, self.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))),
- ty: self.types.usize
- })))
+ self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n)))
}
pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> {
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::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)),
ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)),
ty::TyArray(_, n) => {
- match n.val.to_raw_bits() {
+ match n.assert_usize(tcx) {
Some(n) => format!("array of {} elements", n),
None => "array".to_string(),
}
}
&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)
}
}
}))
},
TyArray(ty, len) => {
- match len.val.to_raw_bits() {
+ match len.assert_usize(tcx) {
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(visited, tcx),
offsets.len(), ty);
}
- if field.abi == Abi::Uninhabited {
- return Ok(LayoutDetails::uninhabited(fields.len()));
- }
-
if field.is_unsized() {
sized = false;
}
}
}
+ if sized && fields.iter().any(|f| f.abi == Abi::Uninhabited) {
+ abi = Abi::Uninhabited;
+ }
+
Ok(LayoutDetails {
variants: Variants::Single { index: 0 },
fields: FieldPlacement::Arbitrary {
// The never type.
ty::TyNever => {
- tcx.intern_layout(LayoutDetails::uninhabited(0))
+ tcx.intern_layout(LayoutDetails {
+ variants: Variants::Single { index: 0 },
+ fields: FieldPlacement::Union(0),
+ abi: Abi::Uninhabited,
+ align: dl.i8_align,
+ size: Size::from_bytes(0)
+ })
}
// Potentially-fat pointers.
}
let element = self.layout_of(element)?;
- let count = count.val.unwrap_u64();
+ let count = count.unwrap_usize(tcx);
let size = element.size.checked_mul(count, dl)
.ok_or(LayoutError::SizeOverflow(ty))?;
}));
}
- let (inh_first, inh_second) = {
- let mut inh_variants = (0..variants.len()).filter(|&v| {
- variants[v].iter().all(|f| f.abi != Abi::Uninhabited)
+ // A variant is absent if it's uninhabited and only has ZST fields.
+ // Present uninhabited variants only require space for their fields,
+ // but *not* an encoding of the discriminant (e.g. a tag value).
+ // See issue #49298 for more details on the need to leave space
+ // for non-ZST uninhabited data (mostly partial initialization).
+ let absent = |fields: &[TyLayout]| {
+ let uninhabited = fields.iter().any(|f| f.abi == Abi::Uninhabited);
+ let is_zst = fields.iter().all(|f| f.is_zst());
+ uninhabited && is_zst
+ };
+ let (present_first, present_second) = {
+ let mut present_variants = (0..variants.len()).filter(|&v| {
+ !absent(&variants[v])
});
- (inh_variants.next(), inh_variants.next())
+ (present_variants.next(), present_variants.next())
};
- if inh_first.is_none() {
- // Uninhabited because it has no variants, or only uninhabited ones.
- return Ok(tcx.intern_layout(LayoutDetails::uninhabited(0)));
+ if present_first.is_none() {
+ // Uninhabited because it has no variants, or only absent ones.
+ return tcx.layout_raw(param_env.and(tcx.types.never));
}
let is_struct = !def.is_enum() ||
- // Only one variant is inhabited.
- (inh_second.is_none() &&
+ // Only one variant is present.
+ (present_second.is_none() &&
// Representation optimizations are allowed.
!def.repr.inhibit_enum_layout_opt());
if is_struct {
// Struct, or univariant enum equivalent to a struct.
// (Typechecking will reject discriminant-sizing attrs.)
- let v = inh_first.unwrap();
+ let v = present_first.unwrap();
let kind = if def.is_enum() || variants[v].len() == 0 {
StructKind::AlwaysSized
} else {
// Find one non-ZST variant.
'variants: for (v, fields) in variants.iter().enumerate() {
- if fields.iter().any(|f| f.abi == Abi::Uninhabited) {
+ if absent(fields) {
continue 'variants;
}
for f in fields {
let offset = st[i].fields.offset(field_index) + offset;
let size = st[i].size;
- let abi = match st[i].abi {
+ let mut abi = match st[i].abi {
Abi::Scalar(_) => Abi::Scalar(niche.clone()),
Abi::ScalarPair(ref first, ref second) => {
// We need to use scalar_unit to reset the
_ => Abi::Aggregate { sized: true },
};
+ if st.iter().all(|v| v.abi == Abi::Uninhabited) {
+ abi = Abi::Uninhabited;
+ }
+
return Ok(tcx.intern_layout(LayoutDetails {
variants: Variants::NicheFilling {
dataful_variant: i,
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);
let old_ity_size = min_ity.size();
let new_ity_size = ity.size();
for variant in &mut layout_variants {
- if variant.abi == Abi::Uninhabited {
- continue;
- }
match variant.fields {
FieldPlacement::Arbitrary { ref mut offsets, .. } => {
for i in offsets {
}
}
}
+
+ if layout_variants.iter().all(|v| v.abi == Abi::Uninhabited) {
+ abi = Abi::Uninhabited;
+ }
+
tcx.intern_layout(LayoutDetails {
variants: Variants::Tagged {
tag,
ty::TyAdt(def, _) => def.variants[variant_index].fields.len(),
_ => bug!()
};
- let mut details = LayoutDetails::uninhabited(fields);
- details.variants = Variants::Single { index: variant_index };
- cx.tcx().intern_layout(details)
+ let tcx = cx.tcx();
+ tcx.intern_layout(LayoutDetails {
+ variants: Variants::Single { index: variant_index },
+ fields: FieldPlacement::Union(fields),
+ abi: Abi::Uninhabited,
+ align: tcx.data_layout.i8_align,
+ size: Size::from_bytes(0)
+ })
}
Variants::NicheFilling { ref variants, .. } |
use dep_graph::SerializedDepNodeIndex;
use dep_graph::DepNode;
use hir::def_id::{CrateNum, DefId, DefIndex};
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, ConstValue};
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::Substs;
}
}
+impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> {
+ fn describe(_tcx: TyCtxt, (val, ty): (ConstValue<'tcx>, Ty<'tcx>)) -> String {
+ format!("converting value `{:?}` ({}) to an allocation", val, ty)
+ }
+}
+
impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> {
fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
format!("erasing regions from `{:?}`", ty)
impl<'tcx> 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")
}
}
}
}
+impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) {
+ fn map_crate(&self) -> CrateNum {
+ LOCAL_CRATE
+ }
+ fn default_span(&self, _: TyCtxt) -> Span {
+ DUMMY_SP
+ }
+}
+
impl<'tcx> Key for Ty<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
use middle::const_val::EvalResult;
use mir::mono::{CodegenUnit, Stats};
use mir;
-use mir::interpret::{GlobalId};
+use mir::interpret::{GlobalId, Allocation, ConstValue};
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::{self, Vtable};
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> EvalResult<'tcx>,
+ /// Converts a constant value to an constant allocation
+ [] fn const_value_to_allocation: const_value_to_allocation(
+ (ConstValue<'tcx>, Ty<'tcx>)
+ ) -> &'tcx Allocation,
+
[] fn check_match: CheckMatch(DefId)
-> Result<(), ErrorReported>,
DepConstructor::EraseRegionsTy { ty }
}
+fn const_value_to_allocation<'tcx>(
+ (val, ty): (ConstValue<'tcx>, Ty<'tcx>)
+) -> DepConstructor<'tcx> {
+ DepConstructor::ConstValueToAllocation { val, ty }
+}
+
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
DepConstructor::TypeParamPredicates {
item_id,
DepKind::FulfillObligation |
DepKind::VtableMethods |
DepKind::EraseRegionsTy |
+ DepKind::ConstValueToAllocation |
DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions |
DepKind::DropckOutlives |
use ich::Fingerprint;
use ich::StableHashingContext;
use infer::canonical::{Canonical, Canonicalize};
-use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::privacy::AccessLevels;
use middle::resolve_lifetime::ObjectLifetimeDefault;
use mir::Mir;
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
use mir::GeneratorLayout;
use session::CrateDisambiguator;
use traits::{self, Reveal};
// 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?"))
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
- Ok(&ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
- ty,
- }) => {
- trace!("discriminants: {} ({:?})", b, repr_type);
- Some(Discr {
- val: b,
- ty,
- })
- },
- Ok(&ty::Const {
- val: ConstVal::Value(other),
- ..
- }) => {
- info!("invalid enum discriminant: {:#?}", other);
- ::middle::const_val::struct_error(
- tcx,
- tcx.def_span(expr_did),
- "constant evaluation of enum discriminant resulted in non-integer",
- ).emit();
- None
+ Ok(val) => {
+ // FIXME: Find the right type and use it instead of `val.ty` here
+ if let Some(b) = val.assert_bits(val.ty) {
+ trace!("discriminants: {} ({:?})", b, repr_type);
+ Some(Discr {
+ val: b,
+ ty: val.ty,
+ })
+ } else {
+ info!("invalid enum discriminant: {:#?}", val);
+ ::middle::const_val::struct_error(
+ tcx,
+ tcx.def_span(expr_did),
+ "constant evaluation of enum discriminant resulted in non-integer",
+ ).emit();
+ None
+ }
}
Err(err) => {
err.report(tcx, tcx.def_span(expr_did), "enum discriminant");
}
None
}
- _ => span_bug!(tcx.def_span(expr_did), "const eval "),
}
}
use ty::subst::{Kind, UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::error::{ExpectedFound, TypeError};
-use mir::interpret::{GlobalId, Value, PrimVal};
+use mir::interpret::GlobalId;
use util::common::ErrorReported;
use std::rc::Rc;
use std::iter;
assert_eq!(sz_a.ty, tcx.types.usize);
assert_eq!(sz_b.ty, tcx.types.usize);
let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result<u64, ErrorReported> {
+ if let Some(s) = x.assert_usize(tcx) {
+ return Ok(s);
+ }
match x.val {
- ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
ConstVal::Unevaluated(def_id, substs) => {
// FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty();
instance,
promoted: None
};
- match tcx.const_eval(param_env.and(cid)) {
- Ok(&ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))),
- ..
- }) => {
- assert_eq!(b as u64 as u128, b);
- return Ok(b as u64);
- }
- _ => {}
+ if let Some(s) = tcx.const_eval(param_env.and(cid))
+ .ok()
+ .map(|c| c.unwrap_usize(tcx)) {
+ return Ok(s)
}
}
},
use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
use ty::{Slice, TyS};
use util::captures::Captures;
+use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue};
use std::iter;
use std::cmp::Ordering;
/// 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);
pub val: ConstVal<'tcx>,
}
+impl<'tcx> Const<'tcx> {
+ pub fn unevaluated(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx Substs<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ tcx.mk_const(Const {
+ val: ConstVal::Unevaluated(def_id, substs),
+ ty,
+ })
+ }
+
+ #[inline]
+ pub fn from_const_val(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: ConstVal<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ tcx.mk_const(Const {
+ val,
+ ty,
+ })
+ }
+
+ #[inline]
+ pub fn from_const_value(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: ConstValue<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_val(tcx, ConstVal::Value(val), ty)
+ }
+
+ #[inline]
+ pub fn from_alloc(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ alloc: &'tcx Allocation,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty)
+ }
+
+ #[inline]
+ pub fn from_byval_value(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: Value,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty)
+ }
+
+ #[inline]
+ pub fn from_primval(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: PrimVal,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_const_value(tcx, ConstValue::from_primval(val), ty)
+ }
+
+ #[inline]
+ pub fn from_bits(
+ tcx: TyCtxt<'_, '_, 'tcx>,
+ val: u128,
+ ty: Ty<'tcx>,
+ ) -> &'tcx Self {
+ Self::from_primval(tcx, PrimVal::Bytes(val), ty)
+ }
+
+ #[inline]
+ pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+ Self::from_primval(tcx, PrimVal::Undef, ty)
+ }
+
+ #[inline]
+ pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self {
+ Self::from_bits(tcx, v as u128, tcx.types.bool)
+ }
+
+ #[inline]
+ pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self {
+ Self::from_bits(tcx, n as u128, tcx.types.usize)
+ }
+
+ #[inline]
+ pub fn to_bits(&self, ty: Ty<'_>) -> Option<u128> {
+ if self.ty != ty {
+ return None;
+ }
+ match self.val {
+ ConstVal::Value(val) => val.to_bits(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_ptr(&self) -> Option<MemoryPointer> {
+ match self.val {
+ ConstVal::Value(val) => val.to_ptr(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn to_primval(&self) -> Option<PrimVal> {
+ match self.val {
+ ConstVal::Value(val) => val.to_primval(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn assert_bits(&self, ty: Ty<'_>) -> Option<u128> {
+ assert_eq!(self.ty, ty);
+ match self.val {
+ ConstVal::Value(val) => val.to_bits(),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
+ self.assert_bits(tcx.types.bool).and_then(|v| match v {
+ 0 => Some(false),
+ 1 => Some(true),
+ _ => None,
+ })
+ }
+
+ #[inline]
+ pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
+ self.assert_bits(tcx.types.usize).map(|v| v as u64)
+ }
+
+ #[inline]
+ pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 {
+ match self.assert_bits(ty) {
+ Some(val) => val,
+ None => bug!("expected bits of {}, got {:#?}", ty, self),
+ }
+ }
+
+ #[inline]
+ pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 {
+ match self.assert_usize(tcx) {
+ Some(val) => val,
+ None => bug!("expected constant usize, got {:#?}", self),
+ }
+ }
+}
+
impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {}
}
}
-/// 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 hir;
use ich::NodeIdHashingMode;
use middle::const_val::ConstVal;
-use traits;
-use ty::{self, Ty, TyCtxt, TypeFoldable};
+use traits::{self, ObligationCause};
+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};
use util::common::ErrorReported;
use middle::lang_items;
-use mir::interpret::{Value, PrimVal};
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
HashStable};
}
-#[derive(Copy, Clone)]
+#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {
- InfrigingField(&'tcx ty::FieldDef),
+ InfrigingFields(Vec<&'tcx ty::FieldDef>),
NotAnAdt,
HasDestructor,
}
impl<'tcx> ty::ParamEnv<'tcx> {
pub fn can_type_implement_copy<'a>(self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- self_type: Ty<'tcx>, span: Span)
+ self_type: Ty<'tcx>)
-> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt().enter(|infcx| {
_ => return Err(CopyImplementationError::NotAnAdt),
};
- let field_implements_copy = |field: &ty::FieldDef| {
- let cause = traits::ObligationCause::dummy();
- match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) {
- Ok(ty) => !infcx.type_moves_by_default(self, ty, span),
- Err(..) => false,
- }
- };
-
+ let mut infringing = Vec::new();
for variant in &adt.variants {
for field in &variant.fields {
- if !field_implements_copy(field) {
- return Err(CopyImplementationError::InfrigingField(field));
+ let span = tcx.def_span(field.did);
+ let ty = field.ty(tcx, substs);
+ if ty.references_error() {
+ continue;
}
+ let cause = ObligationCause { span, ..ObligationCause::dummy() };
+ let ctx = traits::FulfillmentContext::new();
+ match traits::fully_normalize(&infcx, ctx, cause, self, &ty) {
+ Ok(ty) => if infcx.type_moves_by_default(self, ty, span) {
+ infringing.push(field);
+ }
+ Err(errors) => {
+ infcx.report_fulfillment_errors(&errors, None, false);
+ }
+ };
}
}
-
+ if !infringing.is_empty() {
+ return Err(CopyImplementationError::InfrigingFields(infringing));
+ }
if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
/// 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)
+ }
+ }
})
}
TyArray(_, n) => {
self.hash_discriminant_u8(&n.val);
match n.val {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b),
+ ConstVal::Value(alloc) => self.hash(alloc),
ConstVal::Unevaluated(def_id, _) => self.def_id(def_id),
- _ => bug!("arrays should not have {:?} as length", n)
}
}
TyRawPtr(m) => self.hash(m.mutbl),
use ty::{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 mir::interpret::{Value, PrimVal};
use std::cell::Cell;
use std::fmt;
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)
TyArray(ty, sz) => {
print!(f, cx, write("["), print(ty), write("; "))?;
match sz.val {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => {
- write!(f, "{}", sz)?;
- }
+ ConstVal::Value(..) => ty::tls::with(|tcx| {
+ write!(f, "{}", sz.unwrap_usize(tcx))
+ })?,
ConstVal::Unevaluated(_def_id, _substs) => {
write!(f, "_")?;
}
- _ => {
- write!(f, "{:?}", sz)?;
- }
}
write!(f, "]")
}
cfg-if = "0.1.2"
stable_deref_trait = "1.0.0"
parking_lot_core = "0.2.8"
+rustc-rayon = "0.1.0"
[dependencies.parking_lot]
version = "0.5"
}
impl<Node: Idx> fmt::Debug for DominatorTree<Node> {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&DominatorTreeNode {
tree: self,
node: self.root,
}
impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let subtrees: Vec<_> = self.tree
.children(self.node)
.iter()
#[macro_use]
extern crate cfg_if;
extern crate stable_deref_trait;
+extern crate rustc_rayon as rayon;
// See librustc_cratesio_shim/Cargo.toml for a comment explaining this.
#[allow(unused_extern_crates)]
where O: Debug,
T: Debug,
{
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"OwningRef {{ owner: {:?}, reference: {:?} }}",
self.owner(),
where O: Debug,
T: Debug,
{
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"OwningRefMut {{ owner: {:?}, reference: {:?} }}",
self.owner(),
where O: Sync, for<'a> (&'a mut T): Sync {}
impl Debug for Erased {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<Erased>",)
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true.
+//! This module defines types which are thread safe if cfg!(parallel_queries) is true.
//!
//! `Lrc` is an alias of either Rc or Arc.
//!
use std::ops::{Deref, DerefMut};
use owning_ref::{Erased, OwningRef};
+pub fn serial_join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+ where A: FnOnce() -> RA,
+ B: FnOnce() -> RB
+{
+ (oper_a(), oper_b())
+}
+
+pub struct SerialScope;
+
+impl SerialScope {
+ pub fn spawn<F>(&self, f: F)
+ where F: FnOnce(&SerialScope)
+ {
+ f(self)
+ }
+}
+
+pub fn serial_scope<F, R>(f: F) -> R
+ where F: FnOnce(&SerialScope) -> R
+{
+ f(&SerialScope)
+}
+
cfg_if! {
if #[cfg(not(parallel_queries))] {
pub auto trait Send {}
}
}
+ pub use self::serial_join as join;
+ pub use self::serial_scope as scope;
+
+ pub use std::iter::Iterator as ParallelIterator;
+
+ pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
+ t.into_iter()
+ }
+
pub type MetadataRef = OwningRef<Box<Erased>, [u8]>;
pub use std::rc::Rc as Lrc;
+ pub use std::rc::Weak as Weak;
pub use std::cell::Ref as ReadGuard;
pub use std::cell::RefMut as WriteGuard;
pub use std::cell::RefMut as LockGuard;
pub use parking_lot::MutexGuard as LockGuard;
pub use std::sync::Arc as Lrc;
+ pub use std::sync::Weak as Weak;
pub use self::Lock as MTLock;
use parking_lot::RwLock as InnerRwLock;
use std::thread;
+ pub use rayon::{join, scope};
+
+ pub use rayon::iter::ParallelIterator;
+ use rayon::iter::IntoParallelIterator;
+
+ pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter {
+ t.into_par_iter()
+ }
pub type MetadataRef = OwningRef<Box<Erased + Send + Sync>, [u8]>;
graphviz = { path = "../libgraphviz" }
log = "0.4"
env_logger = { version = "0.5", default-features = false }
+rustc-rayon = "0.1.0"
+scoped-tls = { version = "0.1.1", features = ["nightly"] }
rustc = { path = "../librustc" }
rustc_allocator = { path = "../librustc_allocator" }
rustc_target = { path = "../librustc_target" }
use rustc::session::search_paths::PathKind;
use rustc::lint;
use rustc::middle::{self, reachable, resolve_lifetime, stability};
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, AllArenas, Resolutions, TyCtxt};
use rustc::traits;
use std::io::{self, Write};
use std::iter;
use std::path::{Path, PathBuf};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
use std::sync::mpsc;
use syntax::{self, ast, attr, diagnostics, visit};
use syntax::ext::base::ExtCtxt;
use profile;
+#[cfg(not(parallel_queries))]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+ opts: config::Options,
+ f: F
+) -> R {
+ f(opts)
+}
+
+#[cfg(parallel_queries)]
+pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::Send>(
+ opts: config::Options,
+ f: F
+) -> R {
+ use syntax;
+ use syntax_pos;
+ use rayon::{ThreadPoolBuilder, ThreadPool};
+
+ let config = ThreadPoolBuilder::new().num_threads(Session::query_threads_from_opts(&opts))
+ .stack_size(16 * 1024 * 1024);
+
+ let with_pool = move |pool: &ThreadPool| {
+ pool.install(move || f(opts))
+ };
+
+ syntax::GLOBALS.with(|syntax_globals| {
+ syntax_pos::GLOBALS.with(|syntax_pos_globals| {
+ // The main handler run for each Rayon worker thread and sets up
+ // the thread local rustc uses. syntax_globals and syntax_pos_globals are
+ // captured and set on the new threads. ty::tls::with_thread_locals sets up
+ // thread local callbacks from libsyntax
+ let main_handler = move |worker: &mut FnMut()| {
+ syntax::GLOBALS.set(syntax_globals, || {
+ syntax_pos::GLOBALS.set(syntax_pos_globals, || {
+ ty::tls::with_thread_locals(|| {
+ worker()
+ })
+ })
+ })
+ };
+
+ ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap()
+ })
+ })
+}
+
pub fn compile_input(
trans: Box<TransCrate>,
sess: &Session,
let dep_graph = match future_dep_graph {
None => DepGraph::new_disabled(),
Some(future) => {
- let prev_graph = time(sess, "blocked while dep-graph loading finishes", || {
- future
- .open()
- .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
- message: format!("could not decode incremental cache: {:?}", e),
- })
- .open(sess)
- });
- DepGraph::new(prev_graph)
+ let (prev_graph, prev_work_products) =
+ time(sess, "blocked while dep-graph loading finishes", || {
+ future
+ .open()
+ .unwrap_or_else(|e| rustc_incremental::LoadResult::Error {
+ message: format!("could not decode incremental cache: {:?}", e),
+ })
+ .open(sess)
+ });
+ DepGraph::new(prev_graph, prev_work_products)
}
};
let hir_forest = time(sess, "lowering ast -> hir", || {
trans: &TransCrate,
control: &CompileController,
sess: &'tcx Session,
- cstore: &'tcx CrateStore,
+ cstore: &'tcx CrateStoreDyn,
hir_map: hir_map::Map<'tcx>,
mut analysis: ty::CrateAnalysis,
resolutions: Resolutions,
#![feature(rustc_stack_internals)]
#![feature(no_debug)]
+#![recursion_limit="256"]
+
extern crate arena;
extern crate getopts;
extern crate graphviz;
extern crate env_logger;
#[cfg(unix)]
extern crate libc;
+extern crate rustc_rayon as rayon;
extern crate rustc;
extern crate rustc_allocator;
extern crate rustc_target;
extern crate rustc_traits;
extern crate rustc_trans_utils;
extern crate rustc_typeck;
+extern crate scoped_tls;
extern crate serialize;
#[macro_use]
extern crate log;
use rustc_resolve as resolve;
use rustc_save_analysis as save;
use rustc_save_analysis::DumpHandler;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{self, Lrc};
use rustc_data_structures::OnDrop;
use rustc::session::{self, config, Session, build_session, CompileResult};
use rustc::session::CompileIncomplete;
// See comments on CompilerCalls below for details about the callbacks argument.
// The FileLoader provides a way to load files from sources other than the file system.
pub fn run_compiler<'a>(args: &[String],
- callbacks: &mut CompilerCalls<'a>,
+ callbacks: &mut (CompilerCalls<'a> + sync::Send),
file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
emitter_dest: Option<Box<Write + Send>>)
-> (CompileResult, Option<Session>)
{
syntax::with_globals(|| {
- run_compiler_impl(args, callbacks, file_loader, emitter_dest)
+ let matches = match handle_options(args) {
+ Some(matches) => matches,
+ None => return (Ok(()), None),
+ };
+
+ let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
+
+ driver::spawn_thread_pool(sopts, |sopts| {
+ run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)
+ })
})
}
-fn run_compiler_impl<'a>(args: &[String],
- callbacks: &mut CompilerCalls<'a>,
- file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
- emitter_dest: Option<Box<Write + Send>>)
- -> (CompileResult, Option<Session>)
-{
+fn run_compiler_with_pool<'a>(
+ matches: getopts::Matches,
+ sopts: config::Options,
+ cfg: ast::CrateConfig,
+ callbacks: &mut (CompilerCalls<'a> + sync::Send),
+ file_loader: Option<Box<FileLoader + Send + Sync + 'static>>,
+ emitter_dest: Option<Box<Write + Send>>
+) -> (CompileResult, Option<Session>) {
macro_rules! do_or_return {($expr: expr, $sess: expr) => {
match $expr {
Compilation::Stop => return (Ok(()), $sess),
}
}}
- let matches = match handle_options(args) {
- Some(matches) => matches,
- None => return (Ok(()), None),
- };
-
- let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
-
let descriptions = diagnostics_registry();
do_or_return!(callbacks.early_callback(&matches,
use rustc::ty::{self, TyCtxt, Resolutions, AllArenas};
use rustc::cfg;
use rustc::cfg::graphviz::LabelledCFG;
-use rustc::middle::cstore::CrateStore;
+use rustc::middle::cstore::CrateStoreDyn;
use rustc::session::Session;
use rustc::session::config::{Input, OutputFilenames};
use rustc_borrowck as borrowck;
}
fn call_with_pp_support_hir<'tcx, A, F>(&self,
sess: &'tcx Session,
- cstore: &'tcx CrateStore,
+ cstore: &'tcx CrateStoreDyn,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
}
pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
- cstore: &'tcx CrateStore,
+ cstore: &'tcx CrateStoreDyn,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
// with a different callback than the standard driver, so that isn't easy.
// Instead, we call that function ourselves.
fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
- cstore: &'a CrateStore,
+ cstore: &'a CrateStoreDyn,
hir_map: &hir_map::Map<'tcx>,
analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
where F: FnOnce(Env)
{
syntax::with_globals(|| {
- test_env_impl(source_string, args, body)
+ let mut options = config::basic_options();
+ options.debugging_opts.verbose = true;
+ options.unstable_features = UnstableFeatures::Allow;
+
+ driver::spawn_thread_pool(options, |options| {
+ test_env_with_pool(options, source_string, args, body)
+ })
});
}
-fn test_env_impl<F>(source_string: &str,
- (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
- body: F)
+fn test_env_with_pool<F>(
+ options: config::Options,
+ source_string: &str,
+ (emitter, expected_err_count): (Box<Emitter + sync::Send>, usize),
+ body: F
+)
where F: FnOnce(Env)
{
- let mut options = config::basic_options();
- options.debugging_opts.verbose = true;
- options.unstable_features = UnstableFeatures::Allow;
let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
-
let sess = session::build_session_(options,
None,
diagnostic_handler,
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 fmt::Display for FatalError {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "parser fatal error")
}
}
pub struct ExplicitBug;
impl fmt::Display for ExplicitBug {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "parser internal bug")
}
}
pub use persist::load_dep_graph;
pub use persist::load_query_result_cache;
pub use persist::LoadResult;
+pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
pub use persist::save_dep_graph;
-pub use persist::save_trans_partition;
-pub use persist::save_work_products;
+pub use persist::save_work_product_index;
pub use persist::in_incr_comp_dir;
pub use persist::prepare_session_directory;
pub use persist::finalize_session_directory;
//! Code to save/load the dep-graph from files.
-use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph};
+use rustc_data_structures::fx::FxHashMap;
+use rustc::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::ty::maps::OnDiskCache;
tcx.allocate_metadata_dep_nodes();
tcx.precompute_in_scope_traits_hashes();
-
- if tcx.sess.incr_comp_session_dir_opt().is_none() {
- // If we are only building with -Zquery-dep-graph but without an actual
- // incr. comp. session directory, we exit here. Otherwise we'd fail
- // when trying to load work products.
- return
- }
-
- let work_products_path = work_products_path(tcx.sess);
- let load_result = load_data(tcx.sess.opts.debugging_opts.incremental_info, &work_products_path);
-
- if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
- // Decode the list of work_products
- let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
- let work_products: Vec<SerializedWorkProduct> =
- RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
- let msg = format!("Error decoding `work-products` from incremental \
- compilation session directory: {}", e);
- tcx.sess.fatal(&msg[..])
- });
-
- for swp in work_products {
- let mut all_files_exist = true;
- for &(_, ref file_name) in swp.work_product.saved_files.iter() {
- let path = in_incr_comp_dir_sess(tcx.sess, file_name);
- if !path.exists() {
- all_files_exist = false;
-
- if tcx.sess.opts.debugging_opts.incremental_info {
- eprintln!("incremental: could not find file for work \
- product: {}", path.display());
- }
- }
- }
-
- if all_files_exist {
- debug!("reconcile_work_products: all files for {:?} exist", swp);
- tcx.dep_graph.insert_previous_work_product(&swp.id, swp.work_product);
- } else {
- debug!("reconcile_work_products: some file for {:?} does not exist", swp);
- delete_dirty_work_product(tcx, swp);
- }
- }
- }
}
+type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
+
pub enum LoadResult<T> {
Ok { data: T },
DataOutOfDate,
Error { message: String },
}
-
-impl LoadResult<PreviousDepGraph> {
- pub fn open(self, sess: &Session) -> PreviousDepGraph {
+impl LoadResult<(PreviousDepGraph, WorkProductMap)> {
+ pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) {
match self {
LoadResult::Error { message } => {
sess.warn(&message);
- PreviousDepGraph::new(SerializedDepGraph::new())
+ (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
},
LoadResult::DataOutOfDate => {
if let Err(err) = delete_all_session_dir_contents(sess) {
incremental compilation session directory contents `{}`: {}.",
dep_graph_path(sess).display(), err));
}
- PreviousDepGraph::new(SerializedDepGraph::new())
+ (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
}
LoadResult::Ok { data } => data
}
}
}
-fn delete_dirty_work_product(tcx: TyCtxt,
+fn delete_dirty_work_product(sess: &Session,
swp: SerializedWorkProduct) {
debug!("delete_dirty_work_product({:?})", swp);
- work_product::delete_workproduct_files(tcx.sess, &swp.work_product);
+ work_product::delete_workproduct_files(sess, &swp.work_product);
}
/// Either a result that has already be computed or a
/// Launch a thread and load the dependency graph in the background.
pub fn load_dep_graph(sess: &Session) ->
- MaybeAsync<LoadResult<PreviousDepGraph>>
+ MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>
{
// Since `sess` isn't `Sync`, we perform all accesses to `sess`
// before we fire the background thread.
if sess.opts.incremental.is_none() {
// No incremental compilation.
return MaybeAsync::Sync(LoadResult::Ok {
- data: PreviousDepGraph::new(SerializedDepGraph::new())
+ data: (PreviousDepGraph::new(SerializedDepGraph::new()), FxHashMap())
});
}
let report_incremental_info = sess.opts.debugging_opts.incremental_info;
let expected_hash = sess.opts.dep_tracking_hash();
+ let mut prev_work_products = FxHashMap();
+
+ // If we are only building with -Zquery-dep-graph but without an actual
+ // incr. comp. session directory, we skip this. Otherwise we'd fail
+ // when trying to load work products.
+ if sess.incr_comp_session_dir_opt().is_some() {
+ let work_products_path = work_products_path(sess);
+ let load_result = load_data(report_incremental_info, &work_products_path);
+
+ if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
+ // Decode the list of work_products
+ let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
+ let work_products: Vec<SerializedWorkProduct> =
+ RustcDecodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
+ let msg = format!("Error decoding `work-products` from incremental \
+ compilation session directory: {}", e);
+ sess.fatal(&msg[..])
+ });
+
+ for swp in work_products {
+ let mut all_files_exist = true;
+ for &(_, ref file_name) in swp.work_product.saved_files.iter() {
+ let path = in_incr_comp_dir_sess(sess, file_name);
+ if !path.exists() {
+ all_files_exist = false;
+
+ if sess.opts.debugging_opts.incremental_info {
+ eprintln!("incremental: could not find file for work \
+ product: {}", path.display());
+ }
+ }
+ }
+
+ if all_files_exist {
+ debug!("reconcile_work_products: all files for {:?} exist", swp);
+ prev_work_products.insert(swp.id, swp.work_product);
+ } else {
+ debug!("reconcile_work_products: some file for {:?} does not exist", swp);
+ delete_dirty_work_product(sess, swp);
+ }
+ }
+ }
+ }
+
MaybeAsync::Async(std::thread::spawn(move || {
time_ext(time_passes, None, "background load prev dep-graph", move || {
match load_data(report_incremental_info, &path) {
let dep_graph = SerializedDepGraph::decode(&mut decoder)
.expect("Error reading cached dep-graph");
- LoadResult::Ok { data: PreviousDepGraph::new(dep_graph) }
+ LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) }
}
}
})
pub use self::load::load_query_result_cache;
pub use self::load::LoadResult;
pub use self::save::save_dep_graph;
-pub use self::save::save_work_products;
-pub use self::work_product::save_trans_partition;
+pub use self::save::save_work_product_index;
+pub use self::work_product::copy_cgu_workproducts_to_incr_comp_cache_dir;
pub use self::work_product::delete_workproduct_files;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::dep_graph::{DepGraph, DepKind};
+use rustc::dep_graph::{DepGraph, DepKind, WorkProduct, WorkProductId};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::common::time;
})
}
-pub fn save_work_products(sess: &Session, dep_graph: &DepGraph) {
+pub fn save_work_product_index(sess: &Session,
+ dep_graph: &DepGraph,
+ new_work_products: FxHashMap<WorkProductId, WorkProduct>) {
if sess.opts.incremental.is_none() {
return;
}
- debug!("save_work_products()");
+ debug!("save_work_product_index()");
dep_graph.assert_ignored();
let path = work_products_path(sess);
- save_in(sess, path, |e| encode_work_products(dep_graph, e));
+ save_in(sess, path, |e| encode_work_product_index(&new_work_products, e));
// We also need to clean out old work-products, as not all of them are
// deleted during invalidation. Some object files don't change their
// content, they are just not needed anymore.
- let new_work_products = dep_graph.work_products();
let previous_work_products = dep_graph.previous_work_products();
-
for (id, wp) in previous_work_products.iter() {
if !new_work_products.contains_key(id) {
work_product::delete_workproduct_files(sess, wp);
Ok(())
}
-fn encode_work_products(dep_graph: &DepGraph,
- encoder: &mut Encoder) -> io::Result<()> {
- let work_products: Vec<_> = dep_graph
- .work_products()
+fn encode_work_product_index(work_products: &FxHashMap<WorkProductId, WorkProduct>,
+ encoder: &mut Encoder) -> io::Result<()> {
+ let serialized_products: Vec<_> = work_products
.iter()
.map(|(id, work_product)| {
SerializedWorkProduct {
})
.collect();
- work_products.encode(encoder)
+ serialized_products.encode(encoder)
}
fn encode_query_cache(tcx: TyCtxt,
//! This module contains files for saving intermediate work-products.
use persist::fs::*;
-use rustc::dep_graph::{WorkProduct, WorkProductId, DepGraph, WorkProductFileKind};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
use rustc::session::Session;
use rustc::util::fs::link_or_copy;
use std::path::PathBuf;
use std::fs as std_fs;
-pub fn save_trans_partition(sess: &Session,
- dep_graph: &DepGraph,
- cgu_name: &str,
- files: &[(WorkProductFileKind, PathBuf)]) {
- debug!("save_trans_partition({:?},{:?})",
+pub fn copy_cgu_workproducts_to_incr_comp_cache_dir(
+ sess: &Session,
+ cgu_name: &str,
+ files: &[(WorkProductFileKind, PathBuf)]
+) -> Option<(WorkProductId, WorkProduct)> {
+ debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})",
cgu_name,
files);
if sess.opts.incremental.is_none() {
- return
+ return None
}
let work_product_id = WorkProductId::from_cgu_name(cgu_name);
})
.collect();
let saved_files = match saved_files {
+ None => return None,
Some(v) => v,
- None => return,
};
let work_product = WorkProduct {
saved_files,
};
- dep_graph.insert_work_product(&work_product_id, work_product);
+ Some((work_product_id, work_product))
}
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
if !ty.moves_by_default(cx.tcx, param_env, item.span) {
return;
}
- if param_env.can_type_implement_copy(cx.tcx, ty, item.span).is_ok() {
+ if param_env.can_type_implement_copy(cx.tcx, ty).is_ok() {
cx.span_lint(MISSING_COPY_IMPLEMENTATIONS,
item.span,
"type could implement `Copy`; consider adding `impl \
impl UnreachablePub {
fn perform_lint(&self, cx: &LateContext, what: &str, id: ast::NodeId,
- vis: &hir::Visibility, span: Span, exportable: bool) {
+ vis: &hir::Visibility, span: Span, exportable: bool,
+ mut applicability: Applicability) {
if !cx.access_levels.is_reachable(id) && *vis == hir::Visibility::Public {
+ if span.ctxt().outer().expn_info().is_some() {
+ applicability = Applicability::MaybeIncorrect;
+ }
let def_span = cx.tcx.sess.codemap().def_span(span);
let mut err = cx.struct_span_lint(UNREACHABLE_PUB, def_span,
&format!("unreachable `pub` {}", what));
- // visibility is token at start of declaration (can be macro
- // variable rather than literal `pub`)
+ // We are presuming that visibility is token at start of
+ // declaration (can be macro variable rather than literal `pub`)
let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' ');
let replacement = if cx.tcx.features().crate_visibility_modifier {
"crate"
} else {
"pub(crate)"
}.to_owned();
- let app = if span.ctxt().outer().expn_info().is_none() {
- // even if macros aren't involved the suggestion
- // may be incorrect -- the user may have mistakenly
- // hidden it behind a private module and this lint is
- // a helpful way to catch that. However, we're trying
- // not to change the nature of the code with this lint
- // so it's marked as machine applicable.
- Applicability::MachineApplicable
- } else {
- Applicability::MaybeIncorrect
- };
- err.span_suggestion_with_applicability(pub_span, "consider restricting its visibility",
- replacement, app);
+ err.span_suggestion_with_applicability(pub_span,
+ "consider restricting its visibility",
+ replacement,
+ applicability);
if exportable {
err.help("or consider exporting it for use by other crates");
}
}
}
+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnreachablePub {
fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
- self.perform_lint(cx, "item", item.id, &item.vis, item.span, true);
+ let applicability = match item.node {
+ // suggestion span-manipulation is inadequate for `pub use
+ // module::{item}` (Issue #50455)
+ hir::ItemUse(..) => Applicability::MaybeIncorrect,
+ _ => Applicability::MachineApplicable,
+ };
+ self.perform_lint(cx, "item", item.id, &item.vis, item.span, true, applicability);
}
fn check_foreign_item(&mut self, cx: &LateContext, foreign_item: &hir::ForeignItem) {
- self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis, foreign_item.span, true);
+ self.perform_lint(cx, "item", foreign_item.id, &foreign_item.vis,
+ foreign_item.span, true, Applicability::MachineApplicable);
}
fn check_struct_field(&mut self, cx: &LateContext, field: &hir::StructField) {
- self.perform_lint(cx, "field", field.id, &field.vis, field.span, false);
+ self.perform_lint(cx, "field", field.id, &field.vis, field.span, false,
+ Applicability::MachineApplicable);
}
fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
- self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false);
+ self.perform_lint(cx, "item", impl_item.id, &impl_item.vis, impl_item.span, false,
+ Applicability::MachineApplicable);
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ExternCrate {
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ if !cx.tcx.features().extern_absolute_paths {
+ return
+ }
if let hir::ItemExternCrate(ref orig) = it.node {
if it.attrs.iter().any(|a| a.check_name("macro_use")) {
return
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,
UNUSED_PARENS);
add_lint_group!(sess,
- "rust_2018_migration",
+ "rust_2018_idioms",
BARE_TRAIT_OBJECT,
UNREACHABLE_PUB,
UNNECESSARY_EXTERN_CRATE);
MergeFunctions: bool,
SLPVectorize: bool,
LoopVectorize: bool,
+ PrepareForThinLTO: bool,
PGOGenPath: *const c_char,
PGOUsePath: *const c_char);
pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef,
pub struct CrateLoader<'a> {
pub sess: &'a Session,
cstore: &'a CStore,
- next_crate_num: CrateNum,
local_crate_name: Symbol,
}
CrateLoader {
sess,
cstore,
- next_crate_num: cstore.next_crate_num(),
local_crate_name: Symbol::intern(local_crate_name),
}
}
self.verify_no_symbol_conflicts(span, &crate_root);
// Claim this crate number and cache it
- let cnum = self.next_crate_num;
- self.next_crate_num = CrateNum::from_u32(cnum.as_u32() + 1);
+ let cnum = self.cstore.alloc_new_crate_num();
// Stash paths for top-most crate locally if necessary.
let crate_paths = if root.is_none() {
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
+ let dependencies: Vec<CrateNum> = cnum_map.iter().cloned().collect();
+
let def_path_table = record_time(&self.sess.perf_stats.decode_def_path_tables_time, || {
crate_root.def_path_table.decode((&metadata, self.sess))
});
}),
root: crate_root,
blob: metadata,
- cnum_map: Lock::new(cnum_map),
+ cnum_map,
cnum,
+ dependencies: Lock::new(dependencies),
codemap_import_info: RwLock::new(vec![]),
attribute_cache: Lock::new([Vec::new(), Vec::new()]),
dep_kind: Lock::new(dep_kind),
// Propagate the extern crate info to dependencies.
extern_crate.direct = false;
- for &dep_cnum in cmeta.cnum_map.borrow().iter() {
+ for &dep_cnum in cmeta.dependencies.borrow().iter() {
self.update_extern_crate(dep_cnum, extern_crate, visited);
}
}
}
info!("injecting a dep from {} to {}", cnum, krate);
- data.cnum_map.borrow_mut().push(krate);
+ data.dependencies.borrow_mut().push(krate);
});
}
}
pub extern_crate: Lock<Option<ExternCrate>>,
pub blob: MetadataBlob,
- pub cnum_map: Lock<CrateNumMap>,
+ pub cnum_map: CrateNumMap,
pub cnum: CrateNum,
+ pub dependencies: Lock<Vec<CrateNum>>,
pub codemap_import_info: RwLock<Vec<ImportedFileMap>>,
pub attribute_cache: Lock<[Vec<Option<Lrc<[ast::Attribute]>>>; 2]>,
impl CStore {
pub fn new(metadata_loader: Box<MetadataLoader + Sync>) -> CStore {
CStore {
- metas: RwLock::new(IndexVec::new()),
+ // We add an empty entry for LOCAL_CRATE (which maps to zero) in
+ // order to make array indices in `metas` match with the
+ // corresponding `CrateNum`. This first entry will always remain
+ // `None`.
+ metas: RwLock::new(IndexVec::from_elem_n(None, 1)),
extern_mod_crate_map: Lock::new(FxHashMap()),
metadata_loader,
}
}
- /// You cannot use this function to allocate a CrateNum in a thread-safe manner.
- /// It is currently only used in CrateLoader which is single-threaded code.
- pub fn next_crate_num(&self) -> CrateNum {
- CrateNum::new(self.metas.borrow().len() + 1)
+ pub(super) fn alloc_new_crate_num(&self) -> CrateNum {
+ let mut metas = self.metas.borrow_mut();
+ let cnum = CrateNum::new(metas.len());
+ metas.push(None);
+ cnum
}
- pub fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
+ pub(super) fn get_crate_data(&self, cnum: CrateNum) -> Lrc<CrateMetadata> {
self.metas.borrow()[cnum].clone().unwrap()
}
- pub fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
- use rustc_data_structures::indexed_vec::Idx;
- let mut met = self.metas.borrow_mut();
- while met.len() <= cnum.index() {
- met.push(None);
- }
- met[cnum] = Some(data);
+ pub(super) fn set_crate_data(&self, cnum: CrateNum, data: Lrc<CrateMetadata>) {
+ let mut metas = self.metas.borrow_mut();
+ assert!(metas[cnum].is_none(), "Overwriting crate metadata entry");
+ metas[cnum] = Some(data);
}
- pub fn iter_crate_data<I>(&self, mut i: I)
+ pub(super) fn iter_crate_data<I>(&self, mut i: I)
where I: FnMut(CrateNum, &Lrc<CrateMetadata>)
{
for (k, v) in self.metas.borrow().iter_enumerated() {
}
}
- pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
+ pub(super) fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec<CrateNum> {
let mut ordering = Vec::new();
self.push_dependencies_in_postorder(&mut ordering, krate);
ordering.reverse();
ordering
}
- pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate: CrateNum) {
+ pub(super) fn push_dependencies_in_postorder(&self,
+ ordering: &mut Vec<CrateNum>,
+ krate: CrateNum) {
if ordering.contains(&krate) {
return;
}
let data = self.get_crate_data(krate);
- for &dep in data.cnum_map.borrow().iter() {
+ for &dep in data.dependencies.borrow().iter() {
if dep != krate {
self.push_dependencies_in_postorder(ordering, dep);
}
ordering.push(krate);
}
- pub fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
+ pub(super) fn do_postorder_cnums_untracked(&self) -> Vec<CrateNum> {
let mut ordering = Vec::new();
for (num, v) in self.metas.borrow().iter_enumerated() {
if let &Some(_) = v {
return ordering
}
- pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
+ pub(super) fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, cnum: CrateNum) {
self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum);
}
- pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
+ pub(super) fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> {
self.extern_mod_crate_map.borrow().get(&emod_id).cloned()
}
}
if cnum == LOCAL_CRATE {
self.cdata().cnum
} else {
- self.cdata().cnum_map.borrow()[cnum]
+ self.cdata().cnum_map[cnum]
}
}
}
// Translate a DefId from the current compilation environment to a DefId
// for an external crate.
fn reverse_translate_def_id(&self, did: DefId) -> Option<DefId> {
- for (local, &global) in self.cnum_map.borrow().iter_enumerated() {
+ for (local, &global) in self.cnum_map.iter_enumerated() {
if global == did.krate {
return Some(DefId {
krate: local,
.enumerate()
.flat_map(|(i, link)| {
let cnum = CrateNum::new(i + 1);
- link.map(|link| (self.cnum_map.borrow()[cnum], link))
+ link.map(|link| (self.cnum_map[cnum], link))
})
.collect()
}
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)]
}
impl fmt::Debug for Constraint {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
formatter,
"({:?}: {:?} @ {:?}) due to {:?}",
ProjectionElem::Subslice { from, to } => PlaceTy::Ty {
ty: match base_ty.sty {
ty::TyArray(inner, size) => {
- let size = size.val.unwrap_u64();
+ let size = size.unwrap_usize(tcx);
let min_size = (from as u64) + (to as u64);
if let Some(rest_size) = size.checked_sub(min_size) {
tcx.mk_array(inner, rest_size)
use build::{BlockAnd, BlockAndExtension, Builder};
use build::expr::category::{Category, RvalueFunc};
use hair::*;
-use rustc::middle::const_val::ConstVal;
use rustc::middle::region;
use rustc::ty::{self, Ty, UpvarSubsts};
use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::EvalErrorKind;
use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
span: expr_span,
ty: this.hir.tcx().types.u32,
literal: Literal::Value {
- value: this.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty: this.hir.tcx().types.u32
- }),
+ value: ty::Const::from_bits(
+ this.hir.tcx(),
+ 0,
+ this.hir.tcx().types.u32),
},
}));
box AggregateKind::Generator(closure_id, substs, movability)
let bits = self.hir.integer_bit_width(ty);
let n = (!0u128) >> (128 - bits);
let literal = Literal::Value {
- value: self.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
- ty
- })
+ value: ty::Const::from_bits(self.hir.tcx(), n, ty)
};
self.literal_operand(span, ty, literal)
let bits = self.hir.integer_bit_width(ty);
let n = 1 << (bits - 1);
let literal = Literal::Value {
- value: self.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n))),
- ty
- })
+ value: ty::Const::from_bits(self.hir.tcx(), n, ty)
};
self.literal_operand(span, ty, literal)
match *match_pair.pattern.kind {
PatternKind::Constant { value } => {
- // if the places match, the type should match
- assert_eq!(match_pair.pattern.ty, switch_ty);
-
indices.entry(value)
.or_insert_with(|| {
- options.push(value.val.to_raw_bits().expect("switching on int"));
+ options.push(value.unwrap_bits(switch_ty));
options.len() - 1
});
true
use build::Builder;
-use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
-use rustc::mir::interpret::{Value, PrimVal};
use rustc::mir::*;
use syntax_pos::{Span, DUMMY_SP};
}
}
let literal = Literal::Value {
- value: self.hir.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty
- })
+ value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
};
self.literal_operand(span, ty, literal)
use hair::cx::block;
use hair::cx::to_ref::ToRef;
use rustc::hir::def::{Def, CtorKind};
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::interpret::GlobalId;
use rustc::ty::{self, AdtKind, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability};
use rustc::ty::cast::CastKind as TyCastKind;
promoted: None
};
let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and(global_id)) {
- Ok(cv) => cv.val.unwrap_u64(),
+ Ok(cv) => cv.unwrap_usize(cx.tcx),
Err(e) => {
e.report(cx.tcx, cx.tcx.def_span(def_id), "array length");
0
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, _) => {
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx().mk_const(ty::Const {
- val,
- ty,
- }),
+ value: val,
},
},
}.to_ref();
- let offset = mk_const(
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(offset as u128))),
- );
+ let offset = mk_const(ty::Const::from_bits(cx.tcx, offset as u128, ty));
match did {
Some(did) => {
// in case we are offsetting from a computed discriminant
// and not the beginning of discriminants (which is always `0`)
let substs = Substs::identity_for_item(cx.tcx(), did);
- let lhs = mk_const(ConstVal::Unevaluated(did, substs));
+ let lhs = mk_const(ty::Const::unevaluated(cx.tcx(), did, substs, ty));
let bin = ExprKind::Binary {
op: BinOp::Add,
lhs,
span: expr.span,
kind: ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty
- }),
+ value: ty::Const::zero_sized(cx.tcx(), ty),
},
},
}
Def::StructCtor(_, CtorKind::Fn) |
Def::VariantCtor(_, CtorKind::Fn) => ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty: cx.tables().node_id_to_type(expr.hir_id)
- }),
+ value: ty::Const::zero_sized(
+ cx.tcx,
+ cx.tables().node_id_to_type(expr.hir_id)),
},
},
Def::Const(def_id) |
Def::AssociatedConst(def_id) => ExprKind::Literal {
literal: Literal::Value {
- value: cx.tcx.mk_const(ty::Const {
- val: ConstVal::Unevaluated(def_id, substs),
- ty: cx.tables().node_id_to_type(expr.hir_id)
- }),
+ value: ty::Const::unevaluated(
+ cx.tcx,
+ def_id,
+ substs,
+ cx.tables().node_id_to_type(expr.hir_id))
},
},
use hair::*;
-use rustc::middle::const_val::ConstVal;
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
use rustc::hir::map::blocks::FnLikeNode;
use syntax::symbol::Symbol;
use rustc::hir;
use rustc_data_structures::sync::Lrc;
-use rustc::mir::interpret::{Value, PrimVal};
use hair::pattern::parse_float;
#[derive(Clone)]
pub fn usize_literal(&mut self, value: u64) -> Literal<'tcx> {
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value as u128))),
- ty: self.tcx.types.usize
- })
+ value: ty::Const::from_usize(self.tcx, value),
}
}
pub fn true_literal(&mut self) -> Literal<'tcx> {
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(1))),
- ty: self.tcx.types.bool
- })
+ value: ty::Const::from_bool(self.tcx, true),
}
}
pub fn false_literal(&mut self) -> Literal<'tcx> {
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty: self.tcx.types.bool
- })
+ value: ty::Const::from_bool(self.tcx, false),
}
}
layout::Integer::from_attr(self.tcx, ty).size().bits()
}
+ // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
pub fn const_eval_literal(
&mut self,
lit: &'tcx ast::LitKind,
) -> Literal<'tcx> {
trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
- let parse_float = |num, fty| -> Value {
+ let parse_float = |num, fty| -> ConstValue<'tcx> {
parse_float(num, fty, neg).unwrap_or_else(|_| {
// FIXME(#31407) this is only necessary because float parsing is buggy
self.tcx.sess.span_fatal(sp, "could not evaluate float literal (see issue #31407)");
let s = s.as_str();
let id = self.tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
- Value::ByValPair(
+ ConstValue::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
LitKind::ByteStr(ref data) => {
let id = self.tcx.allocate_cached(data);
let ptr = MemoryPointer::new(id, 0);
- Value::ByVal(PrimVal::Ptr(ptr))
+ ConstValue::ByVal(PrimVal::Ptr(ptr))
},
- LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+ LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) if neg => {
let n = n as i128;
let n = n.overflowing_neg().0;
let n = clamp(n as u128);
- Value::ByVal(PrimVal::Bytes(n))
+ ConstValue::ByVal(PrimVal::Bytes(n))
},
- LitKind::Int(n, _) => Value::ByVal(PrimVal::Bytes(clamp(n))),
+ LitKind::Int(n, _) => ConstValue::ByVal(PrimVal::Bytes(clamp(n))),
LitKind::Float(n, fty) => {
parse_float(n, fty)
}
};
parse_float(n, fty)
}
- LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
- LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+ LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+ LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
};
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(lit),
- ty,
- }),
+ value: ty::Const::from_const_value(self.tcx, lit, ty)
}
}
let method_ty = method_ty.subst(self.tcx, substs);
return (method_ty,
Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty: method_ty
- }),
+ value: ty::Const::zero_sized(self.tcx, method_ty)
});
}
}
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::mir::Field;
-use rustc::mir::interpret::{Value, PrimVal};
use rustc::util::common::ErrorReported;
use syntax_pos::{Span, DUMMY_SP};
self.byte_array_map.entry(pat).or_insert_with(|| {
match pat.kind {
box PatternKind::Constant {
- value: &ty::Const { val: ConstVal::Value(b), ty }
+ value: const_val
} => {
- match b {
- Value::ByVal(PrimVal::Ptr(ptr)) => {
- let is_array_ptr = ty
- .builtin_deref(true)
- .and_then(|t| t.ty.builtin_index())
- .map_or(false, |t| t == tcx.types.u8);
- assert!(is_array_ptr);
- let alloc = tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .unwrap();
- assert_eq!(ptr.offset, 0);
- // FIXME: check length
- alloc.bytes.iter().map(|b| {
- &*pattern_arena.alloc(Pattern {
- ty: tcx.types.u8,
- span: pat.span,
- kind: box PatternKind::Constant {
- value: tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(
- PrimVal::Bytes(*b as u128),
- )),
- ty: tcx.types.u8
- })
- }
- })
- }).collect()
- },
- _ => bug!("not a byte str: {:?}", b),
+ if let Some(ptr) = const_val.to_ptr() {
+ let is_array_ptr = const_val.ty
+ .builtin_deref(true)
+ .and_then(|t| t.ty.builtin_index())
+ .map_or(false, |t| t == tcx.types.u8);
+ assert!(is_array_ptr);
+ let alloc = tcx
+ .interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .unwrap();
+ assert_eq!(ptr.offset, 0);
+ // FIXME: check length
+ alloc.bytes.iter().map(|b| {
+ &*pattern_arena.alloc(Pattern {
+ ty: tcx.types.u8,
+ span: pat.span,
+ kind: box PatternKind::Constant {
+ value: ty::Const::from_bits(
+ tcx,
+ *b as u128,
+ tcx.types.u8)
+ }
+ })
+ }).collect()
+ } else {
+ bug!("not a byte str: {:?}", const_val)
}
}
_ => span_bug!(pat.span, "unexpected byte array pattern {:?}", pat)
match pcx.ty.sty {
ty::TyBool => {
[true, false].iter().map(|&b| {
- ConstantValue(cx.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b as u128))),
- ty: cx.tcx.types.bool
- }))
+ ConstantValue(ty::Const::from_bool(cx.tcx, b))
}).collect()
}
- ty::TyArray(ref sub_ty, len) if len.val.to_raw_bits().is_some() => {
- let len = len.val.unwrap_u64();
+ ty::TyArray(ref sub_ty, len) if len.assert_usize(cx.tcx).is_some() => {
+ let len = len.unwrap_usize(cx.tcx);
if len != 0 && cx.is_uninhabited(sub_ty) {
vec![]
} else {
for row in patterns {
match *row.kind {
PatternKind::Constant {
- value: &ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))),
- ty,
+ value: const_val @ &ty::Const {
+ val: ConstVal::Value(..),
+ ..
}
} => {
- let is_array_ptr = ty
- .builtin_deref(true)
- .and_then(|t| t.ty.builtin_index())
- .map_or(false, |t| t == cx.tcx.types.u8);
- if is_array_ptr {
- let alloc = cx.tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .unwrap();
- max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+ if let Some(ptr) = const_val.to_ptr() {
+ let is_array_ptr = const_val.ty
+ .builtin_deref(true)
+ .and_then(|t| t.ty.builtin_index())
+ .map_or(false, |t| t == cx.tcx.types.u8);
+ if is_array_ptr {
+ let alloc = cx.tcx
+ .interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .unwrap();
+ max_fixed_len = cmp::max(max_fixed_len, alloc.bytes.len() as u64);
+ }
}
}
PatternKind::Slice { ref prefix, slice: None, ref suffix } => {
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
///
/// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt,
pat: &Pattern<'tcx>,
pcx: PatternContext)
-> Option<Vec<Constructor<'tcx>>>
Some(vec![ConstantRange(lo, hi, end)]),
PatternKind::Array { .. } => match pcx.ty.sty {
ty::TyArray(_, length) => Some(vec![
- Slice(length.val.unwrap_u64())
+ Slice(length.unwrap_usize(cx.tcx))
]),
_ => span_bug!(pat.span, "bad ty {:?} for array pattern", pcx.ty)
},
}
}
-fn slice_pat_covered_by_constructor(tcx: TyCtxt, _span: Span,
- ctor: &Constructor,
- prefix: &[Pattern],
- slice: &Option<Pattern>,
- suffix: &[Pattern])
- -> Result<bool, ErrorReported> {
+fn slice_pat_covered_by_constructor<'tcx>(
+ tcx: TyCtxt<'_, 'tcx, '_>,
+ _span: Span,
+ ctor: &Constructor,
+ prefix: &[Pattern<'tcx>],
+ slice: &Option<Pattern<'tcx>>,
+ suffix: &[Pattern<'tcx>]
+) -> Result<bool, ErrorReported> {
let data: &[u8] = match *ctor {
- ConstantValue(&ty::Const { val: ConstVal::Value(
- Value::ByVal(PrimVal::Ptr(ptr))
- ), ty }) => {
- let is_array_ptr = ty
- .builtin_deref(true)
- .and_then(|t| t.ty.builtin_index())
- .map_or(false, |t| t == tcx.types.u8);
- assert!(is_array_ptr);
- tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .unwrap()
- .bytes
- .as_ref()
+ ConstantValue(const_val @ &ty::Const { val: ConstVal::Value(..), .. }) => {
+ if let Some(ptr) = const_val.to_ptr() {
+ let is_array_ptr = const_val.ty
+ .builtin_deref(true)
+ .and_then(|t| t.ty.builtin_index())
+ .map_or(false, |t| t == tcx.types.u8);
+ assert!(is_array_ptr);
+ tcx
+ .interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .unwrap()
+ .bytes
+ .as_ref()
+ } else {
+ bug!()
+ }
}
_ => bug!()
};
data[data.len()-suffix.len()..].iter().zip(suffix))
{
match pat.kind {
- box PatternKind::Constant { value } => match value.val {
- ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
- assert_eq!(b as u8 as u128, b);
- if b as u8 != *ch {
- return Ok(false);
- }
+ box PatternKind::Constant { value } => {
+ let b = value.unwrap_bits(pat.ty);
+ assert_eq!(b as u8 as u128, b);
+ if b as u8 != *ch {
+ return Ok(false);
}
- _ => span_bug!(pat.span, "bad const u8 {:?}", value)
- },
+ }
_ => {}
}
}
fn constructor_covered_by_range<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ctor: &Constructor,
- from: &ConstVal, to: &ConstVal,
+ ctor: &Constructor<'tcx>,
+ from: &'tcx ty::Const<'tcx>, to: &'tcx ty::Const<'tcx>,
end: RangeEnd,
ty: Ty<'tcx>,
) -> Result<bool, ErrorReported> {
}
match *ctor {
ConstantValue(value) => {
- let to = some_or_ok!(cmp_to(&value.val));
+ let to = some_or_ok!(cmp_to(value));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
- Ok(some_or_ok!(cmp_from(&value.val)) && end)
+ Ok(some_or_ok!(cmp_from(value)) && end)
},
ConstantRange(from, to, RangeEnd::Included) => {
- let to = some_or_ok!(cmp_to(&to.val));
+ let to = some_or_ok!(cmp_to(to));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Included && to == Ordering::Equal);
- Ok(some_or_ok!(cmp_from(&from.val)) && end)
+ Ok(some_or_ok!(cmp_from(from)) && end)
},
ConstantRange(from, to, RangeEnd::Excluded) => {
- let to = some_or_ok!(cmp_to(&to.val));
+ let to = some_or_ok!(cmp_to(to));
let end = (to == Ordering::Less) ||
(end == RangeEnd::Excluded && to == Ordering::Equal);
- Ok(some_or_ok!(cmp_from(&from.val)) && end)
+ Ok(some_or_ok!(cmp_from(from)) && end)
}
Single => Ok(true),
_ => bug!(),
PatternKind::Constant { value } => {
match *constructor {
- Slice(..) => match value.val {
- ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) => {
+ Slice(..) => {
+ if let Some(ptr) = value.to_ptr() {
let is_array_ptr = value.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
} else {
None
}
- }
- _ => span_bug!(pat.span,
+ } else {
+ span_bug!(pat.span,
"unexpected const-val {:?} with ctor {:?}", value, constructor)
+ }
},
_ => {
match constructor_covered_by_range(
cx.tcx,
- constructor, &value.val, &value.val, RangeEnd::Included,
+ constructor, value, value, RangeEnd::Included,
value.ty,
) {
Ok(true) => Some(vec![]),
PatternKind::Range { lo, hi, ref end } => {
match constructor_covered_by_range(
cx.tcx,
- constructor, &lo.val, &hi.val, end.clone(), lo.ty,
+ constructor, lo, hi, end.clone(), lo.ty,
) {
Ok(true) => Some(vec![]),
Ok(false) => None,
use interpret::{const_val_field, const_variant_index, self};
use rustc::middle::const_val::ConstVal;
-use rustc::mir::{Field, BorrowKind, Mutability};
-use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
+use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue};
use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
use rustc::ty::subst::{Substs, Kind};
use rustc::hir::{self, PatKind, RangeEnd};
fn print_const_val(value: &ty::Const, f: &mut fmt::Formatter) -> fmt::Result {
match value.val {
- ConstVal::Value(v) => print_miri_value(v, value.ty, f),
+ ConstVal::Value(..) => fmt_const_val(f, value),
ConstVal::Unevaluated(..) => bug!("{:?} not printable in a pattern", value)
}
}
-fn print_miri_value(value: Value, ty: Ty, f: &mut fmt::Formatter) -> fmt::Result {
- use rustc::ty::TypeVariants::*;
- match (value, &ty.sty) {
- (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"),
- (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"),
- (Value::ByVal(PrimVal::Bytes(n)), &TyUint(..)) => write!(f, "{:?}", n),
- (Value::ByVal(PrimVal::Bytes(n)), &TyInt(..)) => write!(f, "{:?}", n as i128),
- (Value::ByVal(PrimVal::Bytes(n)), &TyChar) =>
- write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
- _ => bug!("{:?}: {} not printable in a pattern", value, ty),
- }
-}
-
impl<'tcx> fmt::Display for Pattern<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self.kind {
(PatternKind::Constant { value: lo },
PatternKind::Constant { value: hi }) => {
use std::cmp::Ordering;
- match (end, compare_const_vals(self.tcx, &lo.val, &hi.val, ty).unwrap()) {
+ match (end, compare_const_vals(self.tcx, lo, hi, ty).unwrap()) {
(RangeEnd::Excluded, Ordering::Less) =>
PatternKind::Range { lo, hi, end },
(RangeEnd::Excluded, _) => {
ty::TyArray(_, len) => {
// fixed-length array
- let len = len.val.unwrap_u64();
+ let len = len.unwrap_usize(self.tcx);
assert!(len >= prefix.len() as u64 + suffix.len() as u64);
PatternKind::Array { prefix: prefix, slice: slice, suffix: suffix }
}
self.tables.local_id_root.expect("literal outside any scope"),
self.substs,
);
- let cv = self.tcx.mk_const(ty::Const { val, ty });
- *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+ *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
},
Err(()) => {
self.errors.push(PatternError::FloatBug);
self.tables.local_id_root.expect("literal outside any scope"),
self.substs,
);
- let cv = self.tcx.mk_const(ty::Const { val, ty });
- *self.const_to_pat(instance, cv, expr.hir_id, lit.span).kind
+ *self.const_to_pat(instance, val, expr.hir_id, lit.span).kind
},
Err(()) => {
self.errors.push(PatternError::FloatBug);
}
ty::TyArray(_, n) => {
PatternKind::Array {
- prefix: (0..n.val.unwrap_u64())
+ prefix: (0..n.unwrap_usize(self.tcx))
.map(|i| adt_subpattern(i as usize, None))
.collect(),
slice: None,
pub fn compare_const_vals<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- a: &ConstVal,
- b: &ConstVal,
+ a: &'tcx ty::Const<'tcx>,
+ b: &'tcx ty::Const<'tcx>,
ty: Ty<'tcx>,
) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
- use rustc::mir::interpret::{Value, PrimVal};
- match (a, b) {
- (&ConstVal::Value(Value::ByVal(PrimVal::Bytes(a))),
- &ConstVal::Value(Value::ByVal(PrimVal::Bytes(b)))) => {
- use ::rustc_apfloat::Float;
- match ty.sty {
- ty::TyFloat(ast::FloatTy::F32) => {
- let l = ::rustc_apfloat::ieee::Single::from_bits(a);
- let r = ::rustc_apfloat::ieee::Single::from_bits(b);
- l.partial_cmp(&r)
- },
- ty::TyFloat(ast::FloatTy::F64) => {
- let l = ::rustc_apfloat::ieee::Double::from_bits(a);
- let r = ::rustc_apfloat::ieee::Double::from_bits(b);
- l.partial_cmp(&r)
- },
- ty::TyInt(_) => {
- let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
- let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
- Some((a as i128).cmp(&(b as i128)))
- },
- _ => Some(a.cmp(&b)),
- }
- },
- _ if a == b => Some(Ordering::Equal),
- _ => None,
+ // FIXME: This should use assert_bits(ty) instead of use_bits
+ // but triggers possibly bugs due to mismatching of arrays and slices
+ if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
+ use ::rustc_apfloat::Float;
+ match ty.sty {
+ ty::TyFloat(ast::FloatTy::F32) => {
+ let l = ::rustc_apfloat::ieee::Single::from_bits(a);
+ let r = ::rustc_apfloat::ieee::Single::from_bits(b);
+ l.partial_cmp(&r)
+ },
+ ty::TyFloat(ast::FloatTy::F64) => {
+ let l = ::rustc_apfloat::ieee::Double::from_bits(a);
+ let r = ::rustc_apfloat::ieee::Double::from_bits(b);
+ l.partial_cmp(&r)
+ },
+ ty::TyInt(_) => {
+ let a = interpret::sign_extend(tcx, a, ty).expect("layout error for TyInt");
+ let b = interpret::sign_extend(tcx, b, ty).expect("layout error for TyInt");
+ Some((a as i128).cmp(&(b as i128)))
+ },
+ _ => Some(a.cmp(&b)),
+ }
+ } else {
+ if a == b {
+ Some(Ordering::Equal)
+ } else {
+ None
+ }
}
}
+// FIXME: Combine with rustc_mir::hair::cx::const_eval_literal
fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
neg: bool)
- -> Result<ConstVal<'tcx>, ()> {
+ -> Result<&'tcx ty::Const<'tcx>, ()> {
use syntax::ast::*;
use rustc::mir::interpret::*;
let s = s.as_str();
let id = tcx.allocate_cached(s.as_bytes());
let ptr = MemoryPointer::new(id, 0);
- Value::ByValPair(
+ ConstValue::ByValPair(
PrimVal::Ptr(ptr),
PrimVal::from_u128(s.len() as u128),
)
LitKind::ByteStr(ref data) => {
let id = tcx.allocate_cached(data);
let ptr = MemoryPointer::new(id, 0);
- Value::ByVal(PrimVal::Ptr(ptr))
+ ConstValue::ByVal(PrimVal::Ptr(ptr))
},
- LitKind::Byte(n) => Value::ByVal(PrimVal::Bytes(n as u128)),
+ LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)),
LitKind::Int(n, _) => {
enum Int {
Signed(IntTy),
ty::TyUint(other) => Int::Unsigned(other),
_ => bug!(),
};
+ // This converts from LitKind::Int (which is sign extended) to
+ // PrimVal::Bytes (which is zero extended)
let n = match ty {
// FIXME(oli-obk): are these casts correct?
Int::Signed(IntTy::I8) if neg =>
- (n as i128 as i8).overflowing_neg().0 as i128 as u128,
+ (n as i8).overflowing_neg().0 as u8 as u128,
Int::Signed(IntTy::I16) if neg =>
- (n as i128 as i16).overflowing_neg().0 as i128 as u128,
+ (n as i16).overflowing_neg().0 as u16 as u128,
Int::Signed(IntTy::I32) if neg =>
- (n as i128 as i32).overflowing_neg().0 as i128 as u128,
+ (n as i32).overflowing_neg().0 as u32 as u128,
Int::Signed(IntTy::I64) if neg =>
- (n as i128 as i64).overflowing_neg().0 as i128 as u128,
+ (n as i64).overflowing_neg().0 as u64 as u128,
Int::Signed(IntTy::I128) if neg =>
(n as i128).overflowing_neg().0 as u128,
- Int::Signed(IntTy::I8) => n as i128 as i8 as i128 as u128,
- Int::Signed(IntTy::I16) => n as i128 as i16 as i128 as u128,
- Int::Signed(IntTy::I32) => n as i128 as i32 as i128 as u128,
- Int::Signed(IntTy::I64) => n as i128 as i64 as i128 as u128,
- Int::Signed(IntTy::I128) => n,
- Int::Unsigned(UintTy::U8) => n as u8 as u128,
- Int::Unsigned(UintTy::U16) => n as u16 as u128,
- Int::Unsigned(UintTy::U32) => n as u32 as u128,
- Int::Unsigned(UintTy::U64) => n as u64 as u128,
- Int::Unsigned(UintTy::U128) => n,
+ Int::Signed(IntTy::I8) | Int::Unsigned(UintTy::U8) => n as u8 as u128,
+ Int::Signed(IntTy::I16) | Int::Unsigned(UintTy::U16) => n as u16 as u128,
+ Int::Signed(IntTy::I32) | Int::Unsigned(UintTy::U32) => n as u32 as u128,
+ Int::Signed(IntTy::I64) | Int::Unsigned(UintTy::U64) => n as u64 as u128,
+ Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
_ => bug!(),
};
- Value::ByVal(PrimVal::Bytes(n))
+ ConstValue::ByVal(PrimVal::Bytes(n))
},
LitKind::Float(n, fty) => {
parse_float(n, fty, neg)?
};
parse_float(n, fty, neg)?
}
- LitKind::Bool(b) => Value::ByVal(PrimVal::Bytes(b as u128)),
- LitKind::Char(c) => Value::ByVal(PrimVal::Bytes(c as u128)),
+ LitKind::Bool(b) => ConstValue::ByVal(PrimVal::Bytes(b as u128)),
+ LitKind::Char(c) => ConstValue::ByVal(PrimVal::Bytes(c as u128)),
};
- Ok(ConstVal::Value(lit))
+ Ok(ty::Const::from_const_value(tcx, lit, ty))
}
-pub fn parse_float(
+pub fn parse_float<'tcx>(
num: Symbol,
fty: ast::FloatTy,
neg: bool,
-) -> Result<Value, ()> {
+) -> Result<ConstValue<'tcx>, ()> {
let num = num.as_str();
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
}
};
- Ok(Value::ByVal(PrimVal::Bytes(bits)))
+ Ok(ConstValue::ByVal(PrimVal::Bytes(bits)))
}
use rustc::hir;
-use rustc::middle::const_val::{ConstEvalErr, ConstVal, ErrKind};
+use rustc::middle::const_val::{ConstEvalErr, ErrKind};
use rustc::middle::const_val::ErrKind::{TypeckError, CheckMatchError};
use rustc::mir;
use rustc::ty::{self, TyCtxt, Ty, Instance};
use syntax::ast::Mutability;
use syntax::codemap::Span;
+use syntax::codemap::DUMMY_SP;
-use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, MemoryPointer, Pointer, PrimVal, AllocId};
-use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory};
+use rustc::mir::interpret::{
+ EvalResult, EvalError, EvalErrorKind, GlobalId,
+ Value, Pointer, PrimVal, AllocId, Allocation, ConstValue,
+};
+use super::{Place, EvalContext, StackPopCleanup, ValTy, PlaceExtra, Memory, MemoryKind};
use std::fmt;
use std::error::Error;
}
pub fn eval_promoted<'a, 'mir, 'tcx>(
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
cid: GlobalId<'tcx>,
mir: &'mir mir::Mir<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<(Value, Pointer, Ty<'tcx>)> {
- let (res, ecx) = eval_body_and_ecx(tcx, cid, Some(mir), param_env);
- match res {
- Ok(val) => Some(val),
- Err(mut err) => {
- ecx.report(&mut err, false, None);
- None
+ ecx.with_fresh_body(|ecx| {
+ let res = eval_body_using_ecx(ecx, cid, Some(mir), param_env);
+ match res {
+ Ok(val) => Some(val),
+ Err(mut err) => {
+ ecx.report(&mut err, false, None);
+ None
+ }
}
- }
+ })
}
pub fn eval_body<'a, 'tcx>(
}
}
+pub fn value_to_const_value<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ val: Value,
+ ty: Ty<'tcx>,
+) -> &'tcx ty::Const<'tcx> {
+ let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
+
+ if layout.is_zst() {
+ return ty::Const::from_const_value(
+ tcx,
+ ConstValue::ByVal(PrimVal::Undef),
+ ty);
+ }
+
+ let val = match layout.abi {
+ layout::Abi::Scalar(..) => {
+ if let Value::ByVal(val) = val {
+ ConstValue::ByVal(val)
+ } else {
+ bug!("expected ByVal value, got {:?}", val);
+ }
+ }
+ layout::Abi::ScalarPair(..) => {
+ if let Value::ByValPair(a, b) = val {
+ ConstValue::ByValPair(a, b)
+ } else {
+ bug!("expected ByValPair value, got {:?}", val);
+ }
+ }
+ _ => {
+ if let Value::ByRef(ptr, align) = val {
+ let ptr = ptr.primval.to_ptr().unwrap();
+ assert_eq!(ptr.offset, 0);
+ let alloc = tcx.interpret_interner
+ .get_alloc(ptr.alloc_id)
+ .expect("miri allocation never successfully created");
+ assert_eq!(align, alloc.align);
+ ConstValue::ByRef(alloc)
+ } else {
+ bug!("expected ByRef value, got {:?}", val);
+ }
+ },
+ };
+ ty::Const::from_const_value(tcx, val, ty)
+}
+
fn eval_body_and_ecx<'a, 'mir, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cid: GlobalId<'tcx>,
mir: Option<&'mir mir::Mir<'tcx>>,
param_env: ty::ParamEnv<'tcx>,
) -> (EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
- debug!("eval_body: {:?}, {:?}", cid, param_env);
+ debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
// we start out with the best span we have
// and try improving it down the road when more information is available
let span = tcx.def_span(cid.instance.def_id());
- let mut span = mir.map(|mir| mir.span).unwrap_or(span);
+ let span = mir.map(|mir| mir.span).unwrap_or(span);
let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
- let res = (|| {
+ let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
+ (r, ecx)
+}
+
+fn eval_body_using_ecx<'a, 'mir, 'tcx>(
+ ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
+ cid: GlobalId<'tcx>,
+ mir: Option<&'mir mir::Mir<'tcx>>,
+ param_env: ty::ParamEnv<'tcx>,
+) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> {
+ debug!("eval_body: {:?}, {:?}", cid, param_env);
+ let tcx = ecx.tcx.tcx;
let mut mir = match mir {
Some(mir) => mir,
None => ecx.load_mir(cid.instance.def)?,
if let Some(index) = cid.promoted {
mir = &mir.promoted[index];
}
- span = mir.span;
let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
assert!(!layout.is_unsized());
let ptr = ecx.memory.allocate(
let ptr = ptr.into();
// always try to read the value and report errors
let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
- // if it's a constant (so it needs no address, directly compute its value)
- Some(val) if tcx.is_static(cid.instance.def_id()).is_none() => val,
+ Some(val) => val,
// point at the allocation
_ => Value::ByRef(ptr, layout.align),
};
Ok((value, ptr, layout.ty))
- })();
- (res, ecx)
}
pub struct CompileTimeEvaluator;
instance: ty::Instance<'tcx>,
variant: Option<usize>,
field: mir::Field,
- value: Value,
+ value: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> ::rustc::middle::const_val::EvalResult<'tcx> {
trace!("const_val_field: {:?}, {:?}, {:?}, {:?}", instance, field, value, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
let result = (|| {
+ let value = ecx.const_value_to_value(value, ty)?;
let (mut field, ty) = match value {
- Value::ByValPair(..) | Value::ByVal(_) => ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
+ Value::ByValPair(..) | Value::ByVal(_) =>
+ ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"),
Value::ByRef(ptr, align) => {
let place = Place::Ptr {
ptr,
Ok((field, ty))
})();
match result {
- Ok((field, ty)) => Ok(tcx.mk_const(ty::Const {
- val: ConstVal::Value(field),
- ty,
- })),
+ Ok((field, ty)) => Ok(value_to_const_value(tcx, field, ty)),
Err(err) => {
let (trace, span) = ecx.generate_stacktrace(None);
let err = ErrKind::Miri(err, trace);
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
- value: Value,
+ val: ConstValue<'tcx>,
ty: Ty<'tcx>,
) -> EvalResult<'tcx, usize> {
- trace!("const_variant_index: {:?}, {:?}, {:?}", instance, value, ty);
+ trace!("const_variant_index: {:?}, {:?}, {:?}", instance, val, ty);
let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
+ let value = ecx.const_value_to_value(val, ty)?;
let (ptr, align) = match value {
Value::ByValPair(..) | Value::ByVal(_) => {
let layout = ecx.layout_of(ty)?;
- use super::MemoryKind;
let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
let ptr: Pointer = ptr.into();
ecx.write_value_to_ptr(value, ptr, layout.align, ty)?;
ecx.read_discriminant_as_variant_index(place, ty)
}
+pub fn const_value_to_allocation_provider<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ (val, ty): (ConstValue<'tcx>, Ty<'tcx>),
+) -> &'tcx Allocation {
+ match val {
+ ConstValue::ByRef(alloc) => return alloc,
+ _ => ()
+ }
+ let result = || -> EvalResult<'tcx, &'tcx Allocation> {
+ let mut ecx = EvalContext::new(
+ tcx.at(DUMMY_SP),
+ ty::ParamEnv::reveal_all(),
+ CompileTimeEvaluator,
+ ());
+ let value = ecx.const_value_to_value(val, ty)?;
+ let layout = ecx.layout_of(ty)?;
+ let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?;
+ ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?;
+ let alloc = ecx.memory.get(ptr.alloc_id)?;
+ Ok(tcx.intern_const_alloc(alloc.clone()))
+ };
+ result().expect("unable to convert ConstVal to Allocation")
+}
+
pub fn const_eval_provider<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
let cid = key.value;
let def_id = cid.instance.def.def_id();
- if tcx.is_foreign_item(def_id) {
- let id = tcx.interpret_interner.cache_static(def_id);
- let ty = tcx.type_of(def_id);
- let layout = tcx.layout_of(key.param_env.and(ty)).unwrap();
- let ptr = MemoryPointer::new(id, 0);
- return Ok(tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByRef(ptr.into(), layout.align)),
- ty,
- }))
- }
-
if let Some(id) = tcx.hir.as_local_node_id(def_id) {
let tables = tcx.typeck_tables_of(def_id);
let span = tcx.def_span(def_id);
};
let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
- res.map(|(miri_value, _, miri_ty)| {
- tcx.mk_const(ty::Const {
- val: ConstVal::Value(miri_value),
- ty: miri_ty,
- })
+ res.map(|(val, _, miri_ty)| {
+ value_to_const_value(tcx, val, miri_ty)
}).map_err(|mut err| {
if tcx.is_static(def_id).is_some() {
ecx.report(&mut err, true, None);
use syntax::ast::Mutability;
use rustc::mir::interpret::{
GlobalId, Value, Pointer, PrimVal, PrimValKind,
- EvalError, EvalResult, EvalErrorKind, MemoryPointer,
+ EvalError, EvalResult, EvalErrorKind, MemoryPointer, ConstValue,
};
use std::mem;
pub ty: Ty<'tcx>,
}
-impl<'tcx> ValTy<'tcx> {
- pub fn from(val: &ty::Const<'tcx>) -> Option<Self> {
- match val.val {
- ConstVal::Value(value) => Some(ValTy { value, ty: val.ty }),
- ConstVal::Unevaluated { .. } => None,
- }
- }
-}
-
impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
type Target = Value;
fn deref(&self) -> &Value {
}
}
+const MAX_TERMINATORS: usize = 1_000_000;
+
impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
pub fn new(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
memory: Memory::new(tcx, memory_data),
stack: Vec::new(),
stack_limit: tcx.sess.const_eval_stack_frame_limit,
- terminators_remaining: 1_000_000,
+ terminators_remaining: MAX_TERMINATORS,
}
}
+ pub(crate) fn with_fresh_body<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R {
+ let stack = mem::replace(&mut self.stack, Vec::new());
+ let terminators_remaining = mem::replace(&mut self.terminators_remaining, MAX_TERMINATORS);
+ let r = f(self);
+ self.stack = stack;
+ self.terminators_remaining = terminators_remaining;
+ r
+ }
+
pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> {
let layout = self.layout_of(ty)?;
assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
))
}
- pub(super) fn const_to_value(&self, const_val: &ConstVal<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+ pub fn const_value_to_value(
+ &mut self,
+ val: ConstValue<'tcx>,
+ _ty: Ty<'tcx>,
+ ) -> EvalResult<'tcx, Value> {
+ match val {
+ ConstValue::ByRef(alloc) => {
+ // FIXME: Allocate new AllocId for all constants inside
+ let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?;
+ Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align))
+ },
+ ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)),
+ ConstValue::ByVal(val) => Ok(Value::ByVal(val)),
+ }
+ }
+
+ pub(super) fn const_to_value(
+ &mut self,
+ const_val: &ConstVal<'tcx>,
+ ty: Ty<'tcx>
+ ) -> EvalResult<'tcx, Value> {
match *const_val {
ConstVal::Unevaluated(def_id, substs) => {
let instance = self.resolve(def_id, substs)?;
promoted: None,
}, ty)
}
- ConstVal::Value(val) => Ok(val),
+ ConstVal::Value(val) => self.const_value_to_value(val, ty)
}
}
Repeat(ref operand, _) => {
let (elem_ty, length) = match dest_ty.sty {
- ty::TyArray(elem_ty, n) => (elem_ty, n.val.unwrap_u64()),
+ ty::TyArray(elem_ty, n) => (elem_ty, n.unwrap_usize(self.tcx.tcx)),
_ => {
bug!(
"tried to assign array-repeat to non-array type {:?}",
// FIXME(CTFE): don't allow computing the length of arrays in const eval
let src = self.eval_place(place)?;
let ty = self.place_ty(place);
- let (_, len) = src.elem_ty_and_len(ty);
+ let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
self.write_primval(
dest,
PrimVal::from_u128(len as u128),
Literal::Value { ref value } => self.const_to_value(&value.val, ty)?,
Literal::Promoted { index } => {
+ let instance = self.frame().instance;
self.read_global_as_value(GlobalId {
- instance: self.frame().instance,
+ instance,
promoted: Some(index),
}, ty)?
}
Ok(())
}
- pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+ pub fn read_global_as_value(&mut self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
if self.tcx.is_static(gid.instance.def_id()).is_some() {
let alloc_id = self
.tcx
}
}
- pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
- use syntax::ast::FloatTy;
-
- let layout = self.layout_of(ty)?;
- self.memory.check_align(ptr, ptr_align)?;
-
- if layout.size.bytes() == 0 {
- return Ok(Some(Value::ByVal(PrimVal::Undef)));
- }
-
- let ptr = ptr.to_ptr()?;
- let val = match ty.sty {
+ pub fn validate_ptr_target(
+ &self,
+ ptr: MemoryPointer,
+ ptr_align: Align,
+ ty: Ty<'tcx>
+ ) -> EvalResult<'tcx> {
+ match ty.sty {
ty::TyBool => {
let val = self.memory.read_primval(ptr, ptr_align, 1)?;
- let val = match val {
- PrimVal::Bytes(0) => false,
- PrimVal::Bytes(1) => true,
+ match val {
+ PrimVal::Bytes(0) | PrimVal::Bytes(1) => (),
// TODO: This seems a little overeager, should reading at bool type already be insta-UB?
_ => return err!(InvalidBool),
- };
- PrimVal::from_bool(val)
+ }
}
ty::TyChar => {
let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32;
match ::std::char::from_u32(c) {
- Some(ch) => PrimVal::from_char(ch),
+ Some(..) => (),
None => return err!(InvalidChar(c as u128)),
}
}
- ty::TyInt(int_ty) => {
- use syntax::ast::IntTy::*;
- let size = match int_ty {
- I8 => 1,
- I16 => 2,
- I32 => 4,
- I64 => 8,
- I128 => 16,
- Isize => self.memory.pointer_size(),
- };
- self.memory.read_primval(ptr, ptr_align, size)?
- }
-
- ty::TyUint(uint_ty) => {
- use syntax::ast::UintTy::*;
- let size = match uint_ty {
- U8 => 1,
- U16 => 2,
- U32 => 4,
- U64 => 8,
- U128 => 16,
- Usize => self.memory.pointer_size(),
- };
- self.memory.read_primval(ptr, ptr_align, size)?
- }
-
- ty::TyFloat(FloatTy::F32) => {
- PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()?)
- }
- ty::TyFloat(FloatTy::F64) => {
- PrimVal::Bytes(self.memory.read_primval(ptr, ptr_align, 8)?.to_bytes()?)
- }
-
- ty::TyFnPtr(_) => self.memory.read_ptr_sized(ptr, ptr_align)?,
+ ty::TyFnPtr(_) => {
+ self.memory.read_ptr_sized(ptr, ptr_align)?;
+ },
ty::TyRef(_, rty, _) |
ty::TyRawPtr(ty::TypeAndMut { ty: rty, .. }) => {
- return self.read_ptr(ptr, ptr_align, rty).map(Some)
+ self.read_ptr(ptr, ptr_align, rty)?;
}
ty::TyAdt(def, _) => {
if def.is_box() {
- return self.read_ptr(ptr, ptr_align, ty.boxed_ty()).map(Some);
+ self.read_ptr(ptr, ptr_align, ty.boxed_ty())?;
+ return Ok(());
}
if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi {
let size = scalar.value.size(self).bytes();
- self.memory.read_primval(ptr, ptr_align, size)?
- } else {
- return Ok(None);
+ self.memory.read_primval(ptr, ptr_align, size)?;
}
}
- _ => return Ok(None),
- };
+ _ => (),
+ }
+ Ok(())
+ }
+
+ pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
+ let layout = self.layout_of(ty)?;
+ self.memory.check_align(ptr, ptr_align)?;
- Ok(Some(Value::ByVal(val)))
+ if layout.size.bytes() == 0 {
+ return Ok(Some(Value::ByVal(PrimVal::Undef)));
+ }
+
+ let ptr = ptr.to_ptr()?;
+
+ // Not the right place to do this
+ //self.validate_ptr_target(ptr, ptr_align, ty)?;
+
+ match layout.abi {
+ layout::Abi::Scalar(..) => {
+ let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?;
+ Ok(Some(Value::ByVal(primval)))
+ }
+ layout::Abi::ScalarPair(ref a, ref b) => {
+ let (a, b) = (&a.value, &b.value);
+ let (a_size, b_size) = (a.size(self), b.size(self));
+ let a_ptr = ptr;
+ let b_offset = a_size.abi_align(b.align(self));
+ let b_ptr = ptr.offset(b_offset.bytes(), self)?.into();
+ let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?;
+ let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?;
+ Ok(Some(Value::ByValPair(a_val, b_val)))
+ }
+ _ => Ok(None),
+ }
}
pub fn frame(&self) -> &Frame<'mir, 'tcx> {
let ptr = self.into_ptr(src)?;
// u64 cast is from usize to u64, which is always good
let valty = ValTy {
- value: ptr.to_value_with_len(length.val.unwrap_u64() ),
+ value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)),
ty: dest_ty,
};
self.write_value(valty, dest)
-use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
-use std::collections::{btree_map, BTreeMap, VecDeque};
-use std::{ptr, io};
+use std::collections::{btree_map, VecDeque};
+use std::ptr;
+use rustc::hir::def_id::DefId;
use rustc::ty::Instance;
+use rustc::ty::ParamEnv;
use rustc::ty::maps::TyCtxtAt;
use rustc::ty::layout::{self, Align, TargetDataLayout};
use syntax::ast::Mutability;
+use rustc::middle::const_val::{ConstVal, ErrKind};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
-use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer,
- EvalResult, PrimVal, EvalErrorKind};
+use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, Value, Pointer,
+ EvalResult, PrimVal, EvalErrorKind, GlobalId};
+pub use rustc::mir::interpret::{write_target_uint, write_target_int, read_target_uint};
use super::{EvalContext, Machine};
}
/// kind is `None` for statics
- pub fn allocate(
+ pub fn allocate_value(
&mut self,
- size: u64,
- align: Align,
+ alloc: Allocation,
kind: Option<MemoryKind<M::MemoryKinds>>,
- ) -> EvalResult<'tcx, MemoryPointer> {
- assert_eq!(size as usize as u64, size);
- let alloc = Allocation {
- bytes: vec![0; size as usize],
- relocations: BTreeMap::new(),
- undef_mask: UndefMask::new(size),
- align,
- runtime_mutability: Mutability::Immutable,
- };
+ ) -> EvalResult<'tcx, AllocId> {
let id = self.tcx.interpret_interner.reserve();
M::add_lock(self, id);
match kind {
self.uninitialized_statics.insert(id, alloc);
},
}
+ Ok(id)
+ }
+
+ /// kind is `None` for statics
+ pub fn allocate(
+ &mut self,
+ size: u64,
+ align: Align,
+ kind: Option<MemoryKind<M::MemoryKinds>>,
+ ) -> EvalResult<'tcx, MemoryPointer> {
+ let id = self.allocate_value(Allocation::undef(size, align), kind)?;
Ok(MemoryPointer::new(id, 0))
}
/// Allocation accessors
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+ fn const_eval_static(&self, def_id: DefId) -> EvalResult<'tcx, &'tcx Allocation> {
+ let instance = Instance::mono(self.tcx.tcx, def_id);
+ let gid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ self.tcx.const_eval(ParamEnv::reveal_all().and(gid)).map_err(|err| {
+ match *err.kind {
+ ErrKind::Miri(ref err, _) => match err.kind {
+ EvalErrorKind::TypeckError |
+ EvalErrorKind::Layout(_) => EvalErrorKind::TypeckError.into(),
+ _ => EvalErrorKind::ReferencedConstant.into(),
+ },
+ ErrKind::TypeckError => EvalErrorKind::TypeckError.into(),
+ ref other => bug!("const eval returned {:?}", other),
+ }
+ }).map(|val| {
+ let const_val = match val.val {
+ ConstVal::Value(val) => val,
+ ConstVal::Unevaluated(..) => bug!("should be evaluated"),
+ };
+ self.tcx.const_value_to_allocation((const_val, val.ty))
+ })
+ }
+
pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
// normal alloc?
match self.alloc_map.get(&id) {
Some(alloc) => Ok(alloc),
None => {
// static alloc?
- self.tcx.interpret_interner.get_alloc(id)
- // no alloc? produce an error
- .ok_or_else(|| if self.tcx.interpret_interner.get_fn(id).is_some() {
- EvalErrorKind::DerefFunctionPointer.into()
- } else {
- EvalErrorKind::DanglingPointerDeref.into()
- })
+ if let Some(a) = self.tcx.interpret_interner.get_alloc(id) {
+ return Ok(a);
+ }
+ // static variable?
+ if let Some(did) = self.tcx.interpret_interner.get_static(id) {
+ return self.const_eval_static(did);
+ }
+ // otherwise return an error
+ Err(if self.tcx.interpret_interner.get_fn(id).is_some() {
+ EvalErrorKind::DerefFunctionPointer.into()
+ } else {
+ EvalErrorKind::DanglingPointerDeref.into()
+ })
},
},
}
}
}
-////////////////////////////////////////////////////////////////////////////////
-// Methods to access integers in the target endianness
-////////////////////////////////////////////////////////////////////////////////
-
-pub fn write_target_uint(
- endianness: layout::Endian,
- mut target: &mut [u8],
- data: u128,
-) -> Result<(), io::Error> {
- let len = target.len();
- match endianness {
- layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
- layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
- }
-}
-
-pub fn write_target_int(
- endianness: layout::Endian,
- mut target: &mut [u8],
- data: i128,
-) -> Result<(), io::Error> {
- let len = target.len();
- match endianness {
- layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
- layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
- }
-}
-
-pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
- match endianness {
- layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
- layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
// Unaligned accesses
////////////////////////////////////////////////////////////////////////////////
mk_borrowck_eval_cx,
eval_body,
CompileTimeEvaluator,
+ const_value_to_allocation_provider,
const_eval_provider,
const_val_field,
const_variant_index,
+ value_to_const_value,
};
pub use self::machine::Machine;
use rustc::mir;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx;
self.to_ptr_align().0.to_ptr()
}
- pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) {
+ pub(super) fn elem_ty_and_len(
+ self,
+ ty: Ty<'tcx>,
+ tcx: TyCtxt<'_, 'tcx, '_>
+ ) -> (Ty<'tcx>, u64) {
match ty.sty {
- ty::TyArray(elem, n) => (elem, n.val.unwrap_u64() as u64),
+ ty::TyArray(elem, n) => (elem, n.unwrap_usize(tcx)),
ty::TySlice(elem) => {
match self {
let base = self.force_allocation(base)?;
let (base_ptr, align) = base.to_ptr_align();
- let (elem_ty, len) = base.elem_ty_and_len(outer_ty);
+ let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx);
let elem_size = self.layout_of(elem_ty)?.size.bytes();
assert!(
n < len,
let base = self.force_allocation(base)?;
let (base_ptr, align) = base.to_ptr_align();
- let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+ let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
let elem_size = self.layout_of(elem_ty)?.size.bytes();
assert!(n >= min_length as u64);
let base = self.force_allocation(base)?;
let (base_ptr, align) = base.to_ptr_align();
- let (elem_ty, n) = base.elem_ty_and_len(base_ty);
+ let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx);
let elem_size = self.layout_of(elem_ty)?.size.bytes();
assert!(u64::from(from) <= n - u64::from(to));
let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
shim::provide(providers);
transform::provide(providers);
providers.const_eval = interpret::const_eval_provider;
+ providers.const_value_to_allocation = interpret::const_value_to_allocation_provider;
providers.check_match = hair::pattern::check_match;
}
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer};
+use rustc::mir::interpret::{AllocId, ConstValue};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::ty::subst::{Substs, Kind};
-use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
+use rustc::ty::{self, TypeFoldable, Ty, TyCtxt, GenericParamDefKind};
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::session::config;
use rustc::mir::{self, Location, Promoted};
use rustc::mir::visit::Visitor as MirVisitor;
use rustc::mir::mono::MonoItem;
-use rustc::mir::interpret::GlobalId;
+use rustc::mir::interpret::{PrimVal, GlobalId};
use monomorphize::{self, Instance};
use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
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(),
};
match val {
ConstVal::Unevaluated(..) => bug!("const eval yielded unevaluated const"),
- ConstVal::Value(Value::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
+ ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(a), PrimVal::Ptr(b))) => {
collect_miri(tcx, a.alloc_id, output);
collect_miri(tcx, b.alloc_id, output);
}
- ConstVal::Value(Value::ByValPair(_, PrimVal::Ptr(ptr))) |
- ConstVal::Value(Value::ByValPair(PrimVal::Ptr(ptr), _)) |
- ConstVal::Value(Value::ByVal(PrimVal::Ptr(ptr))) =>
+ ConstVal::Value(ConstValue::ByValPair(_, PrimVal::Ptr(ptr))) |
+ ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) |
+ ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) =>
collect_miri(tcx, ptr.alloc_id, output),
- ConstVal::Value(Value::ByRef(Pointer { primval: PrimVal::Ptr(ptr) }, _)) => {
- // by ref should only collect the inner allocation, not the value itself
- let alloc = tcx
- .interpret_interner
- .get_alloc(ptr.alloc_id)
- .expect("ByRef to extern static is not allowed");
- for &inner in alloc.relocations.values() {
- collect_miri(tcx, inner, output);
+ ConstVal::Value(ConstValue::ByRef(alloc)) => {
+ for &id in alloc.relocations.values() {
+ collect_miri(tcx, id, output);
}
}
_ => {},
ty::TyArray(inner_type, len) => {
output.push('[');
self.push_type_name(inner_type, output);
- write!(output, "; {}",
- len.val.unwrap_u64()).unwrap();
+ write!(output, "; {}", len.unwrap_usize(self.tcx)).unwrap();
output.push(']');
},
ty::TySlice(inner_type) => {
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer;
-use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::ty::maps::Providers;
-use rustc::mir::interpret::{Value, PrimVal};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
match self_ty.sty {
_ if is_copy => builder.copy_shim(),
ty::TyArray(ty, len) => {
- let len = len.val.unwrap_u64();
+ let len = len.unwrap_usize(tcx);
builder.array_shim(dest, src, ty, len)
}
ty::TyClosure(def_id, substs) => {
) {
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);
span: self.span,
ty: func_ty,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty: func_ty
- }),
+ value: ty::Const::zero_sized(self.tcx, func_ty)
},
});
span: self.span,
ty: self.tcx.types.usize,
literal: Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(value.into()))),
- ty: self.tcx.types.usize,
- })
+ value: ty::Const::from_usize(self.tcx, value),
}
}
}
span,
ty,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- // ZST function type
- val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
- ty
- }),
+ value: ty::Const::zero_sized(tcx, ty)
},
}),
vec![rcvr])
// 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 {
use rustc::mir::visit::{Visitor, PlaceContext};
use rustc::middle::const_val::ConstVal;
use rustc::ty::{TyCtxt, self, Instance};
-use rustc::mir::interpret::{Value, PrimVal, GlobalId};
+use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult};
+use interpret::EvalContext;
+use interpret::CompileTimeEvaluator;
use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
use transform::{MirPass, MirSource};
-use syntax::codemap::Span;
+use syntax::codemap::{Span, DUMMY_SP};
use rustc::ty::subst::Substs;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc::ty::ParamEnv;
use rustc::ty::layout::{
- LayoutOf, TyLayout, LayoutError,
+ LayoutOf, TyLayout, LayoutError, LayoutCx,
HasTyCtxt, TargetDataLayout, HasDataLayout,
};
/// Finds optimization opportunities on the MIR.
struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
+ ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>,
mir: &'b Mir<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource,
source: MirSource,
) -> ConstPropagator<'b, 'a, 'tcx> {
let param_env = tcx.param_env(source.def_id);
+ let substs = Substs::identity_for_item(tcx, source.def_id);
+ let instance = Instance::new(source.def_id, substs);
+ let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
ConstPropagator {
+ ecx,
mir,
tcx,
source,
}
}
- fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
+ fn use_ecx<F, T>(
+ &mut self,
+ span: Span,
+ f: F
+ ) -> Option<T>
+ where
+ F: FnOnce(&mut Self) -> EvalResult<'tcx, T>,
+ {
+ self.ecx.tcx.span = span;
+ let r = match f(self) {
+ Ok(val) => Some(val),
+ Err(mut err) => {
+ self.ecx.report(&mut err, false, Some(span));
+ None
+ },
+ };
+ self.ecx.tcx.span = DUMMY_SP;
+ r
+ }
+
+ fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
let value = match self.tcx.const_eval(self.param_env.and(cid)) {
Ok(val) => val,
Err(err) => {
},
};
let val = match value.val {
- ConstVal::Value(v) => v,
+ ConstVal::Value(v) => {
+ self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))?
+ },
_ => bug!("eval produced: {:?}", value),
};
let val = (val, value.ty, span);
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
match c.literal {
Literal::Value { value } => match value.val {
- ConstVal::Value(v) => Some((v, value.ty, c.span)),
+ ConstVal::Value(v) => {
+ let v = self.use_ecx(c.span, |this| {
+ this.ecx.const_value_to_value(v, value.ty)
+ })?;
+ Some((v, value.ty, c.span))
+ },
ConstVal::Unevaluated(did, substs) => {
let instance = Instance::resolve(
self.tcx,
// 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;
}
};
// cannot use `const_eval` here, because that would require having the MIR
// for the current function available, but we're producing said MIR right now
- let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
+ let span = self.mir.span;
+ let (value, _, ty) = self.use_ecx(span, |this| {
+ Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env))
+ })??;
let val = (value, ty, c.span);
trace!("evaluated {:?} to {:?}", c, val);
Some(val)
use rustc_data_structures::indexed_vec::Idx;
let field_index = field.index();
let val = [a, b][field_index];
- let field = base_layout.field(&*self, field_index).ok()?;
+ let cx = LayoutCx {
+ tcx: self.tcx,
+ param_env: self.param_env,
+ };
+ let field = base_layout.field(cx, field_index).ok()?;
trace!("projection resulted in: {:?}", val);
Some((Value::ByVal(val), field.ty, span))
},
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;
}
- let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
- let instance = Instance::new(self.source.def_id, substs);
- let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
let val = self.eval_operand(arg)?;
- let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
- match ecx.unary_op(op, prim, val.1) {
- Ok(val) => Some((Value::ByVal(val), place_ty, span)),
- Err(mut err) => {
- ecx.report(&mut err, false, Some(span));
- None
- },
- }
+ let prim = self.use_ecx(span, |this| {
+ this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 })
+ })?;
+ let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?;
+ Some((Value::ByVal(val), place_ty, span))
}
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
Rvalue::BinaryOp(op, ref left, ref right) => {
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;
}
- let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
- let instance = Instance::new(self.source.def_id, substs);
- let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
- let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
+ let r = self.use_ecx(span, |this| {
+ this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
+ })?;
if op == BinOp::Shr || op == BinOp::Shl {
let param_env = self.tcx.param_env(self.source.def_id);
let left_ty = left.ty(self.mir, self.tcx);
}
}
let left = self.eval_operand(left)?;
- let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
+ let l = self.use_ecx(span, |this| {
+ this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 })
+ })?;
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
- match ecx.binary_op(op, l, left.1, r, right.1) {
- Ok((val, overflow)) => {
- let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
- Value::ByValPair(
- val,
- PrimVal::from_bool(overflow),
- )
- } else {
- if overflow {
- use rustc::mir::interpret::EvalErrorKind;
- let mut err = EvalErrorKind::Overflow(op).into();
- ecx.report(&mut err, false, Some(span));
- return None;
- }
- Value::ByVal(val)
- };
- Some((val, place_ty, span))
- },
- Err(mut err) => {
- ecx.report(&mut err, false, Some(span));
- None
- },
- }
+ let (val, overflow) = self.use_ecx(span, |this| {
+ this.ecx.binary_op(op, l, left.1, r, right.1)
+ })?;
+ let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
+ Value::ByValPair(
+ val,
+ PrimVal::from_bool(overflow),
+ )
+ } else {
+ if overflow {
+ use rustc::mir::interpret::EvalErrorKind;
+ let mut err = EvalErrorKind::Overflow(op).into();
+ self.use_ecx(span, |this| {
+ this.ecx.report(&mut err, false, Some(span));
+ Ok(())
+ });
+ return None;
+ }
+ Value::ByVal(val)
+ };
+ Some((val, place_ty, span))
},
}
}
use dataflow::{self, do_dataflow, DebugFormatted};
use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
-use rustc::mir::interpret::{Value, PrimVal};
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_set::IdxSetBuf;
use rustc_data_structures::indexed_vec::Idx;
}
impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> {
- fn fmt(&self, _f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
span,
ty: self.tcx.types.bool,
literal: Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
- ty: self.tcx.types.bool
- })
+ value: ty::Const::from_bool(self.tcx, val)
}
})))
}
use rustc::hir;
use rustc::hir::def_id::DefId;
-use rustc::middle::const_val::ConstVal;
use rustc::mir::*;
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
use rustc::ty::{self, TyCtxt, AdtDef, Ty};
use transform::no_landing_pads::no_landing_pads;
use dataflow::{do_dataflow, DebugFormatted, state_for_location};
use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
-use rustc::mir::interpret::{Value, PrimVal};
pub struct StateTransform;
span: source_info.span,
ty: self.tcx.types.u32,
literal: Literal::Value {
- value: self.tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))),
- ty: self.tcx.types.u32
- }),
+ value: ty::Const::from_bits(
+ self.tcx,
+ state_disc.into(),
+ self.tcx.types.u32),
},
});
Statement {
span: mir.span,
ty: tcx.types.bool,
literal: Literal::Value {
- value: tcx.mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
- ty: tcx.types.bool
- }),
+ value: ty::Const::from_bool(tcx, false),
},
}),
expected: true,
}
Operand::Constant(ref constant) => {
if let Literal::Value {
- value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
+ value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. }
} = constant.literal {
// Don't peek inside trait associated constants.
if self.tcx.trait_of_item(def_id).is_some() {
_ => false
}
} else if let ty::TyArray(_, len) = ty.sty {
- len.val.unwrap_u64() == 0 &&
+ len.unwrap_usize(self.tcx) == 0 &&
self.mode == Mode::Fn
} else {
false
//! A pass that simplifies branches when their condition is known.
-use rustc::ty::{self, TyCtxt};
-use rustc::middle::const_val::ConstVal;
+use rustc::ty::TyCtxt;
use rustc::mir::*;
-use rustc::mir::interpret::{Value, PrimVal};
use transform::{MirPass, MirSource};
use std::borrow::Cow;
}
fn run_pass<'a, 'tcx>(&self,
- _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
_src: MirSource,
mir: &mut Mir<'tcx>) {
for block in mir.basic_blocks_mut() {
terminator.kind = match terminator.kind {
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
literal: Literal::Value { ref value }, ..
- }), ref values, ref targets, .. } => {
- if let Some(constint) = value.val.to_raw_bits() {
+ }), switch_ty, ref values, ref targets, .. } => {
+ if let Some(constint) = value.assert_bits(switch_ty) {
let (otherwise, targets) = targets.split_last().unwrap();
let mut ret = TerminatorKind::Goto { target: *otherwise };
for (&v, t) in values.iter().zip(targets.iter()) {
},
TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
literal: Literal::Value {
- value: &ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
- .. }
+ value
}, ..
- }), expected, .. } if (cond == 1) == expected => {
- assert!(cond <= 1);
+ }), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
TerminatorKind::Goto { target: target }
},
TerminatorKind::FalseEdges { real_target, .. } => {
} else {
let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
if let ty::TyArray(item_ty, const_size) = place_ty.sty {
- if let Some(size) = const_size.val.to_raw_bits() {
- assert!(size <= (u32::max_value() as u128),
- "unform array move out doesn't supported
+ if let Some(size) = const_size.assert_usize(self.tcx) {
+ assert!(size <= u32::max_value() as u64,
+ "uniform array move out doesn't supported
for array bigger then u32");
self.uniform(location, dst_place, proj, item_ty, size as u32);
}
let opt_size = opt_src_place.and_then(|src_place| {
let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
if let ty::TyArray(_, ref size_o) = src_ty.sty {
- size_o.val.to_raw_bits().map(|n| n as u64)
+ size_o.assert_usize(tcx)
} else {
None
}
use std::fmt;
use rustc::hir;
use rustc::mir::*;
-use rustc::middle::const_val::ConstVal;
use rustc::middle::lang_items;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::util::IntTypeExt;
use rustc_data_structures::indexed_vec::Idx;
use util::patch::MirPatch;
-use rustc::mir::interpret::{Value, PrimVal};
use std::{iter, u32};
let succ = self.succ;
self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
}
- ty::TyArray(ety, size) => self.open_drop_for_array(
- ety, size.val.to_raw_bits().map(|i| i as u64)),
+ ty::TyArray(ety, size) => {
+ let size = size.assert_usize(self.tcx());
+ self.open_drop_for_array(ety, size)
+ },
ty::TySlice(ety) => self.open_drop_for_array(ety, None),
_ => bug!("open drop from non-ADT `{:?}`", ty)
span: self.source_info.span,
ty: self.tcx().types.usize,
literal: Literal::Value {
- value: self.tcx().mk_const(ty::Const {
- val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val.into()))),
- ty: self.tcx().types.usize
- })
+ value: ty::Const::from_usize(self.tcx(), val.into())
}
})
}
fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
self.super_const(constant);
- let ty::Const { ty, val } = constant;
+ let ty::Const { ty, val, .. } = constant;
self.push(&format!("ty::Const"));
self.push(&format!("+ ty: {:?}", ty));
self.push(&format!("+ val: {:?}", val));
}
}
- /// 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?
self.with_context(Closure, |v| v.visit_nested_body(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,
- }
- }
+ 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 {
self.require_loop("break", e.span);
}
hir::ExprAgain(label) => {
- if let hir::ScopeTarget::Loop(
- hir::LoopIdResult::Err(
- hir::LoopIdError::UnlabeledCfInWhileCondition)) = label.target_id {
+ if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.target_id {
self.emit_unlabled_cf_in_while_condition(e.span, "continue");
}
self.require_loop("continue", e.span)
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);
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]
align,
}
}
-
- pub fn uninhabited(field_count: usize) -> Self {
- let align = Align::from_bytes(1, 1).unwrap();
- LayoutDetails {
- variants: Variants::Single { index: 0 },
- fields: FieldPlacement::Union(field_count),
- abi: Abi::Uninhabited,
- align,
- size: Size::from_bytes(0)
- }
- }
}
/// The details of the layout of a type, alongside the type itself.
/// Returns true if the type is a ZST and not unsized.
pub fn is_zst(&self) -> bool {
match self.abi {
- Abi::Uninhabited => true,
Abi::Scalar(_) |
Abi::ScalarPair(..) |
Abi::Vector { .. } => false,
+ Abi::Uninhabited => self.size.bytes() == 0,
Abi::Aggregate { sized } => sized && self.size.bytes() == 0
}
}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+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 {
// Make sure that the linker/gcc really don't pull in anything, including
// default objects, libs, etc.
- base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
+ base.pre_link_args_crt.insert(LinkerFlavor::Gcc, Vec::new());
+ base.pre_link_args_crt.get_mut(&LinkerFlavor::Gcc).unwrap().push("-nostdlib".to_string());
// At least when this was tested, the linker would not add the
// `GNU_EH_FRAME` program header to executables generated, which is required
//
// Each target directory for musl has these object files included in it so
// they'll be included from there.
- base.pre_link_objects_exe.push("crt1.o".to_string());
- base.pre_link_objects_exe.push("crti.o".to_string());
- base.post_link_objects.push("crtn.o".to_string());
+ base.pre_link_objects_exe_crt.push("crt1.o".to_string());
+ base.pre_link_objects_exe_crt.push("crti.o".to_string());
+ base.pre_link_objects_exe_crt_sys.push("crtbegin.o".to_string());
+ base.post_link_objects_crt_sys.push("crtend.o".to_string());
+ base.post_link_objects_crt.push("crtn.o".to_string());
// These targets statically link libc by default
base.crt_static_default = true;
("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),
/// Linker to invoke
pub linker: Option<String>,
- /// Linker arguments that are unconditionally passed *before* any
- /// user-defined libraries.
- pub pre_link_args: LinkArgs,
- /// Objects to link before all others, always found within the
+ /// Linker arguments that are passed *before* any user-defined libraries.
+ pub pre_link_args: LinkArgs, // ... unconditionally
+ pub pre_link_args_crt: LinkArgs, // ... when linking with a bundled crt
+ /// Objects to link before all others, all except *_sys found within the
/// sysroot folder.
- pub pre_link_objects_exe: Vec<String>, // ... when linking an executable
+ pub pre_link_objects_exe: Vec<String>, // ... when linking an executable, unconditionally
+ pub pre_link_objects_exe_crt: Vec<String>, // ... when linking an executable with a bundled crt
+ pub pre_link_objects_exe_crt_sys: Vec<String>, // ... when linking an executable with a bundled
+ // crt, from the system library search path
pub pre_link_objects_dll: Vec<String>, // ... when linking a dylib
/// Linker arguments that are unconditionally passed after any
/// user-defined but before post_link_objects. Standard platform
/// libraries that should be always be linked to, usually go here.
pub late_link_args: LinkArgs,
- /// Objects to link after all others, always found within the
+ /// Objects to link after all others, all except *_sys found within the
/// sysroot folder.
- pub post_link_objects: Vec<String>,
+ pub post_link_objects: Vec<String>, // ... unconditionally
+ pub post_link_objects_crt: Vec<String>, // ... when linking with a bundled crt
+ pub post_link_objects_crt_sys: Vec<String>, // ... when linking with a bundled crt, from the
+ // system library search path
/// Linker arguments that are unconditionally passed *after* any
/// user-defined libraries.
pub post_link_args: LinkArgs,
is_builtin: false,
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.to_string()),
pre_link_args: LinkArgs::new(),
+ pre_link_args_crt: LinkArgs::new(),
post_link_args: LinkArgs::new(),
asm_args: Vec::new(),
cpu: "generic".to_string(),
position_independent_executables: false,
relro_level: RelroLevel::None,
pre_link_objects_exe: Vec::new(),
+ pre_link_objects_exe_crt: Vec::new(),
+ pre_link_objects_exe_crt_sys: Vec::new(),
pre_link_objects_dll: Vec::new(),
post_link_objects: Vec::new(),
+ post_link_objects_crt: Vec::new(),
+ post_link_objects_crt_sys: Vec::new(),
late_link_args: LinkArgs::new(),
link_env: Vec::new(),
archive_format: "gnu".to_string(),
key!(is_builtin, bool);
key!(linker, optional);
key!(pre_link_args, link_args);
+ key!(pre_link_args_crt, link_args);
key!(pre_link_objects_exe, list);
+ key!(pre_link_objects_exe_crt, list);
+ key!(pre_link_objects_exe_crt_sys, list);
key!(pre_link_objects_dll, list);
key!(late_link_args, link_args);
key!(post_link_objects, list);
+ key!(post_link_objects_crt, list);
+ key!(post_link_objects_crt_sys, list);
key!(post_link_args, link_args);
key!(link_env, env);
key!(asm_args, list);
target_option_val!(is_builtin);
target_option_val!(linker);
target_option_val!(link_args - pre_link_args);
+ target_option_val!(link_args - pre_link_args_crt);
target_option_val!(pre_link_objects_exe);
+ target_option_val!(pre_link_objects_exe_crt);
+ target_option_val!(pre_link_objects_exe_crt_sys);
target_option_val!(pre_link_objects_dll);
target_option_val!(link_args - late_link_args);
target_option_val!(post_link_objects);
+ target_option_val!(post_link_objects_crt);
+ target_option_val!(post_link_objects_crt_sys);
target_option_val!(link_args - post_link_args);
target_option_val!(env - link_env);
target_option_val!(asm_args);
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);
}
if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) {
cmd.args(args);
}
+ if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) {
+ if sess.crt_static() {
+ cmd.args(args);
+ }
+ }
if let Some(ref args) = sess.opts.debugging_opts.pre_link_args {
cmd.args(args);
}
cmd.arg(root.join(obj));
}
+ if crate_type == config::CrateTypeExecutable && sess.crt_static() {
+ for obj in &sess.target.target.options.pre_link_objects_exe_crt {
+ cmd.arg(root.join(obj));
+ }
+
+ for obj in &sess.target.target.options.pre_link_objects_exe_crt_sys {
+ if flavor == LinkerFlavor::Gcc {
+ cmd.arg(format!("-l:{}", obj));
+ }
+ }
+ }
+
if sess.target.target.options.is_like_emscripten {
cmd.arg("-s");
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
for obj in &sess.target.target.options.post_link_objects {
cmd.arg(root.join(obj));
}
+ if sess.crt_static() {
+ for obj in &sess.target.target.options.post_link_objects_crt_sys {
+ if flavor == LinkerFlavor::Gcc {
+ cmd.arg(format!("-l:{}", obj));
+ }
+ }
+ for obj in &sess.target.target.options.post_link_objects_crt {
+ cmd.arg(root.join(obj));
+ }
+ }
if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) {
cmd.args(args);
}
out_filename: &Path,
trans: &CrateTranslation) {
+ // Linker plugins should be specified early in the list of arguments
+ cmd.cross_lang_lto();
+
// The default library location, we need this to find the runtime.
// The location of crates will be determined as needed.
let lib_path = sess.target_filesearch(PathKind::All).get_lib_path();
use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
use rustc::middle::dependency_format::Linkage;
use rustc::session::Session;
-use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
+use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel,
+ CrossLangLto};
use rustc::ty::TyCtxt;
use rustc_target::spec::{LinkerFlavor, LldFlavor};
use serialize::{json, Encoder};
fn subsystem(&mut self, subsystem: &str);
fn group_start(&mut self);
fn group_end(&mut self);
+ fn cross_lang_lto(&mut self);
// Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
fn finalize(&mut self) -> Command;
}
self.linker_arg("--end-group");
}
}
+
+ fn cross_lang_lto(&mut self) {
+ match self.sess.opts.debugging_opts.cross_lang_lto {
+ CrossLangLto::Disabled |
+ CrossLangLto::NoLink => {
+ // Nothing to do
+ }
+ CrossLangLto::LinkerPlugin(ref path) => {
+ self.linker_arg(&format!("-plugin={}", path.display()));
+
+ let opt_level = match self.sess.opts.optimize {
+ config::OptLevel::No => "O0",
+ config::OptLevel::Less => "O1",
+ config::OptLevel::Default => "O2",
+ config::OptLevel::Aggressive => "O3",
+ config::OptLevel::Size => "Os",
+ config::OptLevel::SizeMin => "Oz",
+ };
+
+ self.linker_arg(&format!("-plugin-opt={}", opt_level));
+ self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu()));
+
+ match self.sess.opts.cg.lto {
+ config::Lto::Thin |
+ config::Lto::ThinLocal => {
+ self.linker_arg(&format!("-plugin-opt=thin"));
+ }
+ config::Lto::Fat |
+ config::Lto::Yes |
+ config::Lto::No => {
+ // default to regular LTO
+ }
+ }
+ }
+ }
+ }
}
pub struct MsvcLinker<'a> {
// MSVC doesn't need group indicators
fn group_start(&mut self) {}
fn group_end(&mut self) {}
+
+ fn cross_lang_lto(&mut self) {
+ // Do nothing
+ }
}
pub struct EmLinker<'a> {
// Appears not necessary on Emscripten
fn group_start(&mut self) {}
fn group_end(&mut self) {}
+
+ fn cross_lang_lto(&mut self) {
+ // Do nothing
+ }
}
fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
// Not needed for now with LLD
fn group_start(&mut self) {}
fn group_end(&mut self) {}
+
+ fn cross_lang_lto(&mut self) {
+ // Do nothing for now
+ }
}
llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
level => level,
};
- with_llvm_pmb(llmod, config, opt_level, &mut |b| {
+ with_llvm_pmb(llmod, config, opt_level, false, &mut |b| {
if thin {
if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
panic!("this version of LLVM does not support ThinLTO");
}) => {
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 back::symbol_export::ExportedSymbols;
use base;
use consts;
-use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
-use rustc::dep_graph::{DepGraph, WorkProductFileKind};
+use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir};
+use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind};
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
AllPasses, Sanitizer, Lto};
let triple = &sess.target.target.llvm_target;
let triple = CString::new(triple.as_bytes()).unwrap();
- let cpu = match sess.opts.cg.target_cpu {
- Some(ref s) => &**s,
- None => &*sess.target.target.options.cpu
- };
+ let cpu = sess.target_cpu();
let cpu = CString::new(cpu.as_bytes()).unwrap();
let features = attributes::llvm_target_features(sess)
.collect::<Vec<_>>()
self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
let embed_bitcode = sess.target.target.options.embed_bitcode ||
sess.opts.debugging_opts.embed_bitcode ||
- sess.opts.debugging_opts.cross_lang_lto;
+ sess.opts.debugging_opts.cross_lang_lto.embed_bitcode();
if embed_bitcode {
match sess.opts.optimize {
config::OptLevel::No |
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
- with_llvm_pmb(llmod, &config, opt_level, &mut |b| {
+ let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal;
+ with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| {
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
})
}
}
-fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
- dep_graph: &DepGraph,
- compiled_modules: &CompiledModules) {
+fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
+ sess: &Session,
+ compiled_modules: &CompiledModules
+) -> FxHashMap<WorkProductId, WorkProduct> {
+ let mut work_products = FxHashMap::default();
+
if sess.opts.incremental.is_none() {
- return;
+ return work_products;
}
for module in compiled_modules.modules.iter() {
files.push((WorkProductFileKind::BytecodeCompressed, path.clone()));
}
- save_trans_partition(sess, dep_graph, &module.name, &files);
+ if let Some((id, product)) =
+ copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) {
+ work_products.insert(id, product);
+ }
}
+
+ work_products
}
fn produce_final_output_artifacts(sess: &Session,
// Don't run LTO passes when cross-lang LTO is enabled. The linker
// will do that for us in this case.
- let needs_lto = needs_lto && !cgcx.opts.debugging_opts.cross_lang_lto;
+ let needs_lto = needs_lto &&
+ !cgcx.opts.debugging_opts.cross_lang_lto.embed_bitcode();
if needs_lto {
Ok(WorkItemResult::NeedsLTO(mtrans))
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
config: &ModuleConfig,
opt_level: llvm::CodeGenOptLevel,
+ prepare_for_thin_lto: bool,
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
use std::ptr;
config.merge_functions,
config.vectorize_slp,
config.vectorize_loop,
+ prepare_for_thin_lto,
pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
);
}
impl OngoingCrateTranslation {
- pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
+ pub(crate) fn join(
+ self,
+ sess: &Session
+ ) -> (CrateTranslation, FxHashMap<WorkProductId, WorkProduct>) {
self.shared_emitter_main.check(sess, true);
let compiled_modules = match self.future.join() {
Ok(Ok(compiled_modules)) => compiled_modules,
time_graph.dump(&format!("{}-timings", self.crate_name));
}
- copy_module_artifacts_into_incr_comp_cache(sess,
- dep_graph,
- &compiled_modules);
+ let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess,
+ &compiled_modules);
+
produce_final_output_artifacts(sess,
&compiled_modules,
&self.output_filenames);
metadata_module: compiled_modules.metadata_module,
};
- trans
+ (trans, work_products)
}
pub(crate) fn submit_pre_translated_module_to_llvm(&self,
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};
let (source, target) = cx.tcx.struct_lockstep_tails(source, target);
match (&source.sty, &target.sty) {
(&ty::TyArray(_, len), &ty::TySlice(_)) => {
- C_usize(cx, len.val.unwrap_u64())
+ C_usize(cx, len.unwrap_usize(cx.tcx))
}
(&ty::TyDynamic(..), &ty::TyDynamic(..)) => {
// For now, upcasts are limited to changes in marker
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>,
}
fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec<u8>) {
- use rustc::mir::interpret::{GlobalId, Value, PrimVal};
+ use rustc::mir::interpret::GlobalId;
use rustc::middle::const_val::ConstVal;
info!("loading wasm section {:?}", id);
let param_env = ty::ParamEnv::reveal_all();
let val = tcx.const_eval(param_env.and(cid)).unwrap();
- let val = match val.val {
+ let const_val = match val.val {
ConstVal::Value(val) => val,
ConstVal::Unevaluated(..) => bug!("should be evaluated"),
};
- let val = match val {
- Value::ByRef(ptr, _align) => ptr.into_inner_primval(),
- ref v => bug!("should be ByRef, was {:?}", v),
- };
- let mem = match val {
- PrimVal::Ptr(mem) => mem,
- ref v => bug!("should be Ptr, was {:?}", v),
- };
- assert_eq!(mem.offset, 0);
- let alloc = tcx
- .interpret_interner
- .get_alloc(mem.alloc_id)
- .expect("miri allocation never successfully created");
+
+ let alloc = tcx.const_value_to_allocation((const_val, val.ty));
(section.to_string(), alloc.bytes.clone())
}
&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 {
let upper_bound = match array_or_slice_type.sty {
ty::TyArray(_, len) => {
- len.val.unwrap_u64() as c_longlong
+ len.unwrap_usize(cx.tcx) as c_longlong
}
_ => -1
};
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
}
ty::TyArray(inner_type, len) => {
output.push('[');
push_debuginfo_type_name(cx, inner_type, true, output);
- output.push_str(&format!("; {}", len.val.unwrap_u64()));
+ output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx)));
output.push(']');
},
ty::TySlice(inner_type) => {
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;
outputs: &OutputFilenames,
) -> Result<(), CompileIncomplete>{
use rustc::util::common::time;
- let trans = trans.downcast::<::back::write::OngoingCrateTranslation>()
+ let (trans, work_products) = trans.downcast::<::back::write::OngoingCrateTranslation>()
.expect("Expected LlvmTransCrate's OngoingCrateTranslation, found Box<Any>")
- .join(sess, dep_graph);
+ .join(sess);
if sess.opts.debugging_opts.incremental_info {
back::write::dump_incremental_data(&trans);
}
time(sess,
"serialize work products",
- move || rustc_incremental::save_work_products(sess, &dep_graph));
+ move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));
sess.compile_status()?;
use 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 rustc::hir::def_id::DefId;
use rustc::mir;
use rustc_data_structures::indexed_vec::Idx;
-use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
+use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue};
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar};
use builder::Builder;
consts::get_static(cx, def_id)
} else if let Some(alloc) = cx.tcx.interpret_interner
.get_alloc(ptr.alloc_id) {
- let init = global_initializer(cx, alloc);
+ let init = const_alloc_to_llvm(cx, alloc);
if alloc.runtime_mutability == Mutability::Mutable {
consts::addr_of_mut(cx, init, alloc.align, "byte_str")
} else {
}
}
-pub fn global_initializer(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
+fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef {
+ let layout = cx.layout_of(ty);
+
+ if layout.is_zst() {
+ return C_undef(layout.immediate_llvm_type(cx));
+ }
+
+ match val {
+ ConstValue::ByVal(x) => {
+ let scalar = match layout.abi {
+ layout::Abi::Scalar(ref x) => x,
+ _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout)
+ };
+ primval_to_llvm(
+ cx,
+ x,
+ scalar,
+ layout.immediate_llvm_type(cx),
+ )
+ },
+ ConstValue::ByValPair(a, b) => {
+ let (a_scalar, b_scalar) = match layout.abi {
+ layout::Abi::ScalarPair(ref a, ref b) => (a, b),
+ _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout)
+ };
+ let a_llval = primval_to_llvm(
+ cx,
+ a,
+ a_scalar,
+ layout.scalar_pair_element_llvm_type(cx, 0),
+ );
+ let b_llval = primval_to_llvm(
+ cx,
+ b,
+ b_scalar,
+ layout.scalar_pair_element_llvm_type(cx, 1),
+ );
+ C_struct(cx, &[a_llval, b_llval], false)
+ },
+ ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc),
+ }
+}
+
+pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef {
let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1);
let layout = cx.data_layout();
let pointer_size = layout.pointer_size.bytes() as usize;
let ptr_offset = read_target_uint(
layout.endian,
&alloc.bytes[offset..(offset + pointer_size)],
- ).expect("global_initializer: could not read relocation pointer") as u64;
+ ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
llvals.push(primval_to_llvm(
cx,
PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }),
let param_env = ty::ParamEnv::reveal_all();
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
- let ptr = match static_.val {
- ConstVal::Value(MiriValue::ByRef(ptr, _)) => ptr,
+ let val = match static_.val {
+ ConstVal::Value(val) => val,
_ => bug!("static const eval returned {:#?}", static_),
};
-
- let alloc = cx
- .tcx
- .interpret_interner
- .get_alloc(ptr.primval.to_ptr().expect("static has integer pointer").alloc_id)
- .expect("miri allocation never successfully created");
- Ok(global_initializer(cx, alloc))
+ Ok(const_value_to_llvm(cx, val, static_.ty))
}
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
- fn const_to_miri_value(
+ fn const_to_const_value(
&mut self,
bx: &Builder<'a, 'tcx>,
constant: &'tcx ty::Const<'tcx>,
- ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+ ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
match constant.val {
ConstVal::Unevaluated(def_id, ref substs) => {
let tcx = bx.tcx();
promoted: None,
};
let c = tcx.const_eval(param_env.and(cid))?;
- self.const_to_miri_value(bx, c)
+ self.const_to_const_value(bx, c)
},
- ConstVal::Value(miri_val) => Ok(miri_val),
+ ConstVal::Value(val) => Ok(val),
}
}
- pub fn mir_constant_to_miri_value(
+ pub fn mir_constant_to_const_value(
&mut self,
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
- ) -> Result<MiriValue, ConstEvalErr<'tcx>> {
+ ) -> Result<ConstValue<'tcx>, ConstEvalErr<'tcx>> {
match constant.literal {
mir::Literal::Promoted { index } => {
let param_env = ty::ParamEnv::reveal_all();
mir::Literal::Value { value } => {
Ok(self.monomorphize(&value))
}
- }.and_then(|c| self.const_to_miri_value(bx, c))
+ }.and_then(|c| self.const_to_const_value(bx, c))
}
/// process constant containing SIMD shuffle indices
bx: &Builder<'a, 'tcx>,
constant: &mir::Constant<'tcx>,
) -> (ValueRef, Ty<'tcx>) {
- self.mir_constant_to_miri_value(bx, constant)
+ self.mir_constant_to_const_value(bx, constant)
.and_then(|c| {
let field_ty = constant.ty.builtin_index().unwrap();
let fields = match constant.ty.sty {
- ty::TyArray(_, n) => n.val.unwrap_u64(),
+ ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()),
ref other => bug!("invalid simd shuffle type: {}", other),
};
let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
c,
constant.ty,
)?;
- match field.val {
- ConstVal::Value(MiriValue::ByVal(prim)) => {
- let layout = bx.cx.layout_of(field_ty);
- let scalar = match layout.abi {
- layout::Abi::Scalar(ref x) => x,
- _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
- };
- Ok(primval_to_llvm(
- bx.cx, prim, scalar,
- layout.immediate_llvm_type(bx.cx),
- ))
- },
- other => bug!("simd shuffle field {:?}, {}", other, constant.ty),
+ if let Some(prim) = field.to_primval() {
+ let layout = bx.cx.layout_of(field_ty);
+ let scalar = match layout.abi {
+ layout::Abi::Scalar(ref x) => x,
+ _ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
+ };
+ Ok(primval_to_llvm(
+ bx.cx, prim, scalar,
+ layout.immediate_llvm_type(bx.cx),
+ ))
+ } else {
+ bug!("simd shuffle field {:?}", field)
}
}).collect();
let llval = C_struct(bx.cx, &values?, false);
use llvm::ValueRef;
use rustc::middle::const_val::ConstEvalErr;
use rustc::mir;
-use rustc::mir::interpret::Value as MiriValue;
+use rustc::mir::interpret::ConstValue;
use rustc::ty;
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc_data_structures::indexed_vec::Idx;
use 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;
+use consts;
use std::fmt;
use std::ptr;
use super::{FunctionCx, LocalRef};
-use super::constant::{primval_to_llvm};
+use super::constant::{primval_to_llvm, const_alloc_to_llvm};
use super::place::PlaceRef;
/// The representation of a Rust value. The enum variant is in fact
}
pub fn from_const(bx: &Builder<'a, 'tcx>,
- miri_val: MiriValue,
+ val: ConstValue<'tcx>,
ty: ty::Ty<'tcx>)
-> Result<OperandRef<'tcx>, ConstEvalErr<'tcx>> {
let layout = bx.cx.layout_of(ty);
return Ok(OperandRef::new_zst(bx.cx, layout));
}
- let val = match miri_val {
- MiriValue::ByVal(x) => {
+ let val = match val {
+ ConstValue::ByVal(x) => {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
);
OperandValue::Immediate(llval)
},
- MiriValue::ByValPair(a, b) => {
+ ConstValue::ByValPair(a, b) => {
let (a_scalar, b_scalar) = match layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
_ => bug!("from_const: invalid ByValPair layout: {:#?}", layout)
);
OperandValue::Pair(a_llval, b_llval)
},
- MiriValue::ByRef(ptr, align) => {
- let scalar = layout::Scalar {
- value: layout::Primitive::Pointer,
- valid_range: 0..=!0
- };
- let ptr = primval_to_llvm(
- bx.cx,
- ptr.into_inner_primval(),
- &scalar,
- layout.llvm_type(bx.cx).ptr_to(),
- );
- return Ok(PlaceRef::new_sized(ptr, layout, align).load(bx));
+ ConstValue::ByRef(alloc) => {
+ let init = const_alloc_to_llvm(bx.cx, alloc);
+ let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str");
+ let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to());
+ return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx));
},
};
let offset = self.layout.fields.offset(i);
let mut val = match (self.val, &self.layout.abi) {
- // If we're uninhabited, or the field is ZST, it has no data.
- _ if self.layout.abi == layout::Abi::Uninhabited || field.is_zst() => {
- return OperandRef {
- val: OperandValue::Immediate(C_undef(field.immediate_llvm_type(bx.cx))),
- layout: field
- };
+ // If the field is ZST, it has no data.
+ _ if field.is_zst() => {
+ return OperandRef::new_zst(bx.cx, field);
}
// Newtype of a scalar, scalar pair or vector.
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);
}
}
}
mir::Operand::Constant(ref constant) => {
let ty = self.monomorphize(&constant.ty);
- self.mir_constant_to_miri_value(bx, constant)
+ self.mir_constant_to_const_value(bx, constant)
.and_then(|c| OperandRef::from_const(bx, c, ty))
.unwrap_or_else(|err| {
match constant.literal {
if let mir::Place::Local(index) = *place {
if let LocalRef::Operand(Some(op)) = self.locals[index] {
if let ty::TyArray(_, n) = op.layout.ty.sty {
- let n = n.val.unwrap_u64();
+ let n = n.unwrap_usize(bx.cx.tcx);
return common::C_usize(bx.cx, n);
}
}
impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
fn is_llvm_immediate(&self) -> bool {
match self.abi {
- layout::Abi::Uninhabited |
layout::Abi::Scalar(_) |
layout::Abi::Vector { .. } => true,
layout::Abi::ScalarPair(..) => false,
+ layout::Abi::Uninhabited |
layout::Abi::Aggregate { .. } => self.is_zst()
}
}
//! representation. The main routine here is `ast_ty_to_ty()`: each use
//! is parameterized by an instance of `AstConv`.
-use rustc::middle::const_val::ConstVal;
use rustc_data_structures::accumulate_vec::AccumulateVec;
use hir;
use hir::def::Def;
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).
hir::TyArray(ref ty, length) => {
let length_def_id = tcx.hir.body_owner_def_id(length);
let substs = Substs::identity_for_item(tcx, length_def_id);
- let length = tcx.mk_const(ty::Const {
- val: ConstVal::Unevaluated(length_def_id, substs),
- ty: tcx.types.usize
- });
+ let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize);
let array_ty = tcx.mk_ty(ty::TyArray(self.ast_ty_to_ty(&ty), length));
self.normalize_ty(ast_ty.span, array_ty)
}
let 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"
let expected_ty = self.structurally_resolved_type(pat.span, expected);
let (inner_ty, slice_ty) = match expected_ty.sty {
ty::TyArray(inner_ty, size) => {
- let size = size.val.unwrap_u64();
+ let size = size.unwrap_usize(tcx);
let min_len = before.len() as u64 + after.len() as u64;
if slice.is_none() {
if min_len != size {
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;
}
span: Span,
variant: &'tcx ty::VariantDef,
ast_fields: &'gcx [hir::Field],
- check_completeness: bool) {
+ check_completeness: bool) -> bool {
let tcx = self.tcx;
let adt_ty_hint =
truncated_fields_error))
.emit();
}
+ error_happened
}
fn check_struct_fields_on_error(&self,
}
}
- self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span, variant, fields,
- base_expr.is_none());
+ let error_happened = self.check_expr_struct_fields(struct_ty, expected, expr.id, path_span,
+ variant, fields, base_expr.is_none());
if let &Some(ref base_expr) = base_expr {
- self.check_expr_has_type_or_error(base_expr, struct_ty);
- match struct_ty.sty {
- ty::TyAdt(adt, substs) if adt.is_struct() => {
- let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
- self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
- }).collect();
-
- self.tables
- .borrow_mut()
- .fru_field_types_mut()
- .insert(expr.hir_id, fru_field_types);
- }
- _ => {
- span_err!(self.tcx.sess, base_expr.span, E0436,
- "functional record update syntax requires a struct");
+ // If check_expr_struct_fields hit an error, do not attempt to populate
+ // the fields with the base_expr. This could cause us to hit errors later
+ // when certain fields are assumed to exist that in fact do not.
+ if !error_happened {
+ self.check_expr_has_type_or_error(base_expr, struct_ty);
+ match struct_ty.sty {
+ ty::TyAdt(adt, substs) if adt.is_struct() => {
+ let fru_field_types = adt.non_enum_variant().fields.iter().map(|f| {
+ self.normalize_associated_types_in(expr.span, &f.ty(self.tcx, substs))
+ }).collect();
+
+ self.tables
+ .borrow_mut()
+ .fru_field_types_mut()
+ .insert(expr.hir_id, fru_field_types);
+ }
+ _ => {
+ span_err!(self.tcx.sess, base_expr.span, E0436,
+ "functional record update syntax requires a struct");
+ }
}
}
}
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);
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 {
};
if let Ok(count) = count {
- let zero_or_one = count.val.to_raw_bits().map_or(false, |count| count <= 1);
+ let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1);
if !zero_or_one {
// For [foo, ..n] where n > 1, `foo` must have
// Copy type:
} 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
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 super::{FnCtxt, Needs};
use super::method::MethodCallee;
-use rustc::ty::{self, Ty, TypeFoldable, TypeVariants};
-use rustc::ty::TypeVariants::{TyStr, TyRef, TyAdt};
+use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::TypeVariants::{TyRef, TyAdt, TyStr, TyUint, TyNever, TyTuple, TyChar, TyArray};
use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::infer::type_variable::TypeVariableOrigin;
use errors;
Err(()) => {
// error types are considered "builtin"
if !lhs_ty.references_error() {
- if let IsAssign::Yes = is_assign {
- struct_span_err!(self.tcx.sess, expr.span, E0368,
- "binary assignment operation `{}=` \
- cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty)
- .span_label(lhs_expr.span,
- format!("cannot use `{}=` on type `{}`",
- op.node.as_str(), lhs_ty))
- .emit();
- } else {
- let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
- "binary operation `{}` cannot be applied to type `{}`",
- op.node.as_str(),
- lhs_ty);
-
- if let TypeVariants::TyRef(_, rty, _) = lhs_ty.sty {
- if {
- !self.infcx.type_moves_by_default(self.param_env,
- rty,
- lhs_expr.span) &&
- self.lookup_op_method(rty,
- &[rhs_ty],
- Op::Binary(op, is_assign))
- .is_ok()
- } {
- err.note(
- &format!(
- "this is a reference to a type that `{}` can be applied \
- to; you need to dereference this variable once for this \
- operation to work",
- op.node.as_str()));
+ let codemap = self.tcx.sess.codemap();
+ match is_assign {
+ IsAssign::Yes => {
+ let mut err = struct_span_err!(self.tcx.sess, expr.span, E0368,
+ "binary assignment operation `{}=` \
+ cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty);
+ err.span_label(lhs_expr.span,
+ format!("cannot use `{}=` on type `{}`",
+ op.node.as_str(), lhs_ty));
+ let mut suggested_deref = false;
+ if let TyRef(_, mut rty, _) = lhs_ty.sty {
+ if {
+ !self.infcx.type_moves_by_default(self.param_env,
+ rty,
+ lhs_expr.span) &&
+ self.lookup_op_method(rty,
+ &[rhs_ty],
+ Op::Binary(op, is_assign))
+ .is_ok()
+ } {
+ if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+ while let TyRef(_, rty_inner, _) = rty.sty {
+ rty = rty_inner;
+ }
+ let msg = &format!(
+ "`{}=` can be used on '{}', you can \
+ dereference `{2}`: `*{2}`",
+ op.node.as_str(),
+ rty,
+ lstring
+ );
+ err.help(msg);
+ suggested_deref = true;
+ }
+ }
}
+ let missing_trait = match op.node {
+ hir::BiAdd => Some("std::ops::AddAssign"),
+ hir::BiSub => Some("std::ops::SubAssign"),
+ hir::BiMul => Some("std::ops::MulAssign"),
+ hir::BiDiv => Some("std::ops::DivAssign"),
+ hir::BiRem => Some("std::ops::RemAssign"),
+ hir::BiBitAnd => Some("std::ops::BitAndAssign"),
+ hir::BiBitXor => Some("std::ops::BitXorAssign"),
+ hir::BiBitOr => Some("std::ops::BitOrAssign"),
+ hir::BiShl => Some("std::ops::ShlAssign"),
+ hir::BiShr => Some("std::ops::ShrAssign"),
+ _ => None
+ };
+ if let Some(missing_trait) = missing_trait {
+ if op.node == hir::BiAdd &&
+ self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+ rhs_ty, &mut err) {
+ // This has nothing here because it means we did string
+ // concatenation (e.g. "Hello " + "World!"). This means
+ // we don't want the note in the else clause to be emitted
+ } else if let ty::TyParam(_) = lhs_ty.sty {
+ // FIXME: point to span of param
+ err.note(&format!(
+ "`{}` might need a bound for `{}`",
+ lhs_ty, missing_trait
+ ));
+ } else if !suggested_deref {
+ err.note(&format!(
+ "an implementation of `{}` might \
+ be missing for `{}`",
+ missing_trait, lhs_ty
+ ));
+ }
+ }
+ err.emit();
}
-
- let missing_trait = match op.node {
- hir::BiAdd => Some("std::ops::Add"),
- hir::BiSub => Some("std::ops::Sub"),
- hir::BiMul => Some("std::ops::Mul"),
- hir::BiDiv => Some("std::ops::Div"),
- hir::BiRem => Some("std::ops::Rem"),
- hir::BiBitAnd => Some("std::ops::BitAnd"),
- hir::BiBitOr => Some("std::ops::BitOr"),
- hir::BiShl => Some("std::ops::Shl"),
- hir::BiShr => Some("std::ops::Shr"),
- hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
- hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
- Some("std::cmp::PartialOrd"),
- _ => None
- };
-
- if let Some(missing_trait) = missing_trait {
- if missing_trait == "std::ops::Add" &&
- self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
- rhs_ty, &mut err) {
- // This has nothing here because it means we did string
- // concatenation (e.g. "Hello " + "World!"). This means
- // we don't want the note in the else clause to be emitted
- } else if let ty::TyParam(_) = lhs_ty.sty {
- // FIXME: point to span of param
- err.note(
- &format!("`{}` might need a bound for `{}`",
- lhs_ty, missing_trait));
- } else {
- err.note(
- &format!("an implementation of `{}` might be missing for `{}`",
- missing_trait, lhs_ty));
+ IsAssign::No => {
+ let mut err = struct_span_err!(self.tcx.sess, expr.span, E0369,
+ "binary operation `{}` cannot be applied to type `{}`",
+ op.node.as_str(),
+ lhs_ty);
+ let mut suggested_deref = false;
+ if let TyRef(_, mut rty, _) = lhs_ty.sty {
+ if {
+ !self.infcx.type_moves_by_default(self.param_env,
+ rty,
+ lhs_expr.span) &&
+ self.lookup_op_method(rty,
+ &[rhs_ty],
+ Op::Binary(op, is_assign))
+ .is_ok()
+ } {
+ if let Ok(lstring) = codemap.span_to_snippet(lhs_expr.span) {
+ while let TyRef(_, rty_inner, _) = rty.sty {
+ rty = rty_inner;
+ }
+ let msg = &format!(
+ "`{}` can be used on '{}', you can \
+ dereference `{2}`: `*{2}`",
+ op.node.as_str(),
+ rty,
+ lstring
+ );
+ err.help(msg);
+ suggested_deref = true;
+ }
+ }
}
+ let missing_trait = match op.node {
+ hir::BiAdd => Some("std::ops::Add"),
+ hir::BiSub => Some("std::ops::Sub"),
+ hir::BiMul => Some("std::ops::Mul"),
+ hir::BiDiv => Some("std::ops::Div"),
+ hir::BiRem => Some("std::ops::Rem"),
+ hir::BiBitAnd => Some("std::ops::BitAnd"),
+ hir::BiBitXor => Some("std::ops::BitXor"),
+ hir::BiBitOr => Some("std::ops::BitOr"),
+ hir::BiShl => Some("std::ops::Shl"),
+ hir::BiShr => Some("std::ops::Shr"),
+ hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+ hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+ Some("std::cmp::PartialOrd"),
+ _ => None
+ };
+ if let Some(missing_trait) = missing_trait {
+ if op.node == hir::BiAdd &&
+ self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty,
+ rhs_ty, &mut err) {
+ // This has nothing here because it means we did string
+ // concatenation (e.g. "Hello " + "World!"). This means
+ // we don't want the note in the else clause to be emitted
+ } else if let ty::TyParam(_) = lhs_ty.sty {
+ // FIXME: point to span of param
+ err.note(&format!(
+ "`{}` might need a bound for `{}`",
+ lhs_ty, missing_trait
+ ));
+ } else if !suggested_deref {
+ err.note(&format!(
+ "an implementation of `{}` might \
+ be missing for `{}`",
+ missing_trait, lhs_ty
+ ));
+ }
+ }
+ err.emit();
}
- err.emit();
}
}
self.tcx.types.err
Err(()) => {
let actual = self.resolve_type_vars_if_possible(&operand_ty);
if !actual.references_error() {
- struct_span_err!(self.tcx.sess, ex.span, E0600,
+ let mut err = struct_span_err!(self.tcx.sess, ex.span, E0600,
"cannot apply unary operator `{}` to type `{}`",
- op.as_str(), actual).emit();
+ op.as_str(), actual);
+ err.span_label(ex.span, format!("cannot apply unary \
+ operator `{}`", op.as_str()));
+ match actual.sty {
+ TyUint(_) if op == hir::UnNeg => {
+ err.note(&format!("unsigned values cannot be negated"));
+ },
+ TyStr | TyNever | TyChar | TyTuple(_) | TyArray(_,_) => {},
+ TyRef(_, ref lty, _) if lty.sty == TyStr => {},
+ _ => {
+ let missing_trait = match op {
+ hir::UnNeg => "std::ops::Neg",
+ hir::UnNot => "std::ops::Not",
+ hir::UnDeref => "std::ops::UnDerf"
+ };
+ err.note(&format!("an implementation of `{}` might \
+ be missing for `{}`",
+ missing_trait, operand_ty));
+ }
+ }
+ err.emit();
}
self.tcx.types.err
}
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();
}
}
}
debug!("visit_implementation_of_copy: self_type={:?} (free)",
self_type);
- match param_env.can_type_implement_copy(tcx, self_type, span) {
+ match param_env.can_type_implement_copy(tcx, self_type) {
Ok(()) => {}
- Err(CopyImplementationError::InfrigingField(field)) => {
+ Err(CopyImplementationError::InfrigingFields(fields)) => {
let item = tcx.hir.expect_item(impl_node_id);
let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
tr.path.span
span
};
- struct_span_err!(tcx.sess,
- span,
- E0204,
- "the trait `Copy` may not be implemented for this type")
- .span_label(
- tcx.def_span(field.did),
- "this field does not implement `Copy`")
- .emit()
+ let mut err = struct_span_err!(tcx.sess,
+ span,
+ E0204,
+ "the trait `Copy` may not be implemented for this type");
+ for span in fields.iter().map(|f| tcx.def_span(f.did)) {
+ err.span_label(span, "this field does not implement `Copy`");
+ }
+ err.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
let item = tcx.hir.expect_item(impl_node_id);
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;
pub struct Attributes {
pub doc_strings: Vec<DocFragment>,
pub other_attrs: Vec<ast::Attribute>,
- pub cfg: Option<Rc<Cfg>>,
+ pub cfg: Option<Arc<Cfg>>,
pub span: Option<syntax_pos::Span>,
/// map from Rust paths to resolved defs and potential URL fragments
pub links: Vec<(String, Option<DefId>, Option<String>)>,
Attributes {
doc_strings,
other_attrs,
- cfg: if cfg == Cfg::True { None } else { Some(Rc::new(cfg)) },
+ cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) },
span: sp,
links: vec![],
}
}
}
-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
promoted: None
};
let n = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| {
- cx.tcx.mk_const(ty::Const {
- val: ConstVal::Unevaluated(def_id, substs),
- ty: cx.tcx.types.usize
- })
+ ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize)
});
let n = print_const(cx, n);
Array(box ty.clean(cx), n)
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,
}
inline::print_inlined_const(cx, def_id)
}
},
- ConstVal::Value(val) => {
+ ConstVal::Value(..) => {
let mut s = String::new();
- ::rustc::mir::print_miri_value(val, n.ty, &mut s).unwrap();
+ ::rustc::mir::fmt_const_val(&mut s, n).unwrap();
// array lengths are obviously usize
if s.ends_with("usize") {
let n = s.len() - "usize".len();
#[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()
};
-
- let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
- let emitter: Box<dyn Emitter + sync::Send> = match error_format {
- ErrorOutputType::HumanReadable(color_config) => Box::new(
- EmitterWriter::stderr(
- color_config,
- Some(codemap.clone()),
- false,
- sessopts.debugging_opts.teach,
- ).ui_testing(sessopts.debugging_opts.ui_testing)
- ),
- ErrorOutputType::Json(pretty) => Box::new(
- JsonEmitter::stderr(
- None,
- codemap.clone(),
- pretty,
- sessopts.debugging_opts.suggestion_applicability,
- ).ui_testing(sessopts.debugging_opts.ui_testing)
- ),
- ErrorOutputType::Short(color_config) => Box::new(
- EmitterWriter::stderr(color_config, Some(codemap.clone()), true, false)
- ),
- };
-
- let diagnostic_handler = errors::Handler::with_emitter_and_flags(
- emitter,
- errors::HandlerFlags {
- can_emit_warnings: true,
- treat_err_as_bug: false,
- external_macro_backtrace: false,
- ..Default::default()
- },
- );
-
- let mut sess = session::build_session_(
- sessopts, cpath, diagnostic_handler, codemap,
- );
- let trans = rustc_driver::get_trans(&sess);
- let cstore = Rc::new(CStore::new(trans.metadata_loader()));
- rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
- target_features::add_configuration(&mut cfg, &sess, &*trans);
- sess.parse_sess.config = cfg;
-
- let control = &driver::CompileController::basic();
-
- let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
-
- let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
-
- let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
-
- let resolver_arenas = resolve::Resolver::arenas();
- let result = driver::phase_2_configure_and_expand_inner(&sess,
- &cstore,
- krate,
- None,
- &name,
- None,
- resolve::MakeGlobMap::No,
- &resolver_arenas,
- &mut crate_loader,
- |_| Ok(()));
- let driver::InnerExpansionResult {
- mut hir_forest,
- resolver,
- ..
- } = abort_on_err(result, &sess);
-
- // We need to hold on to the complete resolver, so we clone everything
- // for the analysis passes to use. Suboptimal, but necessary in the
- // current architecture.
- let defs = resolver.definitions.clone();
- let resolutions = ty::Resolutions {
- freevars: resolver.freevars.clone(),
- export_map: resolver.export_map.clone(),
- trait_map: resolver.trait_map.clone(),
- maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
- maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
- };
- let analysis = ty::CrateAnalysis {
- access_levels: Lrc::new(AccessLevels::default()),
- name: name.to_string(),
- glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
- };
-
- let arenas = AllArenas::new();
- let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
- let output_filenames = driver::build_output_filenames(&input,
- &None,
- &None,
- &[],
- &sess);
-
- let resolver = RefCell::new(resolver);
-
- abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
- control,
- &sess,
- &*cstore,
- hir_map,
- analysis,
- resolutions,
- &arenas,
- &name,
- &output_filenames,
- |tcx, analysis, _, result| {
- if let Err(_) = result {
- sess.fatal("Compilation failed, aborting rustdoc");
- }
-
- let ty::CrateAnalysis { access_levels, .. } = analysis;
-
- // Convert from a NodeId set to a DefId set since we don't always have easy access
- // to the map from defid -> nodeid
- let access_levels = AccessLevels {
- map: access_levels.map.iter()
- .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
- .collect()
- };
-
- let send_trait = if crate_name == Some("core".to_string()) {
- clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
- } else {
- clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+ driver::spawn_thread_pool(sessopts, move |sessopts| {
+ let codemap = Lrc::new(codemap::CodeMap::new(sessopts.file_path_mapping()));
+ let diagnostic_handler = new_handler(error_format, Some(codemap.clone()));
+
+ let mut sess = session::build_session_(
+ sessopts, cpath, diagnostic_handler, codemap,
+ );
+ let trans = rustc_driver::get_trans(&sess);
+ let cstore = Rc::new(CStore::new(trans.metadata_loader()));
+ rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+ let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs));
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
+ sess.parse_sess.config = cfg;
+
+ let control = &driver::CompileController::basic();
+
+ let krate = panictry!(driver::phase_1_parse_input(control, &sess, &input));
+
+ let name = ::rustc_trans_utils::link::find_crate_name(Some(&sess), &krate.attrs, &input);
+
+ let mut crate_loader = CrateLoader::new(&sess, &cstore, &name);
+
+ let resolver_arenas = resolve::Resolver::arenas();
+ let result = driver::phase_2_configure_and_expand_inner(&sess,
+ &cstore,
+ krate,
+ None,
+ &name,
+ None,
+ resolve::MakeGlobMap::No,
+ &resolver_arenas,
+ &mut crate_loader,
+ |_| Ok(()));
+ let driver::InnerExpansionResult {
+ mut hir_forest,
+ resolver,
+ ..
+ } = abort_on_err(result, &sess);
+
+ // We need to hold on to the complete resolver, so we clone everything
+ // for the analysis passes to use. Suboptimal, but necessary in the
+ // current architecture.
+ let defs = resolver.definitions.clone();
+ let resolutions = ty::Resolutions {
+ freevars: resolver.freevars.clone(),
+ export_map: resolver.export_map.clone(),
+ trait_map: resolver.trait_map.clone(),
+ maybe_unused_trait_imports: resolver.maybe_unused_trait_imports.clone(),
+ maybe_unused_extern_crates: resolver.maybe_unused_extern_crates.clone(),
};
-
- let ctxt = DocContext {
- tcx,
- resolver: &resolver,
- crate_name,
- cstore: cstore.clone(),
- populated_all_crate_impls: Cell::new(false),
- access_levels: RefCell::new(access_levels),
- external_traits: Default::default(),
- active_extern_traits: Default::default(),
- renderinfo: Default::default(),
- ty_substs: Default::default(),
- lt_substs: Default::default(),
- impl_trait_bounds: Default::default(),
- mod_ids: Default::default(),
- send_trait: send_trait,
- fake_def_ids: RefCell::new(FxHashMap()),
- all_fake_def_ids: RefCell::new(FxHashSet()),
- generated_synthetics: RefCell::new(FxHashSet()),
- };
- debug!("crate: {:?}", tcx.hir.krate());
-
- let krate = {
- let mut v = RustdocVisitor::new(&*cstore, &ctxt);
- v.visit(tcx.hir.krate());
- v.clean(&ctxt)
+ let analysis = ty::CrateAnalysis {
+ access_levels: Lrc::new(AccessLevels::default()),
+ name: name.to_string(),
+ glob_map: if resolver.make_glob_map { Some(resolver.glob_map.clone()) } else { None },
};
- (krate, ctxt.renderinfo.into_inner())
- }), &sess)
+ let arenas = AllArenas::new();
+ let hir_map = hir_map::map_crate(&sess, &*cstore, &mut hir_forest, &defs);
+ let output_filenames = driver::build_output_filenames(&input,
+ &None,
+ &None,
+ &[],
+ &sess);
+
+ let resolver = RefCell::new(resolver);
+
+ abort_on_err(driver::phase_3_run_analysis_passes(&*trans,
+ control,
+ &sess,
+ &*cstore,
+ hir_map,
+ analysis,
+ resolutions,
+ &arenas,
+ &name,
+ &output_filenames,
+ |tcx, analysis, _, result| {
+ if let Err(_) = result {
+ sess.fatal("Compilation failed, aborting rustdoc");
+ }
+
+ let ty::CrateAnalysis { access_levels, .. } = analysis;
+
+ // Convert from a NodeId set to a DefId set since we don't always have easy access
+ // to the map from defid -> nodeid
+ let access_levels = AccessLevels {
+ map: access_levels.map.iter()
+ .map(|(&k, &v)| (tcx.hir.local_def_id(k), v))
+ .collect()
+ };
+
+ let send_trait = if crate_name == Some("core".to_string()) {
+ clean::get_trait_def_id(&tcx, &["marker", "Send"], true)
+ } else {
+ clean::get_trait_def_id(&tcx, &["core", "marker", "Send"], false)
+ };
+
+ let ctxt = DocContext {
+ tcx,
+ resolver: &resolver,
+ crate_name,
+ cstore: cstore.clone(),
+ populated_all_crate_impls: Cell::new(false),
+ access_levels: RefCell::new(access_levels),
+ external_traits: Default::default(),
+ active_extern_traits: Default::default(),
+ renderinfo: Default::default(),
+ ty_substs: Default::default(),
+ lt_substs: Default::default(),
+ impl_trait_bounds: Default::default(),
+ mod_ids: Default::default(),
+ send_trait: send_trait,
+ fake_def_ids: RefCell::new(FxHashMap()),
+ all_fake_def_ids: RefCell::new(FxHashSet()),
+ generated_synthetics: RefCell::new(FxHashSet()),
+ };
+ debug!("crate: {:?}", tcx.hir.krate());
+
+ let krate = {
+ let mut v = RustdocVisitor::new(&*cstore, &ctxt);
+ v.visit(tcx.hir.krate());
+ v.clean(&ctxt)
+ };
+
+ (krate, ctxt.renderinfo.into_inner())
+ }), &sess)
+ })
}
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),
}
fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter,
- implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> Result<(), fmt::Error> {
+ implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result {
write!(w, "<li><table class='table-display'><tbody><tr><td><code>")?;
// If there's already another implementor that has the same abbridged name, use the
// full path, for example in `std::iter::ExactSizeIterator`
fn render_impls(cx: &Context, w: &mut fmt::Formatter,
traits: &[&&Impl],
- containing_item: &clean::Item) -> Result<(), fmt::Error> {
+ containing_item: &clean::Item) -> fmt::Result {
for i in traits {
let did = i.trait_did().unwrap();
let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods);
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
#![feature(vec_remove_item)]
#![feature(entry_and_modify)]
+#![recursion_limit="256"]
+
extern crate arena;
extern crate getopts;
extern crate env_logger;
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,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::rc::Rc;
+use std::sync::Arc;
use clean::{Crate, Item};
use clean::cfg::Cfg;
}
struct CfgPropagator {
- parent_cfg: Option<Rc<Cfg>>,
+ parent_cfg: Option<Arc<Cfg>>,
}
impl DocFolder for CfgPropagator {
(None, None) => None,
(Some(rc), None) | (None, Some(rc)) => Some(rc),
(Some(mut a), Some(b)) => {
- let b = Rc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
- *Rc::make_mut(&mut a) &= b;
+ let b = Arc::try_unwrap(b).unwrap_or_else(|rc| Cfg::clone(&rc));
+ *Arc::make_mut(&mut a) &= b;
Some(a)
}
};
edition,
..config::basic_options().clone()
};
-
- let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
- let handler =
- errors::Handler::with_tty_emitter(ColorConfig::Auto,
- true, false,
- Some(codemap.clone()));
-
- let mut sess = session::build_session_(
- sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
- );
- let trans = rustc_driver::get_trans(&sess);
- let cstore = CStore::new(trans.metadata_loader());
- rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
- target_features::add_configuration(&mut cfg, &sess, &*trans);
- sess.parse_sess.config = cfg;
-
- let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
- &sess,
- &input));
- let driver::ExpansionResult { defs, mut hir_forest, .. } = {
- phase_2_configure_and_expand(
- &sess,
- &cstore,
- krate,
- None,
- "rustdoc-test",
- None,
- MakeGlobMap::No,
- |_| Ok(()),
- ).expect("phase_2_configure_and_expand aborted in rustdoc!")
- };
-
- let crate_name = crate_name.unwrap_or_else(|| {
- ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
- });
- let mut opts = scrape_test_config(hir_forest.krate());
- opts.display_warnings |= display_warnings;
- let mut collector = Collector::new(crate_name,
- cfgs,
- libs,
- cg,
- externs,
- false,
- opts,
- maybe_sysroot,
- Some(codemap),
- None,
- linker,
- edition);
-
- {
- let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
- let krate = map.krate();
- let mut hir_collector = HirCollector {
- sess: &sess,
- collector: &mut collector,
- map: &map
+ driver::spawn_thread_pool(sessopts, |sessopts| {
+ let codemap = Lrc::new(CodeMap::new(sessopts.file_path_mapping()));
+ let handler =
+ errors::Handler::with_tty_emitter(ColorConfig::Auto,
+ true, false,
+ Some(codemap.clone()));
+
+ let mut sess = session::build_session_(
+ sessopts, Some(input_path.to_owned()), handler, codemap.clone(),
+ );
+ let trans = rustc_driver::get_trans(&sess);
+ let cstore = CStore::new(trans.metadata_loader());
+ rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+ let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
+ sess.parse_sess.config = cfg;
+
+ let krate = panictry!(driver::phase_1_parse_input(&driver::CompileController::basic(),
+ &sess,
+ &input));
+ let driver::ExpansionResult { defs, mut hir_forest, .. } = {
+ phase_2_configure_and_expand(
+ &sess,
+ &cstore,
+ krate,
+ None,
+ "rustdoc-test",
+ None,
+ MakeGlobMap::No,
+ |_| Ok(()),
+ ).expect("phase_2_configure_and_expand aborted in rustdoc!")
};
- hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
- intravisit::walk_crate(this, krate);
+
+ let crate_name = crate_name.unwrap_or_else(|| {
+ ::rustc_trans_utils::link::find_crate_name(None, &hir_forest.krate().attrs, &input)
});
- }
+ let mut opts = scrape_test_config(hir_forest.krate());
+ opts.display_warnings |= display_warnings;
+ let mut collector = Collector::new(
+ crate_name,
+ cfgs,
+ libs,
+ cg,
+ externs,
+ false,
+ opts,
+ maybe_sysroot,
+ Some(codemap),
+ None,
+ linker,
+ edition
+ );
+
+ {
+ let map = hir::map::map_crate(&sess, &cstore, &mut hir_forest, &defs);
+ let krate = map.krate();
+ let mut hir_collector = HirCollector {
+ sess: &sess,
+ collector: &mut collector,
+ map: &map
+ };
+ hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
+ intravisit::walk_crate(this, krate);
+ });
+ }
- test_args.insert(0, "rustdoctest".to_string());
+ test_args.insert(0, "rustdoctest".to_string());
- testing::test_main(&test_args,
- collector.tests.into_iter().collect(),
- testing::Options::new().display_output(display_warnings));
- 0
+ testing::test_main(&test_args,
+ collector.tests.into_iter().collect(),
+ testing::Options::new().display_output(display_warnings));
+ 0
+ })
}
// Look for #![doc(test(no_crate_inject))], used by crates in the std facade
..config::basic_options().clone()
};
- // Shuffle around a few input and output handles here. We're going to pass
- // an explicit handle into rustc to collect output messages, but we also
- // want to catch the error message that rustc prints when it fails.
- //
- // We take our thread-local stderr (likely set by the test runner) and replace
- // it with a sink that is also passed to rustc itself. When this function
- // returns the output of the sink is copied onto the output of our own thread.
- //
- // The basic idea is to not use a default Handler for rustc, and then also
- // not print things by default to the actual stderr.
- struct Sink(Arc<Mutex<Vec<u8>>>);
- impl Write for Sink {
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- Write::write(&mut *self.0.lock().unwrap(), data)
+ let (libdir, outdir) = driver::spawn_thread_pool(sessopts, |sessopts| {
+ // Shuffle around a few input and output handles here. We're going to pass
+ // an explicit handle into rustc to collect output messages, but we also
+ // want to catch the error message that rustc prints when it fails.
+ //
+ // We take our thread-local stderr (likely set by the test runner) and replace
+ // it with a sink that is also passed to rustc itself. When this function
+ // returns the output of the sink is copied onto the output of our own thread.
+ //
+ // The basic idea is to not use a default Handler for rustc, and then also
+ // not print things by default to the actual stderr.
+ struct Sink(Arc<Mutex<Vec<u8>>>);
+ impl Write for Sink {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ Write::write(&mut *self.0.lock().unwrap(), data)
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
- fn flush(&mut self) -> io::Result<()> { Ok(()) }
- }
- struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
- impl Drop for Bomb {
- fn drop(&mut self) {
- let _ = self.1.write_all(&self.0.lock().unwrap());
+ struct Bomb(Arc<Mutex<Vec<u8>>>, Box<Write+Send>);
+ impl Drop for Bomb {
+ fn drop(&mut self) {
+ let _ = self.1.write_all(&self.0.lock().unwrap());
+ }
}
- }
- let data = Arc::new(Mutex::new(Vec::new()));
- let codemap = Lrc::new(CodeMap::new_doctest(
- sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
- ));
- let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
- Some(codemap.clone()),
- false,
- false);
- let old = io::set_panic(Some(box Sink(data.clone())));
- let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
-
- // Compile the code
- let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
-
- let mut sess = session::build_session_(
- sessopts, None, diagnostic_handler, codemap,
- );
- let trans = rustc_driver::get_trans(&sess);
- let cstore = CStore::new(trans.metadata_loader());
- rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
-
- let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
- let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
- let mut control = driver::CompileController::basic();
-
- let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
- target_features::add_configuration(&mut cfg, &sess, &*trans);
- sess.parse_sess.config = cfg;
-
- let out = Some(outdir.lock().unwrap().path().to_path_buf());
-
- if no_run {
- control.after_analysis.stop = Compilation::Stop;
- }
-
- let res = panic::catch_unwind(AssertUnwindSafe(|| {
- driver::compile_input(
- trans,
- &sess,
- &cstore,
- &None,
- &input,
- &out,
- &None,
- None,
- &control
- )
- }));
-
- let compile_result = match res {
- Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
- Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
- };
-
- match (compile_result, compile_fail) {
- (Ok(()), true) => {
- panic!("test compiled while it wasn't supposed to")
+ let data = Arc::new(Mutex::new(Vec::new()));
+ let codemap = Lrc::new(CodeMap::new_doctest(
+ sessopts.file_path_mapping(), filename.clone(), line as isize - line_offset as isize
+ ));
+ let emitter = errors::emitter::EmitterWriter::new(box Sink(data.clone()),
+ Some(codemap.clone()),
+ false,
+ false);
+ let old = io::set_panic(Some(box Sink(data.clone())));
+ let _bomb = Bomb(data.clone(), old.unwrap_or(box io::stdout()));
+
+ // Compile the code
+ let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
+
+ let mut sess = session::build_session_(
+ sessopts, None, diagnostic_handler, codemap,
+ );
+ let trans = rustc_driver::get_trans(&sess);
+ let cstore = CStore::new(trans.metadata_loader());
+ rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
+
+ let outdir = Mutex::new(TempDir::new("rustdoctest").ok().expect("rustdoc needs a tempdir"));
+ let libdir = sess.target_filesearch(PathKind::All).get_lib_path();
+ let mut control = driver::CompileController::basic();
+
+ let mut cfg = config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
+ target_features::add_configuration(&mut cfg, &sess, &*trans);
+ sess.parse_sess.config = cfg;
+
+ let out = Some(outdir.lock().unwrap().path().to_path_buf());
+
+ if no_run {
+ control.after_analysis.stop = Compilation::Stop;
}
- (Ok(()), false) => {}
- (Err(()), true) => {
- if error_codes.len() > 0 {
- let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
- error_codes.retain(|err| !out.contains(err));
+
+ let res = panic::catch_unwind(AssertUnwindSafe(|| {
+ driver::compile_input(
+ trans,
+ &sess,
+ &cstore,
+ &None,
+ &input,
+ &out,
+ &None,
+ None,
+ &control
+ )
+ }));
+
+ let compile_result = match res {
+ Ok(Ok(())) | Ok(Err(CompileIncomplete::Stopped)) => Ok(()),
+ Err(_) | Ok(Err(CompileIncomplete::Errored(_))) => Err(())
+ };
+
+ match (compile_result, compile_fail) {
+ (Ok(()), true) => {
+ panic!("test compiled while it wasn't supposed to")
+ }
+ (Ok(()), false) => {}
+ (Err(()), true) => {
+ if error_codes.len() > 0 {
+ let out = String::from_utf8(data.lock().unwrap().to_vec()).unwrap();
+ error_codes.retain(|err| !out.contains(err));
+ }
+ }
+ (Err(()), false) => {
+ panic!("couldn't compile the test")
}
}
- (Err(()), false) => {
- panic!("couldn't compile the test")
+
+ if error_codes.len() > 0 {
+ panic!("Some expected error codes were not found: {:?}", error_codes);
}
- }
- if error_codes.len() > 0 {
- panic!("Some expected error codes were not found: {:?}", error_codes);
- }
+ (libdir, outdir)
+ });
if no_run { return }
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);
//! This module provides constants which are specific to the implementation
//! of the `f32` floating point data type.
//!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
//! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
/// 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;
///
}
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
- /// error. This produces a more accurate result with better performance than
- /// a separate multiplication operation followed by an add.
+ /// error, yielding a more accurate result than an unfused multiply-add.
+ ///
+ /// 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;
///
//! This module provides constants which are specific to the implementation
//! of the `f64` floating point data type.
//!
-//! Mathematically significant numbers are provided in the `consts` sub-module.
-//!
//! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
+//!
+//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
/// 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;
///
}
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding
- /// error. This produces a more accurate result with better performance than
- /// a separate multiplication operation followed by an add.
+ /// error, yielding a more accurate result than an unfused multiply-add.
+ ///
+ /// 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;
/// 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;
///
///
/// fn main() -> std::io::Result<()> {
/// fs::write("foo.txt", b"Lorem ipsum")?;
+/// fs::write("bar.txt", "dolor sit")?;
/// Ok(())
/// }
/// ```
fs_imp::readlink(path.as_ref())
}
-/// Returns the canonical form of a path with all intermediate components
-/// normalized and symbolic links resolved.
+/// Returns the canonical, absolute form of a path with all intermediate
+/// components normalized and symbolic links resolved.
///
/// # Platform-specific behavior
///
/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
/// Note that, this [may change in the future][changes].
///
+/// On Windows, this converts the path to use [extended length path][path]
+/// syntax, which allows your program to use longer path names, but means you
+/// can only join backslash-delimited paths to it, and it may be incompatible
+/// with other applications (if passed to the application on the command-line,
+/// or written to a file another application may read).
+///
/// [changes]: ../io/index.html#platform-specific-behavior
+/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
///
/// # Errors
///
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for PathBuf {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter)
}
}
fs::symlink_metadata(self)
}
- /// Returns the canonical form of the path with all intermediate components
- /// normalized and symbolic links resolved.
+ /// Returns the canonical, absolute form of the path with all intermediate
+ /// components normalized and symbolic links resolved.
///
/// This is an alias to [`fs::canonicalize`].
///
//
/// Raw, unsafe pointers, `*const T`, and `*mut T`.
///
+/// *[See also the `std::ptr` module](ptr/index.html).*
+///
/// Working with raw pointers in Rust is uncommon,
/// typically limited to a few patterns.
///
/// but C APIs hand out a lot of pointers generally, so are a common source
/// of raw pointers in Rust.
///
-/// *[See also the `std::ptr` module](ptr/index.html).*
-///
/// [`null`]: ../std/ptr/fn.null.html
/// [`null_mut`]: ../std/ptr/fn.null_mut.html
/// [`is_null`]: ../std/primitive.pointer.html#method.is_null
//
/// A dynamically-sized view into a contiguous sequence, `[T]`.
///
+/// *[See also the `std::slice` module](slice/index.html).*
+///
/// Slices are a view into a block of memory represented as a pointer and a
/// length.
///
/// assert_eq!(x, &[1, 7, 3]);
/// ```
///
-/// *[See also the `std::slice` module](slice/index.html).*
-///
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice { }
//
/// String slices.
///
+/// *[See also the `std::str` module](str/index.html).*
+///
/// The `str` type, also called a 'string slice', is the most primitive string
/// type. It is usually seen in its borrowed form, `&str`. It is also the type
/// of string literals, `&'static str`.
///
-/// Strings slices are always valid UTF-8.
-///
-/// This documentation describes a number of methods and trait implementations
-/// on the `str` type. For technical reasons, there is additional, separate
-/// documentation in the [`std::str`](str/index.html) module as well.
+/// String slices are always valid UTF-8.
///
/// # Examples
///
//
/// The pointer-sized signed integer type.
///
+/// *[See also the `std::isize` module](isize/index.html).*
+///
/// The size of this primitive is how many bytes it takes to reference any
/// location in memory. For example, on a 32 bit target, this is 4 bytes
/// and on a 64 bit target, this is 8 bytes.
-///
-/// *[See also the `std::isize` module](isize/index.html).*
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_isize { }
//
/// The pointer-sized unsigned integer type.
///
+/// *[See also the `std::usize` module](usize/index.html).*
+///
/// The size of this primitive is how many bytes it takes to reference any
/// location in memory. For example, on a 32 bit target, this is 4 bytes
/// and on a 64 bit target, this is 8 bytes.
-///
-/// *[See also the `std::usize` module](usize/index.html).*
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize { }
}
impl fmt::Debug for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.text())
}
}
impl fmt::Display for Error {
- fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.text())
}
}
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
-> io::Result<isize>
{
+ use convert::TryInto;
use libc::pread64;
- cvt(pread64(fd, buf, count, offset as i32))
+ // pread64 on emscripten actually takes a 32 bit offset
+ if let Ok(o) = offset.try_into() {
+ cvt(pread64(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pread >2GB"))
+ }
}
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
-> io::Result<isize>
{
+ use convert::TryInto;
use libc::pwrite64;
- cvt(pwrite64(fd, buf, count, offset as i32))
+ // pwrite64 on emscripten actually takes a 32 bit offset
+ if let Ok(o) = offset.try_into() {
+ cvt(pwrite64(fd, buf, count, o))
+ } else {
+ Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot pwrite >2GB"))
+ }
}
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
// Reallocate the last page of the stack.
// This ensures SIGBUS will be raised on
// stack overflow.
- let result = mmap(stackaddr, PAGE_SIZE, PROT_NONE,
+ // Systems which enforce strict PAX MPROTECT do not allow
+ // to mprotect() a mapping with less restrictive permissions
+ // than the initial mmap() used, so we mmap() here with
+ // read/write permissions and only then mprotect() it to
+ // no permissions at all. See issue #50313.
+ let result = mmap(stackaddr, PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
-
if result != stackaddr || result == MAP_FAILED {
panic!("failed to allocate a guard page");
}
+ let result = mprotect(stackaddr, PAGE_SIZE, PROT_NONE);
+ if result != 0 {
+ panic!("failed to protect the guard page");
+ }
+
let guardaddr = stackaddr as usize;
let offset = if cfg!(target_os = "freebsd") {
2
/// Example: `U+1F4A9`
impl fmt::Debug for CodePoint {
#[inline]
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "U+{:04X}", self.value)
}
}
/// Example: `"a\u{D800}"` for a string with code points [U+0061, U+D800]
impl fmt::Debug for Wtf8Buf {
#[inline]
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter)
}
}
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,
},
impl Edition {
pub fn lint_name(&self) -> &'static str {
match *self {
- Edition::Edition2015 => "rust_2015_breakage",
- Edition::Edition2018 => "rust_2018_breakage",
+ Edition::Edition2015 => "rust_2015_compatibility",
+ Edition::Edition2018 => "rust_2018_compatibility",
}
}
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);
(active, rustc_attrs, "1.0.0", Some(29642), None),
// Allows the use of non lexical lifetimes; RFC 2094
- (active, nll, "1.0.0", Some(43234), Some(Edition::Edition2018)),
+ (active, nll, "1.0.0", Some(43234), None),
// Allows the use of #[allow_internal_unstable]. This is an
// attribute on macro_rules! and can't use the attribute handling
// 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),
);
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";
continue
}
- match attr.meta_item_list() {
+ let list = match attr.meta_item_list() {
+ Some(list) => list,
None => {
span_err!(span_handler, attr.span, E0555,
"malformed feature attribute, expected #![feature(...)]");
+ continue
+ }
+ };
+
+ for mi in list {
+ let name = if let Some(word) = mi.word() {
+ word.name()
+ } else {
+ span_err!(span_handler, mi.span, E0556,
+ "malformed feature, expected just one word");
+ continue
+ };
+
+ if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
+ set(&mut features, mi.span);
+ feature_checker.collect(&features, mi.span);
+ continue
}
- Some(list) => {
- for mi in list {
- let name = if let Some(word) = mi.word() {
- word.name()
- } else {
- span_err!(span_handler, mi.span, E0556,
- "malformed feature, expected just one word");
- continue
- };
-
- if let Some(&(_, _, _, _, set)) = ACTIVE_FEATURES.iter()
- .find(|& &(n, ..)| name == n) {
- set(&mut features, mi.span);
- feature_checker.collect(&features, mi.span);
- }
- else if let Some(&(.., reason)) = REMOVED_FEATURES.iter()
- .find(|& &(n, ..)| name == n)
- .or_else(|| STABLE_REMOVED_FEATURES.iter()
- .find(|& &(n, ..)| name == n)) {
- feature_removed(span_handler, mi.span, reason);
- }
- else if let Some(&(..)) = ACCEPTED_FEATURES.iter()
- .find(|& &(n, ..)| name == n) {
- features.declared_stable_lang_features.push((name, mi.span));
- } else if let Some(&edition) = ALL_EDITIONS.iter()
- .find(|e| name == e.feature_name()) {
- if edition <= crate_edition {
- feature_removed(span_handler, mi.span, None);
- } else {
- for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
- if let Some(f_edition) = f_edition {
- if edition >= f_edition {
- // FIXME(Manishearth) there is currently no way to set
- // lib features by edition
- set(&mut features, DUMMY_SP);
- }
- }
- }
+ let removed = REMOVED_FEATURES.iter().find(|f| name == f.0);
+ let stable_removed = STABLE_REMOVED_FEATURES.iter().find(|f| name == f.0);
+ if let Some((.., reason)) = removed.or(stable_removed) {
+ feature_removed(span_handler, mi.span, *reason);
+ continue
+ }
+
+ if ACCEPTED_FEATURES.iter().any(|f| name == f.0) {
+ features.declared_stable_lang_features.push((name, mi.span));
+ continue
+ }
+
+ if let Some(edition) = ALL_EDITIONS.iter().find(|e| name == e.feature_name()) {
+ if *edition <= crate_edition {
+ continue
+ }
+
+ for &(.., f_edition, set) in ACTIVE_FEATURES.iter() {
+ if let Some(f_edition) = f_edition {
+ if *edition >= f_edition {
+ // FIXME(Manishearth) there is currently no way to set
+ // lib features by edition
+ set(&mut features, DUMMY_SP);
}
- } else {
- features.declared_lib_features.push((name, mi.span));
}
}
+
+ continue
}
+
+ features.declared_lib_features.push((name, mi.span));
}
}
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)),
}
}
-struct Globals {
+pub struct Globals {
used_attrs: Lock<Vec<u64>>,
known_attrs: Lock<Vec<u64>>,
syntax_pos_globals: syntax_pos::Globals,
})
}
-scoped_thread_local!(static GLOBALS: Globals);
+scoped_thread_local!(pub static GLOBALS: Globals);
#[macro_use]
pub mod diagnostics {
(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());
}
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;
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);
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()?;
let vis = p.parse_visibility(true)?;
let ty = p.parse_ty()?;
Ok(StructField {
- span: lo.to(p.span),
+ span: lo.to(ty.span),
vis,
ident: None,
id: ast::DUMMY_NODE_ID,
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),
// 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
+ }
}
}
impl<'a> std::fmt::Debug for StrCursor<'a> {
- fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after())
}
}
[dependencies]
serialize = { path = "../libserialize" }
rustc_data_structures = { path = "../librustc_data_structures" }
+arena = { path = "../libarena" }
scoped-tls = { version = "0.1.1", features = ["nightly"] }
unicode-width = "0.1.4"
//! `[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;
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{Lrc, Lock};
+extern crate arena;
extern crate rustc_data_structures;
#[macro_use]
impl Copy for Span {}
impl Clone for Span {
+ #[inline]
fn clone(&self) -> Span {
*self
}
}
impl PartialEq for Span {
+ #[inline]
fn eq(&self, other: &Span) -> bool {
let a = self.0;
let b = other.0;
}
impl Eq for Span {}
impl Hash for Span {
+ #[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
let a = self.0;
a.hash(state)
use {Span, DUMMY_SP, GLOBALS};
use rustc_data_structures::fx::FxHashMap;
+use arena::DroplessArena;
use serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
+use std::str;
use std::cmp::{PartialEq, Ordering, PartialOrd, Ord};
use std::hash::{Hash, Hasher};
}
}
-#[derive(Default)]
+// The &'static strs in this type actually point into the arena
pub struct Interner {
- names: FxHashMap<Box<str>, Symbol>,
- strings: Vec<Box<str>>,
+ arena: DroplessArena,
+ names: FxHashMap<&'static str, Symbol>,
+ strings: Vec<&'static str>,
gensyms: Vec<Symbol>,
}
impl Interner {
pub fn new() -> Self {
- Interner::default()
+ Interner {
+ arena: DroplessArena::new(),
+ names: Default::default(),
+ strings: Default::default(),
+ gensyms: Default::default(),
+ }
}
fn prefill(init: &[&str]) -> Self {
let mut this = Interner::new();
for &string in init {
- this.intern(string);
+ if string == "" {
+ // We can't allocate empty strings in the arena, so handle this here
+ let name = Symbol(this.strings.len() as u32);
+ this.names.insert("", name);
+ this.strings.push("");
+ } else {
+ this.intern(string);
+ }
}
this
}
}
let name = Symbol(self.strings.len() as u32);
- let string = string.to_string().into_boxed_str();
- self.strings.push(string.clone());
+
+ // from_utf8_unchecked is safe since we just allocated a &str which is known to be utf8
+ let string: &str = unsafe {
+ str::from_utf8_unchecked(self.arena.alloc_slice(string.as_bytes()))
+ };
+ // It is safe to extend the arena allocation to 'static because we only access
+ // these while the arena is still alive
+ let string: &'static str = unsafe {
+ &*(string as *const str)
+ };
+ self.strings.push(string);
self.names.insert(string, name);
name
}
pub fn get(&self, symbol: Symbol) -> &str {
match self.strings.get(symbol.0 as usize) {
- Some(ref string) => string,
+ Some(string) => string,
None => self.get(self.gensyms[(!0 - symbol.0) as usize]),
}
}
if self.symbol == other.symbol {
return Some(Ordering::Equal);
}
- self.with(|self_str| other.with(|other_str| self_str.partial_cmp(&other_str)))
+ self.with(|self_str| other.with(|other_str| self_str.partial_cmp(other_str)))
}
}
-Subproject commit b6c1a03fb498f6c03d1cbfd4404223a046f8c3b2
+Subproject commit fd7dd99edf371ac502ae4e70288c027f6692ace0
extern "C" void LLVMRustConfigurePassManagerBuilder(
LLVMPassManagerBuilderRef PMBR, LLVMRustCodeGenOptLevel OptLevel,
- bool MergeFunctions, bool SLPVectorize, bool LoopVectorize,
+ bool MergeFunctions, bool SLPVectorize, bool LoopVectorize, bool PrepareForThinLTO,
const char* PGOGenPath, const char* PGOUsePath) {
// Ignore mergefunc for now as enabling it causes crashes.
// unwrap(PMBR)->MergeFunctions = MergeFunctions;
unwrap(PMBR)->SLPVectorize = SLPVectorize;
unwrap(PMBR)->OptLevel = fromRust(OptLevel);
unwrap(PMBR)->LoopVectorize = LoopVectorize;
+#if LLVM_VERSION_GE(4, 0)
+ unwrap(PMBR)->PrepareForThinLTO = PrepareForThinLTO;
+#endif
#ifdef PGO_AVAILABLE
if (PGOGenPath) {
-Subproject commit 2f86c75a2479cf051b92fc98273daaf7f151e7a1
+Subproject commit a19ca1cd91cf97777af8268a6136bd2e4648e189
#![crate_type = "lib"]
-// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one"
+// CHECK: @VAR1 = constant i32 1, section ".test_one"
#[no_mangle]
#[link_section = ".test_one"]
-#[cfg(target_endian = "little")]
pub static VAR1: u32 = 1;
-#[no_mangle]
-#[link_section = ".test_one"]
-#[cfg(target_endian = "big")]
-pub static VAR1: u32 = 0x01000000;
-
pub enum E {
A(u32),
B(f32)
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;
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// intentionally empty
}
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() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:edition-extern-crate-allowed.rs
+// compile-flags: --edition 2015
+// compile-pass
+
+#![deny(rust_2018_idioms)]
+
+extern crate edition_extern_crate_allowed;
+
+fn main() {}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags:--edition 2018
+// compile-pass
+
+#![feature(rust_2018_preview)]
+
+fn main() {}
}
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() {}
--- /dev/null
+-include ../tools.mk
+
+all: foo
+ $(call RUN,foo)
+
+foo: foo.rs $(call NATIVE_STATICLIB,foo)
+ $(RUSTC) $< -lfoo $(EXTRACXXFLAGS)
+
+$(TMPDIR)/libfoo.o: foo.cpp
+ $(call COMPILE_OBJ_CXX,$@,$<)
+
+.PHONY: all
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <stdint.h>
+
+struct A {
+ A() { v = 1234; }
+ ~A() { v = 1; }
+ uint32_t v;
+};
+
+A a;
+
+extern "C" {
+ uint32_t get() {
+ return a.v;
+ }
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that linking to C++ code with global destructors works.
+
+extern { fn get() -> u32; }
+
+fn main() {
+ let i = unsafe { get() };
+ assert_eq!(i, 1234);
+}
ifdef IS_MSVC
COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -Fo:`cygpath -w $(1)` $(2)
NATIVE_STATICLIB_FILE = $(1).lib
NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
-Fo:`cygpath -w $(TMPDIR)/$(1).obj`
else
COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+COMPILE_OBJ_CXX = $(CXX) -c -o $(1) $(2)
NATIVE_STATICLIB_FILE = lib$(1).a
NATIVE_STATICLIB = $(call STATICLIB,$(1))
OUT_EXE=-o $(TMPDIR)/$(1)
OBJDUMP=llvm-objdump
SECTION_HEADERS=$(OBJDUMP) -section-headers
-BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1
+BUILD_LIB=$(RUSTC) lib.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1
-BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto -Ccodegen-units=1 --emit=obj
+BUILD_EXE=$(RUSTC) main.rs -Copt-level=2 -Z cross-lang-lto=no-link -Ccodegen-units=1 --emit=obj
all: staticlib staticlib-fat-lto staticlib-thin-lto rlib exe cdylib rdylib
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;
struct SlowFmt(u32);
impl fmt::Debug for SlowFmt {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
thread::sleep_ms(3);
self.0.fmt(f)
}
--- /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() {}
}
// If all the variants are uninhabited, however, the union should be uninhabited.
+// NOTE(#49298) the union being uninhabited shouldn't change its size.
union Bar {
_a: (Never, u64),
_b: (u64, Never)
fn main() {
assert_eq!(mem::size_of::<Foo>(), 8);
- assert_eq!(mem::size_of::<Bar>(), 0);
+ // See the note on `Bar`'s definition for why this isn't `0`.
+ assert_eq!(mem::size_of::<Bar>(), 8);
let f = [Foo { a: 42 }, Foo { a: 10 }];
println!("{}", unsafe { f[0].a });
--- /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(test)]
+
+extern crate test;
+
+enum Void {}
+
+fn main() {
+ let mut x: (Void, usize);
+ let mut y = 42;
+ x.1 = 13;
+
+ // Make sure `y` stays on the stack.
+ test::black_box(&mut y);
+
+ // Check that the write to `x.1` did not overwrite `y`.
+ // Note that this doesn't fail with optimizations enabled,
+ // because we can't keep `x.1` on the stack, like we can `y`,
+ // as we can't borrow partially initialized variables.
+ assert_eq!(y.to_string(), "42");
+
+ // Check that `(Void, usize)` has space for the `usize` field.
+ assert_eq!(std::mem::size_of::<(Void, usize)>(),
+ std::mem::size_of::<usize>());
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Void {}
+
+enum Foo {
+ A(i32),
+ B(Void),
+ C(i32)
+}
+
+fn main() {
+ let _foo = Foo::A(0);
+}
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum Void {}
+fn foo(_: Result<(Void, u32), (Void, String)>) {}
+fn main() {
+ let _: fn(_) = foo;
+}
// 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");
+}
A = 42 as u8,
}
-enum NicheFilledEnumWithInhabitedVariant {
+enum EnumWithMaybeUninhabitedVariant<T> {
A(&'static ()),
- B(&'static (), !),
+ B(&'static (), T),
+ C,
+}
+
+enum NicheFilledEnumWithAbsentVariant {
+ A(&'static ()),
+ B((), !),
C,
}
assert_eq!(size_of::<EnumSingle4>(), 1);
assert_eq!(size_of::<EnumSingle5>(), 1);
- assert_eq!(size_of::<NicheFilledEnumWithInhabitedVariant>(), size_of::<&'static ()>());
+ assert_eq!(size_of::<EnumWithMaybeUninhabitedVariant<!>>(),
+ size_of::<EnumWithMaybeUninhabitedVariant<()>>());
+ assert_eq!(size_of::<NicheFilledEnumWithAbsentVariant>(), size_of::<&'static ()>());
}
}
impl fmt::Display for U {
- fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
unsafe { write!(f, "Oh hai {}", self.a) }
}
}
--- /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`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --edition 2018
+
#![deny(unnecessary_extern_crate)]
#![feature(alloc, test, libc)]
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:14:1
+ --> $DIR/unnecessary-extern-crate.rs:16:1
|
LL | extern crate alloc;
| ^^^^^^^^^^^^^^^^^^^ help: remove it
|
note: lint level defined here
- --> $DIR/unnecessary-extern-crate.rs:11:9
+ --> $DIR/unnecessary-extern-crate.rs:13:9
|
LL | #![deny(unnecessary_extern_crate)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:17:1
+ --> $DIR/unnecessary-extern-crate.rs:19:1
|
LL | extern crate alloc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:23:1
+ --> $DIR/unnecessary-extern-crate.rs:25:1
|
LL | pub extern crate test as y;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:26:1
+ --> $DIR/unnecessary-extern-crate.rs:28:1
|
LL | pub extern crate libc;
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use libc;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:32:5
+ --> $DIR/unnecessary-extern-crate.rs:34:5
|
LL | extern crate alloc;
- | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+ | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:35:5
+ --> $DIR/unnecessary-extern-crate.rs:37:5
|
LL | extern crate alloc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:38:5
+ --> $DIR/unnecessary-extern-crate.rs:40:5
|
LL | pub extern crate test;
- | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test`
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:41:5
+ --> $DIR/unnecessary-extern-crate.rs:43:5
|
LL | pub extern crate test as y;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `pub use`: `pub use test as y;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:45:9
+ --> $DIR/unnecessary-extern-crate.rs:47:9
|
LL | extern crate alloc;
- | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc`
+ | ^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc;`
error: `extern crate` is unnecessary in the new edition
- --> $DIR/unnecessary-extern-crate.rs:48:9
+ --> $DIR/unnecessary-extern-crate.rs:50:9
|
LL | extern crate alloc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `use`: `use alloc as x;`
error: aborting due to 10 previous errors
LL | x % 2 == 0
| ^^^^^
|
- = note: this is a reference to a type that `%` can be applied to; you need to dereference this variable once for this operation to work
- = note: an implementation of `std::ops::Rem` might be missing for `&&{integer}`
+ = help: `%` can be used on '{integer}', you can dereference `x`: `*x`
error: aborting due to previous error
--> $DIR/issue-28308.rs:12:5
|
LL | assert!("foo");
- | ^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
error: aborting due to previous error
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![feature(duration_getters)]
+
+use std::time::Duration;
+
+fn main() {
+ const _ONE_SECOND: Duration = Duration::from_nanos(1_000_000_000);
+ const _ONE_MILLISECOND: Duration = Duration::from_nanos(1_000_000);
+ const _ONE_MICROSECOND: Duration = Duration::from_nanos(1_000);
+ const _ONE_NANOSECOND: Duration = Duration::from_nanos(1);
+ const _ONE: usize = _ONE_SECOND.as_secs() as usize;
+ const _TWO: usize = _ONE_MILLISECOND.subsec_millis() as usize;
+ const _THREE: usize = _ONE_MICROSECOND.subsec_micros() as usize;
+ const _FOUR: usize = _ONE_NANOSECOND.subsec_nanos() as usize;
+ const _0: [[u8; _ONE]; _TWO] = [[1; _ONE]; _TWO];
+ const _1: [[u8; _THREE]; _FOUR] = [[3; _THREE]; _FOUR];
+}
| -----------------^^^^^
| |
| cannot use `+=` on type `std::collections::LinkedList<_>`
+ |
+ = note: an implementation of `std::ops::AddAssign` might be missing for `std::collections::LinkedList<_>`
error[E0067]: invalid left-hand side expression
--> $DIR/E0067.rs:14:5
--> $DIR/E0600.rs:12:5
|
LL | !"a"; //~ ERROR E0600
- | ^^^^
+ | ^^^^ cannot apply unary operator `!`
error: aborting due to previous error
| -^^^^^
| |
| cannot use `+=` on type `&str`
+ |
+ = note: an implementation of `std::ops::AddAssign` might be missing for `&str`
error[E0599]: no method named `z` found for type `&str` in the current scope
--> $DIR/error-festival.rs:26:7
--> $DIR/error-festival.rs:29:5
|
LL | !Question::Yes;
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ cannot apply unary operator `!`
+ |
+ = note: an implementation of `std::ops::Not` might be missing for `Question`
error[E0604]: only `u8` can be cast as `char`, not `u32`
--> $DIR/error-festival.rs:35:5
+++ /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`.
--> $DIR/feature-gate-negate-unsigned.rs:20:23
|
LL | let _max: usize = -1;
- | ^^
+ | ^^ cannot apply unary operator `-`
+ |
+ = note: unsigned values cannot be negated
error[E0600]: cannot apply unary operator `-` to type `u8`
--> $DIR/feature-gate-negate-unsigned.rs:24:14
|
LL | let _y = -x;
- | ^^
+ | ^^ cannot apply unary operator `-`
+ |
+ = note: unsigned values cannot be negated
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 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`.
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-// FIXME(#44752) -- this scenario should not be warned
-fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
- 22
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-2.rs:12:10
- |
-LL | fn deref<'x>() -> &'x u32 { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-2.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- x: &'x u32 // no warning!
-}
-
-// Once #44524 is fixed, this should issue a warning.
-impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
- fn method() { }
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-3.rs:11:12
- |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-3.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'y` only used once
- --> $DIR/single_use_lifetimes-3.rs:16:6
- |
-LL | impl<'y> Foo<'y> { //~ ERROR lifetime name `'y` only used once
- | ^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
- // Neither should issue a warning, as explicit lifetimes are mandatory in this case
-struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- x: &'x u32
-}
-
-enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
- Variant(&'x u32)
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-4.rs:12:12
- |
-LL | struct Foo<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-4.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-4.rs:16:10
- |
-LL | enum Bar<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-// Should not issue a warning, as explicit lifetimes are mandatory in this case:
-trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
- fn foo(&self, arg: &'x u32);
-}
-
-fn main() { }
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes-5.rs:12:11
- |
-LL | trait Foo<'x> { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes-5.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-#![deny(single_use_lifetime)]
-
-fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
- *v
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime name `'x` only used once
- --> $DIR/single_use_lifetimes.rs:12:10
- |
-LL | fn deref<'x>(v: &'x u32) -> u32 { //~ ERROR lifetime name `'x` only used once
- | ^^
- |
-note: lint level defined here
- --> $DIR/single_use_lifetimes.rs:10:9
- |
-LL | #![deny(single_use_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
| ^^^^^^^^ recursive type has infinite size
...
LL | BarSome(Bar)
- | ---- recursive without indirection
+ | --- recursive without indirection
|
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
LL | enum Expr { //~ ERROR E0072
| ^^^^^^^^^ recursive type has infinite size
LL | Plus(Expr, Expr),
- | ----- ----- recursive without indirection
+ | ---- ---- recursive without indirection
| |
| recursive without indirection
|
...
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.
+
+#[derive(Clone, Copy)]
+//~^ ERROR the trait `Copy` may not be implemented for this type
+struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+//~^ ERROR cannot find type `NotDefined` in this scope
+//~| ERROR the trait bound `i32: std::iter::Iterator` is not satisfied
+
+fn main() {}
--- /dev/null
+error[E0412]: cannot find type `NotDefined` in this scope
+ --> $DIR/issue-50480.rs:13:12
+ |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^ not found in this scope
+
+error[E0277]: the trait bound `i32: std::iter::Iterator` is not satisfied
+ --> $DIR/issue-50480.rs:13:24
+ |
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator; maybe try calling `.iter()` or a similar method
+ |
+ = help: the trait `std::iter::Iterator` is not implemented for `i32`
+
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/issue-50480.rs:11:17
+ |
+LL | #[derive(Clone, Copy)]
+ | ^^^^
+LL | //~^ ERROR the trait `Copy` may not be implemented for this type
+LL | struct Foo(NotDefined, <i32 as Iterator>::Item, Vec<i32>, String);
+ | -------- ------ this field does not implement `Copy`
+ | |
+ | this field does not implement `Copy`
+
+error: aborting due to 3 previous errors
+
+Some errors occurred: E0204, E0277, E0412.
+For more information about an error, try `rustc --explain E0204`.
--- /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.
+
+struct Point {
+ pub x: u64,
+ pub y: u64,
+}
+
+const TEMPLATE: Point = Point {
+ x: 0,
+ y: 0
+};
+
+fn main() {
+ let _ = || {
+ Point {
+ nonexistent: 0,
+ //~^ ERROR struct `Point` has no field named `nonexistent`
+ ..TEMPLATE
+ }
+ };
+}
--- /dev/null
+error[E0560]: struct `Point` has no field named `nonexistent`
+ --> $DIR/issue-50618.rs:24:13
+ |
+LL | nonexistent: 0,
+ | ^^^^^^^^^^^ `Point` does not have this field
+ |
+ = note: available fields are: `x`, `y`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0560`.
| -^^^^^
| |
| cannot use `+=` on type `&isize`
+ |
+ = help: `+=` can be used on 'isize', you can dereference `x`: `*x`
error: aborting due to previous error
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`
+
mod private_mod {
// non-leaked `pub` items in private module should be linted
pub use std::fmt;
+ pub use std::env::{Args}; // braced-use has different item spans than unbraced
pub struct Hydrogen {
// `pub` struct fields, too
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:28:5
+ --> $DIR/unreachable_pub-pub_crate.rs:27:24
+ |
+LL | pub use std::env::{Args}; // braced-use has different item spans than unbraced
+ | ^^^^ help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub-pub_crate.rs:29:5
|
LL | pub struct Hydrogen {
| ---^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` field
- --> $DIR/unreachable_pub-pub_crate.rs:30:9
+ --> $DIR/unreachable_pub-pub_crate.rs:31:9
|
LL | pub neutrons: usize,
| ---^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `pub(crate)`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:36:9
+ --> $DIR/unreachable_pub-pub_crate.rs:37:9
|
LL | pub fn count_neutrons(&self) -> usize { self.neutrons }
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `pub(crate)`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:40:5
+ --> $DIR/unreachable_pub-pub_crate.rs:41:5
|
LL | pub enum Helium {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:41:5
+ --> $DIR/unreachable_pub-pub_crate.rs:42:5
|
LL | pub union Lithium { c1: usize, c2: u8 }
| ---^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:42:5
+ --> $DIR/unreachable_pub-pub_crate.rs:43:5
|
LL | pub fn beryllium() {}
| ---^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:43:5
+ --> $DIR/unreachable_pub-pub_crate.rs:44:5
|
LL | pub trait Boron {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:44:5
+ --> $DIR/unreachable_pub-pub_crate.rs:45:5
|
LL | pub const CARBON: usize = 1;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:45:5
+ --> $DIR/unreachable_pub-pub_crate.rs:46:5
|
LL | pub static NITROGEN: usize = 2;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:46:5
+ --> $DIR/unreachable_pub-pub_crate.rs:47:5
|
LL | pub type Oxygen = bool;
| ---^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:49:47
+ --> $DIR/unreachable_pub-pub_crate.rs:50:47
|
LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
| -----------^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub-pub_crate.rs:54:9
+ --> $DIR/unreachable_pub-pub_crate.rs:55:9
|
LL | pub fn catalyze() -> bool;
| ---^^^^^^^^^^^^^^^^^^^^^^^
mod private_mod {
// non-leaked `pub` items in private module should be linted
pub use std::fmt;
+ pub use std::env::{Args}; // braced-use has different item spans than unbraced
pub struct Hydrogen {
// `pub` struct fields, too
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:23:5
+ --> $DIR/unreachable_pub.rs:22:24
+ |
+LL | pub use std::env::{Args}; // braced-use has different item spans than unbraced
+ | ^^^^ help: consider restricting its visibility: `crate`
+ |
+ = help: or consider exporting it for use by other crates
+
+warning: unreachable `pub` item
+ --> $DIR/unreachable_pub.rs:24:5
|
LL | pub struct Hydrogen {
| ---^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` field
- --> $DIR/unreachable_pub.rs:25:9
+ --> $DIR/unreachable_pub.rs:26:9
|
LL | pub neutrons: usize,
| ---^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `crate`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:31:9
+ --> $DIR/unreachable_pub.rs:32:9
|
LL | pub fn count_neutrons(&self) -> usize { self.neutrons }
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| help: consider restricting its visibility: `crate`
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:35:5
+ --> $DIR/unreachable_pub.rs:36:5
|
LL | pub enum Helium {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:36:5
+ --> $DIR/unreachable_pub.rs:37:5
|
LL | pub union Lithium { c1: usize, c2: u8 }
| ---^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:37:5
+ --> $DIR/unreachable_pub.rs:38:5
|
LL | pub fn beryllium() {}
| ---^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:38:5
+ --> $DIR/unreachable_pub.rs:39:5
|
LL | pub trait Boron {}
| ---^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:39:5
+ --> $DIR/unreachable_pub.rs:40:5
|
LL | pub const CARBON: usize = 1;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:40:5
+ --> $DIR/unreachable_pub.rs:41:5
|
LL | pub static NITROGEN: usize = 2;
| ---^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:41:5
+ --> $DIR/unreachable_pub.rs:42:5
|
LL | pub type Oxygen = bool;
| ---^^^^^^^^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:44:47
+ --> $DIR/unreachable_pub.rs:45:47
|
LL | ($visibility: vis, $name: ident) => { $visibility struct $name {} }
| -----------^^^^^^^^^^^^^
= help: or consider exporting it for use by other crates
warning: unreachable `pub` item
- --> $DIR/unreachable_pub.rs:49:9
+ --> $DIR/unreachable_pub.rs:50:9
|
LL | pub fn catalyze() -> bool;
| ---^^^^^^^^^^^^^^^^^^^^^^^
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}>`"]
--> $DIR/expr_unary.rs:17:16
|
LL | let x: ! = ! { return; }; //~ ERROR unreachable
- | ^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^ cannot apply unary operator `!`
error: unreachable expression
--> $DIR/expr_unary.rs:17:16
// Type U needs to outlive lifetime 'b
struct Bar<'b, U> {
- field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+ field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
}
// Type K needs to outlive lifetime 'c.
enum Ying<'c, K> {
- One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
+ One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
}
struct Yang<V> {
|
LL | struct Bar<'b, U> {
| - help: consider adding an explicit lifetime bound `U: 'b`...
-LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
|
note: ...so that the reference type `&'b U` does not outlive the data it points at
--> $DIR/enum.rs:23:5
|
-LL | field2: &'b U //~ ERROR 23:5: 23:18: the parameter type `U` may not live long enough [E0309]
+LL | field2: &'b U //~ ERROR the parameter type `U` may not live long enough [E0309]
| ^^^^^^^^^^^^^
error[E0309]: the parameter type `K` may not live long enough
|
LL | enum Ying<'c, K> {
| - help: consider adding an explicit lifetime bound `K: 'c`...
-LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
- | ^^^^^^^^^^^^
+LL | One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
+ | ^^^^^^^^^^^
|
note: ...so that the reference type `&'c Yang<K>` does not outlive the data it points at
--> $DIR/enum.rs:30:9
|
-LL | One(&'c Yang<K>) //~ ERROR 30:9: 30:21: the parameter type `K` may not live long enough [E0309]
- | ^^^^^^^^^^^^
+LL | One(&'c Yang<K>) //~ ERROR the parameter type `K` may not live long enough [E0309]
+ | ^^^^^^^^^^^
error: aborting due to 2 previous errors
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
+//follow-up PR
+
+// A Collection trait and collection families. Based on
+// http://smallcultfollowing.com/babysteps/blog/2016/11/03/
+// associated-type-constructors-part-2-family-traits/
+
+trait Collection<T> {
+ type Iter<'iter>: Iterator<Item=&'iter T>;
+ type Family: CollectionFamily;
+ // Test associated type defaults with parameters
+ type Sibling<U>: Collection<U> =
+ <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
+ //~^ ERROR type parameters are not allowed on this type [E0109]
+
+ fn empty() -> Self;
+
+ fn add(&mut self, value: T);
+
+ fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+}
+
+trait CollectionFamily {
+ type Member<T>: Collection<T, Family = Self>;
+}
+
+struct VecFamily;
+
+impl CollectionFamily for VecFamily {
+ type Member<T> = Vec<T>;
+}
+
+impl<T> Collection<T> for Vec<T> {
+ type Iter<'iter> = std::slice::Iter<'iter, T>;
+ type Family = VecFamily;
+
+ fn empty() -> Self {
+ Vec::new()
+ }
+
+ fn add(&mut self, value: T) {
+ self.push(value)
+ }
+
+ fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ self.iter()
+ }
+}
+
+fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>
+//~^ ERROR type parameters are not allowed on this type [E0109]
+where
+ C: Collection<i32>,
+{
+ let mut res = C::Family::Member::<f32>::empty();
+ for &v in ints.iterate() {
+ res.add(v as f32);
+ }
+ res
+}
+
+fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+//~^ ERROR type parameters are not allowed on this type [E0109]
+where
+ C: Collection<i32>,
+{
+ let mut res = C::Family::Member::<f32>::empty();
+ for &v in ints.iterate() {
+ res.add(v as f32);
+ }
+ res
+}
+
+fn use_floatify() {
+ let a = vec![1i32, 2, 3];
+ let b = floatify(a);
+ println!("{}", b.iterate().next());
+ let c = floatify_sibling(a);
+ println!("{}", c.iterate().next());
+}
+
+fn main() {}
--- /dev/null
+error[E0109]: type parameters are not allowed on this type
+ --> $DIR/collections.rs:65:90
+ |
+LL | fn floatify<C>(ints: &C) -> <<C as Collection<i32>>::Family as CollectionFamily>::Member<f32>
+ | ^^^ type parameter not allowed
+
+error[E0109]: type parameters are not allowed on this type
+ --> $DIR/collections.rs:77:69
+ |
+LL | fn floatify_sibling<C>(ints: &C) -> <C as Collection<i32>>::Sibling<f32>
+ | ^^^ type parameter not allowed
+
+error[E0109]: type parameters are not allowed on this type
+ --> $DIR/collections.rs:26:71
+ |
+LL | <<Self as Collection<T>>::Family as CollectionFamily>::Member<U>;
+ | ^ type parameter not allowed
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/collections.rs:33:50
+ |
+LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter>;
+ | ^^^^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/collections.rs:59:50
+ |
+LL | fn iterate<'iter>(&'iter self) -> Self::Iter<'iter> {
+ | ^^^^^ lifetime parameter not allowed on this type
+
+error: aborting due to 5 previous errors
+
+Some errors occurred: E0109, E0110.
+For more information about an error, try `rustc --explain E0109`.
#![feature(generic_associated_types)]
+use std::ops::Deref;
+
//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
//follow-up PR
}
trait Baz {
- type Quux<'a>;
+ type Quux<'a>: Foo;
+
+ // This weird type tests that we can use universal function call syntax to access the Item on
+ type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ //~| ERROR lifetime parameters are not allowed on this type [E0110]
}
impl<T> Baz for T where T: Foo {
- type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
+ type Quux<'a> = T;
+
+ type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
}
error[E0110]: lifetime parameters are not allowed on this type
- --> $DIR/construct_with_other_type.rs:25:37
+ --> $DIR/construct_with_other_type.rs:26:46
|
-LL | type Quux<'a> = <T as Foo>::Bar<'a, 'static>;
- | ^^ lifetime parameter not allowed on this type
+LL | type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
+ | ^^ lifetime parameter not allowed on this type
-error: aborting due to previous error
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/construct_with_other_type.rs:26:63
+ |
+LL | type Baa<'a>: Deref<Target = <Self::Quux<'a> as Foo>::Bar<'a, 'static>>;
+ | ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/construct_with_other_type.rs:34:40
+ |
+LL | type Baa<'a> = &'a <T as Foo>::Bar<'a, 'static>;
+ | ^^ lifetime parameter not allowed on this type
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0110`.
type Iter<'a>: Iterator<Item = Self::Item<'a>>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
- // This weird type tests that we can use universal function call syntax to access the Item on
- // Self::Iter which we have declared to be an Iterator
- type Iter2<'a>: Deref<Target = <Self::Iter<'a> as Iterator>::Item>;
+ fn iter<'a>(&'a self) -> Self::Iter<'a>;
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
+}
- fn iter<'a>(&'a self) -> Self::Iter<'a>;
+// Impl for struct type
+impl<T> Iterable for Vec<T> {
+ type Item<'a> = &'a T;
+ type Iter<'a> = std::slice::Iter<'a, T>;
+
+ fn iter<'a>(&'a self) -> Self::Iter<'a> {
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ self.iter()
+ }
+}
+
+// Impl for a primitive type
+impl<T> Iterable for [T] {
+ type Item<'a> = &'a T;
+ type Iter<'a> = std::slice::Iter<'a, T>;
+
+ fn iter<'a>(&'a self) -> Self::Iter<'a> {
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ self.iter()
+ }
+}
+
+fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ it.iter()
+}
+
+fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ it.iter().next()
}
fn main() {}
| ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
- --> $DIR/iterable.rs:25:48
+ --> $DIR/iterable.rs:49:53
|
-LL | type Iter2<'a>: Deref<Target = <Self::Iter<'a> as Iterator>::Item>;
- | ^^ lifetime parameter not allowed on this type
+LL | fn make_iter<'a, I: Iterable>(it: &'a I) -> I::Iter<'a> {
+ | ^^ lifetime parameter not allowed on this type
error[E0110]: lifetime parameters are not allowed on this type
- --> $DIR/iterable.rs:28:41
+ --> $DIR/iterable.rs:54:60
+ |
+LL | fn get_first<'a, I: Iterable>(it: &'a I) -> Option<I::Item<'a>> {
+ | ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/iterable.rs:23:41
|
LL | fn iter<'a>(&'a self) -> Self::Iter<'a>;
| ^^ lifetime parameter not allowed on this type
-error: aborting due to 3 previous errors
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/iterable.rs:32:41
+ |
+LL | fn iter<'a>(&'a self) -> Self::Iter<'a> {
+ | ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/iterable.rs:43:41
+ |
+LL | fn iter<'a>(&'a self) -> Self::Iter<'a> {
+ | ^^ lifetime parameter not allowed on this type
+
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0110`.
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generic_associated_types)]
+#![feature(associated_type_defaults)]
+
+//FIXME(#44265): "lifetime parameters are not allowed on this type" errors will be addressed in a
+//follow-up PR
+
+//FIXME(#44265): Update expected errors once E110 is resolved, now does not get past `trait Foo`
+
+trait Foo {
+ type A<'a>;
+ type B<'a, 'b>;
+ type C;
+ type D<T>;
+ type E<'a, T>;
+ // Test parameters in default values
+ type FOk<T> = Self::E<'static, T>;
+ //~^ ERROR type parameters are not allowed on this type [E0109]
+ //~| ERROR lifetime parameters are not allowed on this type [E0110]
+ type FErr1 = Self::E<'static, 'static>; // Error
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ type FErr2<T> = Self::E<'static, T, u32>; // Error
+ //~^ ERROR type parameters are not allowed on this type [E0109]
+ //~| ERROR lifetime parameters are not allowed on this type [E0110]
+}
+
+struct Fooy;
+
+impl Foo for Fooy {
+ type A = u32; // Error: parameter expected
+ type B<'a, T> = Vec<T>; // Error: lifetime param expected
+ type C<'a> = u32; // Error: no param expected
+ type D<'a> = u32; // Error: type param expected
+ type E<T, U> = u32; // Error: lifetime expected as the first param
+}
+
+struct Fooer;
+
+impl Foo for Fooer {
+ type A<T> = u32; // Error: lifetime parameter expected
+ type B<'a> = u32; // Error: another lifetime param expected
+ type C<T> = T; // Error: no param expected
+ type D<'b, T> = u32; // Error: unexpected lifetime param
+ type E<'a, 'b> = u32; // Error: type expected as the second param
+}
+
+fn main() {}
--- /dev/null
+error[E0109]: type parameters are not allowed on this type
+ --> $DIR/parameter_number_and_kind.rs:26:36
+ |
+LL | type FOk<T> = Self::E<'static, T>;
+ | ^ type parameter not allowed
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/parameter_number_and_kind.rs:26:27
+ |
+LL | type FOk<T> = Self::E<'static, T>;
+ | ^^^^^^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/parameter_number_and_kind.rs:29:26
+ |
+LL | type FErr1 = Self::E<'static, 'static>; // Error
+ | ^^^^^^^ lifetime parameter not allowed on this type
+
+error[E0109]: type parameters are not allowed on this type
+ --> $DIR/parameter_number_and_kind.rs:31:38
+ |
+LL | type FErr2<T> = Self::E<'static, T, u32>; // Error
+ | ^ type parameter not allowed
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/parameter_number_and_kind.rs:31:29
+ |
+LL | type FErr2<T> = Self::E<'static, T, u32>; // Error
+ | ^^^^^^^ lifetime parameter not allowed on this type
+
+error: aborting due to 5 previous errors
+
+Some errors occurred: E0109, E0110.
+For more information about an error, try `rustc --explain E0109`.
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(generic_associated_types)]
+
+//FIXME(#44265): The lifetime shadowing and type parameter shadowing
+// should cause an error. Now it compiles (errorneously) and this will be addressed
+// by a future PR. Then remove the following:
+// compile-pass
+
+trait Shadow<'a> {
+ type Bar<'a>; // Error: shadowed lifetime
+}
+
+trait NoShadow<'a> {
+ type Bar<'b>; // OK
+}
+
+impl<'a> NoShadow<'a> for &'a u32 {
+ type Bar<'a> = i32; // Error: shadowed lifetime
+}
+
+trait ShadowT<T> {
+ type Bar<T>; // Error: shadowed type parameter
+}
+
+trait NoShadowT<T> {
+ type Bar<U>; // OK
+}
+
+impl<T> NoShadowT<T> for Option<T> {
+ type Bar<T> = i32; // Error: shadowed type parameter
+}
+
+fn main() {}
fn foo<T>(iter: T) where T: StreamingIterator, for<'a> T::Item<'a>: Display { /* ... */ }
//~^ ERROR lifetime parameters are not allowed on this type [E0110]
+// Full example of enumerate iterator
+
+#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
+struct StreamEnumerate<I> {
+ iter: I,
+ count: usize,
+}
+
+impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
+ type Item<'a> = (usize, I::Item<'a>);
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ fn next<'a>(&'a self) -> Option<Self::Item<'a>> {
+ //~^ ERROR lifetime parameters are not allowed on this type [E0110]
+ match self.iter.next() {
+ None => None,
+ Some(val) => {
+ let r = Some((self.count, val));
+ self.count += 1;
+ r
+ }
+ }
+ }
+}
+
+impl<I> StreamEnumerate<I> {
+ pub fn new(iter: I) -> Self {
+ StreamEnumerate {
+ count: 0,
+ iter: iter,
+ }
+ }
+}
+
+fn test_stream_enumerate() {
+ let v = vec!["a", "b", "c"];
+ let se = StreamEnumerate::new(v.iter());
+ let a: &str = se.next().unwrap().1;
+ for (i, s) in se {
+ println!("{} {}", i, s);
+ }
+ println!("{}", a);
+}
+
+
fn main() {}
LL | fn next<'a>(&'a self) -> Option<Self::Item<'a>>;
| ^^ lifetime parameter not allowed on this type
-error: aborting due to 3 previous errors
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/streaming_iterator.rs:47:37
+ |
+LL | type Item<'a> = (usize, I::Item<'a>);
+ | ^^ lifetime parameter not allowed on this type
+
+error[E0110]: lifetime parameters are not allowed on this type
+ --> $DIR/streaming_iterator.rs:49:48
+ |
+LL | fn next<'a>(&'a self) -> Option<Self::Item<'a>> {
+ | ^^ lifetime parameter not allowed on this type
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0110`.
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+struct Foo {
+ a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+ b: for<'a> fn(&'a u32, &'a u32), // OK, used twice.
+ c: for<'a> fn(&'a u32) -> &'a u32, // OK, used twice.
+ d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+ //~^ ERROR return type references lifetime `'a`, which is not constrained by the fn input types
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` only used once
+ --> $DIR/fn-types.rs:19:10
+ |
+LL | a: for<'a> fn(&'a u32), //~ ERROR `'a` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/fn-types.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
+ --> $DIR/fn-types.rs:22:22
+ |
+LL | d: for<'a> fn() -> &'a u32, // OK, used only in return type.
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0581`.
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(in_band_lifetimes)]
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument, even with in band lifetimes.
+
+fn a(x: &'a u32, y: &'b u32) {
+ //~^ ERROR `'a` only used once
+ //~| ERROR `'b` only used once
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'b` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:19:22
+ |
+LL | fn a(x: &'a u32, y: &'b u32) {
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-fn-argument-in-band.rs:12:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-fn-argument-in-band.rs:19:10
+ |
+LL | fn a(x: &'a u32, y: &'b u32) {
+ | ^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn when lifetime name is used only
+// once in a fn argument.
+
+fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-fn-argument.rs:18:6
+ |
+LL | fn a<'a>(x: &'a u32) { //~ ERROR `'a` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-fn-argument.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn when lifetime name is used only
+// once in a fn return type -- using `'_` is not legal there,
+// as it must refer back to an argument.
+//
+// (Normally, using `'static` would be preferred, but there are
+// times when that is not what you want.)
+//
+// run-pass
+
+fn b<'a>() -> &'a u32 { // OK: used only in return type
+ &22
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an impl.
+//
+// (Actually, until #15872 is fixed, you can't use `'_` here, but
+// hopefully that will come soon.)
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a(&self) {
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'f` only used once
+ --> $DIR/one-use-in-inherent-impl-header.rs:24:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-inherent-impl-header.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO warn for a lifetime used only once in an inherent method.
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` only used once
+ --> $DIR/one-use-in-inherent-method-argument.rs:22:19
+ |
+LL | fn inherent_a<'a>(&self, data: &'a u32) { //~ ERROR `'a` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-inherent-method-argument.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: lifetime parameter `'f` only used once
+ --> $DIR/one-use-in-inherent-method-argument.rs:21:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+// Test that we DO NOT warn for a lifetime used just once in a return type,
+// where that return type is in an inherent method.
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a<'a>(&self) -> &'a u32 { // OK for 'a
+ &22
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'f` only used once
+ --> $DIR/one-use-in-inherent-method-return.rs:22:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-inherent-method-return.rs:11:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we do not warn for named lifetimes in structs,
+// even when they are only used once (since to not use a named
+// lifetime is illegal!)
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+enum Bar<'f> {
+ Data(&'f u32)
+}
+
+trait Baz<'f> { }
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn for a lifetime on an impl used only in `&self`
+// in a trait method.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+ type Item = &'f u32;
+
+ fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+ None
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'g` only used once
+ --> $DIR/one-use-in-trait-method-argument.rs:25:13
+ |
+LL | fn next<'g>(&'g mut self) -> Option<Self::Item> { //~ ERROR `'g` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/one-use-in-trait-method-argument.rs:14:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn when lifetime name is used in
+// both the argument and return.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32) -> &'a u32 { // OK: used twice
+ &22
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn when lifetime name is used multiple
+// argments, or more than once in a single argument.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn c<'a>(x: &'a u32, y: &'a u32) { // OK: used twice
+}
+
+fn d<'a>(x: (&'a u32, &'a u32)) { // OK: used twice
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> {
+ fn inherent_a(&self, data: &'f u32) {
+ }
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime used twice in an impl method and
+// header.
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ fn inherent_a<'a>(&self, data: &'a u32) -> &'a u32{
+ data
+ }
+}
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'f` only used once
+ --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:22:6
+ |
+LL | impl<'f> Foo<'f> { //~ ERROR `'f` only used once
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/two-uses-in-inherent-method-argument-and-return.rs:14:9
+ |
+LL | #![deny(single_use_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO NOT warn for a lifetime on an impl used in both
+// header and in an associated type.
+//
+// compile-pass
+
+#![deny(single_use_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo<'f> {
+ data: &'f u32
+}
+
+impl<'f> Iterator for Foo<'f> {
+ type Item = &'f u32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn d<'a>() { } //~ ERROR `'a` never used
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` never used
+ --> $DIR/zero-uses-in-fn.rs:17:6
+ |
+LL | fn d<'a>() { } //~ ERROR `'a` never used
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/zero-uses-in-fn.rs:13:9
+ |
+LL | #![deny(unused_lifetime)]
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that we DO warn when lifetime name is not used at all.
+
+#![deny(unused_lifetime)]
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct Foo { }
+
+impl<'a> Foo { } //~ ERROR `'a` never used
+
+fn main() { }
--- /dev/null
+error: lifetime parameter `'a` never used
+ --> $DIR/zero-uses-in-impl.rs:19:6
+ |
+LL | impl<'a> Foo { } //~ ERROR `'a` never used
+ | ^^
+ |
+note: lint level defined here
+ --> $DIR/zero-uses-in-impl.rs:13:9
+ |
+LL | #![deny(unused_lifetime)]
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
| ^^^^
LL | enum EFoo2<'a> {
LL | Bar(&'a mut bool),
- | ------------- this field does not implement `Copy`
+ | ------------ this field does not implement `Copy`
error: aborting due to 4 previous errors
| - 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
+
fn foo<T>(x: T, y: T) {
let z = x + y; //~ ERROR binary operation `+` cannot be applied to type `T`
}
+
+fn bar<T>(x: T) {
+ x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+}
|
= note: `T` might need a bound for `std::ops::Add`
-error: aborting due to previous error
+error[E0368]: binary assignment operation `+=` cannot be applied to type `T`
+ --> $DIR/missing_trait_impl.rs:19:5
+ |
+LL | x += x; //~ ERROR binary assignment operation `+=` cannot be applied to type `T`
+ | -^^^^^
+ | |
+ | cannot use `+=` on type `T`
+ |
+ = note: `T` might need a bound for `std::ops::AddAssign`
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0369`.
+Some errors occurred: E0368, E0369.
+For more information about an error, try `rustc --explain E0368`.
--> $DIR/union-sized-field.rs:23:11
|
LL | Value(T), //~ ERROR the trait bound `T: std::marker::Sized` is not satisfied
- | ^^ `T` does not have a constant size known at compile-time
+ | ^ `T` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `T`
= help: consider adding a `where T: std::marker::Sized` bound
--> $DIR/unsized-enum2.rs:33:8
|
LL | VA(W), //~ ERROR `W: std::marker::Sized` is not satisfied
- | ^^ `W` does not have a constant size known at compile-time
+ | ^ `W` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `W`
= help: consider adding a `where W: std::marker::Sized` bound
--> $DIR/unsized-enum2.rs:35:15
|
LL | VC(isize, Y), //~ ERROR `Y: std::marker::Sized` is not satisfied
- | ^^ `Y` does not have a constant size known at compile-time
+ | ^ `Y` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Y`
= help: consider adding a `where Y: std::marker::Sized` bound
--> $DIR/unsized-enum2.rs:39:8
|
LL | VE([u8]), //~ ERROR `[u8]: std::marker::Sized` is not satisfied
- | ^^^^^ `[u8]` does not have a constant size known at compile-time
+ | ^^^^ `[u8]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[u8]`
= note: no field of an enum variant may have a dynamically sized type
--> $DIR/unsized-enum2.rs:41:15
|
LL | VG(isize, [f32]), //~ ERROR `[f32]: std::marker::Sized` is not satisfied
- | ^^^^^^ `[f32]` does not have a constant size known at compile-time
+ | ^^^^^ `[f32]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[f32]`
= note: no field of an enum variant may have a dynamically sized type
--> $DIR/unsized-enum2.rs:51:8
|
LL | VM(Foo), //~ ERROR `Foo + 'static: std::marker::Sized` is not satisfied
- | ^^^^ `Foo + 'static` does not have a constant size known at compile-time
+ | ^^^ `Foo + 'static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Foo + 'static`
= note: no field of an enum variant may have a dynamically sized type
--> $DIR/unsized-enum2.rs:53:15
|
LL | VO(isize, FooBar), //~ ERROR `FooBar + 'static: std::marker::Sized` is not satisfied
- | ^^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time
+ | ^^^^^^ `FooBar + 'static` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `FooBar + 'static`
= note: no field of an enum variant may have a dynamically sized type
--> $DIR/unsized-enum2.rs:57:8
|
LL | VQ(<&'static [i8] as Deref>::Target), //~ ERROR `[i8]: std::marker::Sized` is not satisfied
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[i8]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[i8]`
= note: no field of an enum variant may have a dynamically sized type
--> $DIR/unsized-enum2.rs:60:15
|
LL | VS(isize, <&'static [f64] as Deref>::Target),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `[f64]` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `[f64]`
= note: no field of an enum variant may have a dynamically sized type
--> $DIR/unsized-enum2.rs:45:8
|
LL | VI(Path1), //~ ERROR `PathHelper1 + 'static: std::marker::Sized` is not satisfied
- | ^^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time
+ | ^^^^^ `PathHelper1 + 'static` does not have a constant size known at compile-time
|
= help: within `Path1`, the trait `std::marker::Sized` is not implemented for `PathHelper1 + 'static`
= note: required because it appears within the type `Path1`
--> $DIR/unsized-enum2.rs:47:15
|
LL | VK(isize, Path3), //~ ERROR `PathHelper3 + 'static: std::marker::Sized` is not satisfied
- | ^^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time
+ | ^^^^^ `PathHelper3 + 'static` does not have a constant size known at compile-time
|
= help: within `Path3`, the trait `std::marker::Sized` is not implemented for `PathHelper3 + 'static`
= note: required because it appears within the type `Path3`
echo " $0 ../../../build/x86_64-apple-darwin/test/ui *.rs */*.rs"
fi
+MYDIR=$(dirname $0)
BUILD_DIR="$1"
shift
shopt -s nullglob
while [[ "$1" != "" ]]; do
- MYDIR=$(dirname $1)
for EXT in "stderr" "stdout" "fixed"; do
for OUT_NAME in $BUILD_DIR/${1%.rs}.*$EXT; do
+ OUT_DIR=`dirname "$1"`
OUT_BASE=`basename "$OUT_NAME"`
- if ! (diff $OUT_NAME $MYDIR/$OUT_BASE >& /dev/null); then
- echo updating $MYDIR/$OUT_BASE
- cp $OUT_NAME $MYDIR
+ if ! (diff $OUT_NAME $MYDIR/$OUT_DIR/$OUT_BASE >& /dev/null); then
+ echo updating $MYDIR/$OUT_DIR/$OUT_BASE
+ cp $OUT_NAME $MYDIR/$OUT_DIR
fi
done
done
-Subproject commit e456241f18227c7eb8d78a45daa66c756a9b65e7
+Subproject commit c658fc8cbcd1f199edd445a49cb43139ebdc5f02
.env("IS_WINDOWS", "1")
.env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
.env("CC", format!("'{}' {}", self.config.cc, cflags))
- .env("CXX", &self.config.cxx);
+ .env("CXX", format!("'{}'", &self.config.cxx));
} else {
cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags))
.env("CXX", format!("{} {}", self.config.cxx, self.config.cflags))
-Subproject commit e0e1bd7ff778e5913b566c9e03224faecc0eb486
+Subproject commit 6a4c62c1673c3dabcc9a0c99018bd08fec46fda7
-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
static WHITELIST: &'static [Crate] = &[
Crate("aho-corasick"),
Crate("ar"),
+ Crate("arrayvec"),
Crate("atty"),
Crate("backtrace"),
Crate("backtrace-sys"),
Crate("cc"),
Crate("cfg-if"),
Crate("cmake"),
+ Crate("crossbeam-deque"),
+ Crate("crossbeam-epoch"),
+ Crate("crossbeam-utils"),
+ Crate("either"),
Crate("ena"),
Crate("env_logger"),
Crate("filetime"),
Crate("log"),
Crate("log_settings"),
Crate("memchr"),
+ Crate("memoffset"),
Crate("miniz-sys"),
+ Crate("nodrop"),
Crate("num_cpus"),
Crate("owning_ref"),
Crate("parking_lot"),
Crate("regex-syntax"),
Crate("remove_dir_all"),
Crate("rustc-demangle"),
+ Crate("rustc-rayon"),
+ Crate("rustc-rayon-core"),
Crate("scoped-tls"),
+ Crate("scopeguard"),
Crate("smallvec"),
Crate("stable_deref_trait"),
Crate("tempdir"),
&libcore_path,
&mut |subpath| t!(subpath.strip_prefix(&libcore_path)).starts_with("tests"),
&mut |subpath| {
- if t!(read_to_string(subpath)).contains("#[test]") {
- tidy_error!(
- bad,
- "{} contains #[test]; libcore tests must be placed inside `src/libcore/tests/`",
- subpath.display()
- );
+ if let Some("rs") = subpath.extension().and_then(|e| e.to_str()) {
+ match read_to_string(subpath) {
+ Ok(contents) => {
+ if contents.contains("#[test]") {
+ tidy_error!(
+ bad,
+ "{} contains #[test]; libcore tests must be placed inside \
+ `src/libcore/tests/`",
+ subpath.display()
+ );
+ }
+ }
+ Err(err) => {
+ panic!("failed to read file {:?}: {}", subpath, err);
+ }
+ }
}
},
);