Fix #[track_caller] shims for trait objects.
We were missing an Instance::resolve_for_fn_ptr in resolve_for_vtable.
Closes #74764.
branches:
- auto
- try
+ - try-perf
- master
pull_request:
branches:
name: PR
env:
CI_JOB_NAME: "${{ matrix.name }}"
- SCCACHE_BUCKET: rust-lang-gha-caches
- TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
- CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+ SCCACHE_BUCKET: rust-lang-ci-sccache2
+ TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+ CACHE_DOMAIN: ci-caches.rust-lang.org
if: "github.event_name == 'pull_request'"
strategy:
matrix:
with:
github_token: "${{ secrets.github_token }}"
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ - name: configure the PR in which the error message will be posted
+ run: "echo \"[CI_PR_NUMBER=$num]\""
+ env:
+ num: "${{ github.event.number }}"
+ if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
- name: add extra environment variables
run: src/ci/scripts/setup-environment.sh
env:
name: try
env:
CI_JOB_NAME: "${{ matrix.name }}"
- SCCACHE_BUCKET: rust-lang-gha-caches
- DEPLOY_BUCKET: rust-lang-gha
- TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
- TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+ SCCACHE_BUCKET: rust-lang-ci-sccache2
+ DEPLOY_BUCKET: rust-lang-ci2
+ TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+ TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
TOOLSTATE_PUBLISH: 1
- CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
- ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
- CACHE_DOMAIN: ci-caches-gha.rust-lang.org
- if: "github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+ ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+ CACHE_DOMAIN: ci-caches.rust-lang.org
+ if: "github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
strategy:
matrix:
include:
with:
github_token: "${{ secrets.github_token }}"
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ - name: configure the PR in which the error message will be posted
+ run: "echo \"[CI_PR_NUMBER=$num]\""
+ env:
+ num: "${{ github.event.number }}"
+ if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
- name: add extra environment variables
run: src/ci/scripts/setup-environment.sh
env:
name: auto
env:
CI_JOB_NAME: "${{ matrix.name }}"
- SCCACHE_BUCKET: rust-lang-gha-caches
- DEPLOY_BUCKET: rust-lang-gha
- TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
- TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+ SCCACHE_BUCKET: rust-lang-ci-sccache2
+ DEPLOY_BUCKET: rust-lang-ci2
+ TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+ TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
TOOLSTATE_PUBLISH: 1
- CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
- ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
- CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+ CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+ ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+ CACHE_DOMAIN: ci-caches.rust-lang.org
if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
strategy:
matrix:
with:
github_token: "${{ secrets.github_token }}"
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ - name: configure the PR in which the error message will be posted
+ run: "echo \"[CI_PR_NUMBER=$num]\""
+ env:
+ num: "${{ github.event.number }}"
+ if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
- name: add extra environment variables
run: src/ci/scripts/setup-environment.sh
env:
with:
github_token: "${{ secrets.github_token }}"
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
+ - name: configure the PR in which the error message will be posted
+ run: "echo \"[CI_PR_NUMBER=$num]\""
+ env:
+ num: "${{ github.event.number }}"
+ if: "success() && !env.SKIP_JOBS && github.event_name == 'pull_request'"
- name: add extra environment variables
run: src/ci/scripts/setup-environment.sh
env:
name: master
runs-on: ubuntu-latest
env:
- SCCACHE_BUCKET: rust-lang-gha-caches
- DEPLOY_BUCKET: rust-lang-gha
- TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
- TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/pietroalbini/rust-toolstate/issues"
+ SCCACHE_BUCKET: rust-lang-ci-sccache2
+ DEPLOY_BUCKET: rust-lang-ci2
+ TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
+ TOOLSTATE_ISSUES_API_URL: "https://api.github.com/repos/rust-lang/rust/issues"
TOOLSTATE_PUBLISH: 1
- CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
- ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
- CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+ CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+ ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+ CACHE_DOMAIN: ci-caches.rust-lang.org
if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
steps:
- name: checkout the source code
try-success:
needs:
- try
- if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
steps:
- name: mark the job as a success
run: exit 0
try-failure:
needs:
- try
- if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
steps:
- name: mark the job as a failure
run: exit 1
[submodule "src/tools/rust-analyzer"]
path = src/tools/rust-analyzer
url = https://github.com/rust-analyzer/rust-analyzer.git
-[submodule "src/backtrace"]
- path = src/backtrace
- url = https://github.com/rust-lang/backtrace-rs.git
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
-name = "addr2line"
-version = "0.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
-dependencies = [
- "compiler_builtins",
- "gimli",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
-[[package]]
-name = "adler"
-version = "0.2.2"
+name = "adler32"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccc9a9dd069569f212bc4330af9f17c4afb5e8ce185e83dbb14f1349dda18b10"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
+checksum = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
[[package]]
name = "aho-corasick"
[[package]]
name = "backtrace"
-version = "0.3.50"
+version = "0.3.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1e692897359247cc6bb902933361652380af0f1b7651ae5c5013407f30e109e"
dependencies = [
- "addr2line",
+ "backtrace-sys",
"cfg-if",
+ "compiler_builtins",
"libc",
- "miniz_oxide",
- "object",
"rustc-demangle",
+ "rustc-std-workspace-core",
+]
+
+[[package]]
+name = "backtrace-sys"
+version = "0.1.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18fbebbe1c9d1f383a9cc7e8ccdb471b91c8d024ee9c2ca5b5346121fe8b4399"
+dependencies = [
+ "cc",
+ "compiler_builtins",
+ "libc",
+ "rustc-std-workspace-core",
]
[[package]]
[[package]]
name = "cargo"
-version = "0.47.0"
+version = "0.48.0"
dependencies = [
"anyhow",
"atty",
[[package]]
name = "cc"
-version = "1.0.57"
+version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fde55d2a2bfaa4c9668bbc63f531fbdeee3ffe188f4662511ce2c22b3eedebe"
+checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518"
dependencies = [
"jobserver",
]
[[package]]
name = "crc32fast"
-version = "1.2.0"
+version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
+checksum = "e91d5240c6975ef33aeb5f148f35275c25eda8e8a5f95abe421978b05b8bf192"
dependencies = [
"cfg-if",
]
[[package]]
name = "flate2"
-version = "1.0.16"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
+checksum = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3"
dependencies = [
"cfg-if",
"crc32fast",
"wasi",
]
-[[package]]
-name = "gimli"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
[[package]]
name = "git2"
version = "0.13.5"
[[package]]
name = "hermit-abi"
-version = "0.1.14"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909"
+checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
dependencies = [
"compiler_builtins",
"libc",
[[package]]
name = "libc"
-version = "0.2.71"
+version = "0.2.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+checksum = "bd7d4bd64732af4bf3a67f367c27df8520ad7e230c5817b8ff485864d80242b9"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "miniz_oxide"
-version = "0.4.0"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
+checksum = "6f3f74f726ae935c3f514300cc6773a0c9492abc5e972d42ba0c0ebb88757625"
dependencies = [
- "adler",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
+ "adler32",
]
[[package]]
"libc",
]
-[[package]]
-name = "object"
-version = "0.20.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
[[package]]
name = "once_cell"
version = "1.1.0"
[[package]]
name = "racer"
-version = "2.1.35"
+version = "2.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "421174f19211ba9e5fda34aa0cbc292188aae8e0cfbff4aebbae23f1a416bfb3"
+checksum = "09ba6cca9fcd8ae086b842b1bd9e3f19f104a4c30e0e8927b2befc06d375e7e0"
dependencies = [
"bitflags",
"clap",
[[package]]
name = "rustc-ap-rustc_arena"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c6683b49209f8b132bec33dc6b6c8f9958c8c94eb3586d4cb495e092b61c1da"
+checksum = "c9cdd301e9dcb15ead384fc07196c850fd22829fae81d296b2ed6b4b10bf3278"
dependencies = [
"rustc-ap-rustc_data_structures",
"smallvec 1.4.0",
[[package]]
name = "rustc-ap-rustc_ast"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b21784d92fb2d584800f528866f00fe814f73abda794f406bfd1fbb2f1ca7f7"
+checksum = "3f7c0d0537ca69dfe4a49212035295dfb37a235b5df01aa877d50b247f4775b8"
dependencies = [
"bitflags",
"log",
[[package]]
name = "rustc-ap-rustc_ast_passes"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "820c46fde7ef1df0432073090d775f097b7279ca75ea34ba954081ce4b884d4c"
+checksum = "d4cf4dca95f55f70eeb193fb08554026d79d0628de771fd726bb609e36887b82"
dependencies = [
"itertools 0.8.0",
"log",
[[package]]
name = "rustc-ap-rustc_ast_pretty"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "013db7dd198fe95962d2cefa5bd0b350cf2028af77c169b17b4baa9c3bbf77d1"
+checksum = "202bd2886d0cfa48baa3711042c14843f1b4852555b7ee7e5376bf66b276cb8d"
dependencies = [
"log",
"rustc-ap-rustc_ast",
[[package]]
name = "rustc-ap-rustc_attr"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35b5a85c90eb341eec543600ffdd9e262da5ea72a73a23ae4ca2f4ab8cd1a188"
+checksum = "b11ee1d92b3214e8a8c7829eff84cc1b03925da0ea5c6900cefe05b99edb4682"
dependencies = [
"rustc-ap-rustc_ast",
"rustc-ap-rustc_ast_pretty",
[[package]]
name = "rustc-ap-rustc_data_structures"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b92e4c6cb6c43ee9031a71709dc12853b358253c2b41d12a26379994fab625e0"
+checksum = "7a45d43b974d4cb9e32e5a15119c5eb7672c306ef09b064f2125b6a0399f6656"
dependencies = [
"bitflags",
"cfg-if",
[[package]]
name = "rustc-ap-rustc_errors"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b0aa79423260c1b9e2f856e144e040f606b0f5d43644408375becf9d7bcdf86"
+checksum = "8cd895d440820aaa04e6dc5486105494920a1e9779b9b051e8dba4ca5c182f94"
dependencies = [
"annotate-snippets 0.8.0",
"atty",
[[package]]
name = "rustc-ap-rustc_expand"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c07d76ba2a1b7d4325a2ed21d6345ccebd89ddc6666a1535a6edd489fb4cbc11"
+checksum = "71a0cc7820860d6691bf0aa7a95cdbc60f6587b495c18e0fa15a888fdabbf171"
dependencies = [
"log",
"rustc-ap-rustc_ast",
[[package]]
name = "rustc-ap-rustc_feature"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bbd625705c1db42a0c7503736292813d7b76ada5da20578fb55c63228c80ab5"
+checksum = "5473d5106401aa46f881eb91772f0a41fd5f28ae6134cf4b450eb1370ea6af22"
dependencies = [
"lazy_static",
"rustc-ap-rustc_data_structures",
[[package]]
name = "rustc-ap-rustc_fs_util"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34cca6e2942fa0b059c582437ead666d5bcf20fa7c242599e2bbea9b609f29ae"
+checksum = "8da1d57ee7a7ef55f31a97d99c7f919f02fc9a60ab96faa8cf45a7ae3ab1ccbf"
[[package]]
name = "rustc-ap-rustc_graphviz"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13d6a029b81f5e02da85763f82c135507f278a4a0c776432c728520563059529"
+checksum = "e3af62b20460908378cd1d354917acd9553376c5363bbb4e465f949bd82bdef9"
[[package]]
name = "rustc-ap-rustc_index"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bae50852d303e230b2781c994513788136dc6c2fe4ebe032959f0b990a425767"
+checksum = "3af7d4c456fe7647453d3fcd58335c9d512d1ff9a239a370b7ebdd353d69f66f"
dependencies = [
"rustc-ap-rustc_serialize",
"smallvec 1.4.0",
[[package]]
name = "rustc-ap-rustc_lexer"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7186e74aa2d31bf0e2454325fefcdf0a3da77d9344134592144b9e40d45b15d"
+checksum = "456af5f09c006cf6c22c1a433ee0232c4bb74bdc6c647a010166a47c94ed2a63"
dependencies = [
"unicode-xid 0.2.0",
]
[[package]]
name = "rustc-ap-rustc_macros"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fc1add04e9d2301164118660ee0bc3266e9a7b1973fc2303fdbe002a12e5401"
+checksum = "64f6acd192f313047759a346b892998b626466b93fe04f415da5f38906bb3b4c"
dependencies = [
"proc-macro2 1.0.3",
"quote 1.0.2",
[[package]]
name = "rustc-ap-rustc_parse"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cd7fc4968bd60084f2fa4f280fa450b0cf98660a7983d6b93a7ae41b6d1d322"
+checksum = "c006e8117c1c55e42bb56386c86ce6f7e4b47349e0bec7888c1d24784272e61b"
dependencies = [
"bitflags",
"log",
[[package]]
name = "rustc-ap-rustc_serialize"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00bf4c110271d9a2b7dfd2c6eb82e56fd80606a8bad6c102e158c54e44044046"
+checksum = "306ced69beaeebe4de9552ee751eb54ea25b5f34a73fe80f5f9cbbe15ccebc48"
dependencies = [
"indexmap",
"smallvec 1.4.0",
[[package]]
name = "rustc-ap-rustc_session"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "431cf962de71d4c03fb877d54f331ec36eca77350b0539017abc40a4410d6501"
+checksum = "dbff48435f5a476365e3ab5f49e07f98715cecb2d8c5bbcafeaf3aec638407be"
dependencies = [
+ "bitflags",
"getopts",
"log",
"num_cpus",
[[package]]
name = "rustc-ap-rustc_span"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b912039640597624f4bcb75f1e1fcfa5710267d715a7f73a6336baef341b23d1"
+checksum = "ec4273af0abbe78fc4585316ab193445c848c555e9203ddc28af02330918bf30"
dependencies = [
"cfg-if",
"log",
[[package]]
name = "rustc-ap-rustc_target"
-version = "664.0.0"
+version = "669.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51347a9dadc5ad0b5916cc12d42624b31955285ad13745dbe72f0140038b84e9"
+checksum = "6f9a2d6004ce6ad492a8eeacc2569b1c008169434b8828996d8dade4e5c6b6ee"
dependencies = [
"bitflags",
"log",
[[package]]
name = "rustfmt-nightly"
-version = "1.4.18"
+version = "1.4.19"
dependencies = [
"annotate-snippets 0.6.1",
"anyhow",
name = "std"
version = "0.0.0"
dependencies = [
- "addr2line",
"alloc",
+ "backtrace",
"cfg-if",
"compiler_builtins",
"core",
"hashbrown",
"hermit-abi",
"libc",
- "miniz_oxide",
- "object",
"panic_abort",
"panic_unwind",
"profiler_builtins",
"rand 0.7.3",
- "rustc-demangle",
"unwind",
"wasi",
]
rustc-std-workspace-alloc = { path = 'src/tools/rustc-std-workspace-alloc' }
rustc-std-workspace-std = { path = 'src/tools/rustc-std-workspace-std' }
-# This crate's integration with libstd is a bit wonky, so we use a submodule
-# instead of a crates.io dependency. Make sure everything else in the repo is
-# also using the submodule, however, so we can avoid duplicate copies of the
-# source code for this crate.
-backtrace = { path = "src/backtrace" }
-
[patch."https://github.com/rust-lang/rust-clippy"]
clippy_lints = { path = "src/tools/clippy/clippy_lints" }
"src/tools/rust-analyzer",
"src/tools/rust-installer",
"src/tools/rustfmt",
- "src/backtrace",
# We do not format this file as it is externally sourced and auto-generated.
"src/libstd/sys/cloudabi/abi/cloudabi.rs",
+++ /dev/null
-Subproject commit 8f89434446f72f27f8145d8bbc1a302c6ef29d1e
&& self.config.control_flow_guard
&& compiler.stage >= 1
{
- rustflags.arg("-Zcontrol-flow-guard");
+ rustflags.arg("-Ccontrol-flow-guard");
}
// For `cargo doc` invocations, make rustdoc print the Rust version into the docs
}
impl Cargo {
+ pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
+ self.rustdocflags.arg(arg);
+ self
+ }
pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
self.rustflags.arg(arg);
self
}
pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Cargo {
+ // These are managed through rustflag/rustdocflag interfaces.
+ assert_ne!(key.as_ref(), "RUSTFLAGS");
+ assert_ne!(key.as_ref(), "RUSTDOCFLAGS");
self.command.env(key.as_ref(), value.as_ref());
self
}
let name = pkgname(builder, "rust-docs");
if !builder.config.docs {
- return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
}
builder.default_doc(None);
builder.info(&format!("Dist docs ({})", host));
let _time = timeit(builder);
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
let _ = fs::remove_dir_all(&image);
let dst = image.join("share/doc/rust/html");
.arg(&tmpdir(builder))
.arg("--output-dir")
.arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, host))
+ .arg(format!("--package-name={}-{}", name, host.triple))
.arg("--component-name=rust-docs")
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--bulk-dirs=share/doc/rust/html");
builder.run(&mut cmd);
builder.remove_dir(&image);
- distdir(builder).join(format!("{}-{}.tar.gz", name, host))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
}
}
let name = pkgname(builder, "rustc-docs");
if !builder.config.compiler_docs {
- return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
}
builder.default_doc(None);
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
let _ = fs::remove_dir_all(&image);
let dst = image.join("share/doc/rust/html");
.arg(&tmpdir(builder))
.arg("--output-dir")
.arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, host))
+ .arg(format!("--package-name={}-{}", name, host.triple))
.arg("--component-name=rustc-docs")
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--bulk-dirs=share/doc/rust/html");
builder.run(&mut cmd);
builder.remove_dir(&image);
- distdir(builder).join(format!("{}-{}.tar.gz", name, host))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple))
}
}
builder.info(&format!("Dist mingw ({})", host));
let _time = timeit(builder);
let name = pkgname(builder, "rust-mingw");
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
let _ = fs::remove_dir_all(&image);
t!(fs::create_dir_all(&image));
.arg(&tmpdir(builder))
.arg("--output-dir")
.arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, host))
+ .arg(format!("--package-name={}-{}", name, host.triple))
.arg("--component-name=rust-mingw")
.arg("--legacy-manifest-dirs=rustlib,cargo");
builder.run(&mut cmd);
t!(fs::remove_dir_all(&image));
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host)))
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple)))
}
}
let host = self.compiler.host;
let name = pkgname(builder, "rustc");
- let image = tmpdir(builder).join(format!("{}-{}-image", name, host));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, host.triple));
let _ = fs::remove_dir_all(&image);
- let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host));
+ let overlay = tmpdir(builder).join(format!("{}-{}-overlay", name, host.triple));
let _ = fs::remove_dir_all(&overlay);
// Prepare the rustc "image", what will actually end up getting installed
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, host))
+ .arg(format!("--package-name={}-{}", name, host.triple))
.arg("--component-name=rustc")
.arg("--legacy-manifest-dirs=rustlib,cargo");
- builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host));
+ builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host.triple));
let _time = timeit(builder);
builder.run(&mut cmd);
builder.remove_dir(&image);
builder.remove_dir(&overlay);
- return distdir(builder).join(format!("{}-{}.tar.gz", name, host));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, host.triple));
fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
let host = compiler.host;
let target = self.target;
let name = pkgname(builder, "rust-std");
- let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target));
+ let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
if skip_host_target_lib(builder, compiler) {
return archive;
}
builder.ensure(compile::Std { compiler, target });
- let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
let _ = fs::remove_dir_all(&image);
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
.arg(&tmpdir(builder))
.arg("--output-dir")
.arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, target))
- .arg(format!("--component-name=rust-std-{}", target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
+ .arg(format!("--component-name=rust-std-{}", target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo");
builder
let target = self.target;
let name = pkgname(builder, "rustc-dev");
- let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target));
+ let archive = distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
if skip_host_target_lib(builder, compiler) {
return archive;
}
builder.ensure(compile::Rustc { compiler, target });
- let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
let _ = fs::remove_dir_all(&image);
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
.arg(&tmpdir(builder))
.arg("--output-dir")
.arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, target))
- .arg(format!("--component-name=rustc-dev-{}", target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
+ .arg(format!("--component-name=rustc-dev-{}", target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo");
builder.info(&format!(
let name = pkgname(builder, "rust-analysis");
if compiler.host != builder.config.build {
- return distdir(builder).join(format!("{}-{}.tar.gz", name, target));
+ return distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple));
}
builder.ensure(compile::Std { compiler, target });
- let image = tmpdir(builder).join(format!("{}-{}-image", name, target));
+ let image = tmpdir(builder).join(format!("{}-{}-image", name, target.triple));
let src = builder
.stage_out(compiler, Mode::Std)
.arg(&tmpdir(builder))
.arg("--output-dir")
.arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", name, target))
- .arg(format!("--component-name=rust-analysis-{}", target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
+ .arg(format!("--component-name=rust-analysis-{}", target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo");
builder.info("Dist analysis");
let _time = timeit(builder);
builder.run(&mut cmd);
builder.remove_dir(&image);
- distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
}
}
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
.arg("--component-name=cargo")
.arg("--legacy-manifest-dirs=rustlib,cargo");
builder.info(&format!("Dist cargo stage{} ({})", compiler.stage, target));
let _time = timeit(builder);
builder.run(&mut cmd);
- distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
}
}
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=rls-preview");
- builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target));
+ builder.info(&format!("Dist RLS stage{} ({})", compiler.stage, target.triple));
let _time = timeit(builder);
builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
}
}
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=rust-analyzer-preview");
builder.info(&format!("Dist rust-analyzer stage{} ({})", compiler.stage, target));
let _time = timeit(builder);
builder.run(&mut cmd);
- distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
}
}
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=clippy-preview");
builder.info(&format!("Dist clippy stage{} ({})", compiler.stage, target));
let _time = timeit(builder);
builder.run(&mut cmd);
- distdir(builder).join(format!("{}-{}.tar.gz", name, target))
+ distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))
}
}
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=miri-preview");
builder.info(&format!("Dist miri stage{} ({})", compiler.stage, target));
let _time = timeit(builder);
builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
}
}
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=rustfmt-preview");
builder.info(&format!("Dist Rustfmt stage{} ({})", compiler.stage, target));
let _time = timeit(builder);
builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
}
}
.arg(&work)
.arg("--output-dir")
.arg(&distdir(builder))
- .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target))
+ .arg(format!("--package-name={}-{}", pkgname(builder, "rust"), target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--input-tarballs")
.arg(input_tarballs)
let prepare = |name: &str| {
builder.create_dir(&pkg.join(name));
builder.cp_r(
- &work.join(&format!("{}-{}", pkgname(builder, name), target)),
+ &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)),
&pkg.join(name),
);
builder.install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
.arg(xform(&etc.join("pkg/Distribution.xml")))
.arg("--resources")
.arg(pkg.join("res"))
- .arg(distdir(builder).join(format!("{}-{}.pkg", pkgname(builder, "rust"), target)))
+ .arg(distdir(builder).join(format!(
+ "{}-{}.pkg",
+ pkgname(builder, "rust"),
+ target.triple
+ )))
.arg("--package-path")
.arg(&pkg);
let _time = timeit(builder);
let prepare = |name: &str| {
builder.create_dir(&exe.join(name));
let dir = if name == "rust-std" || name == "rust-analysis" {
- format!("{}-{}", name, target)
+ format!("{}-{}", name, target.triple)
} else if name == "rls" {
"rls-preview".to_string()
} else if name == "rust-analyzer" {
name.to_string()
};
builder.cp_r(
- &work.join(&format!("{}-{}", pkgname(builder, name), target)).join(dir),
+ &work.join(&format!("{}-{}", pkgname(builder, name), target.triple)).join(dir),
&exe.join(name),
);
builder.remove(&exe.join(name).join("manifest.in"));
builder.install(&etc.join("gfx/dialogbg.bmp"), &exe, 0o644);
builder.info(&format!("building `msi` installer with {:?}", light));
- let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target);
+ let filename = format!("{}-{}.msi", pkgname(builder, "rust"), target.triple);
let mut cmd = Command::new(&light);
cmd.arg("-nologo")
.arg("-ext")
.arg(&distdir(builder))
.arg("--non-installed-overlay")
.arg(&overlay)
- .arg(format!("--package-name={}-{}", name, target))
+ .arg(format!("--package-name={}-{}", name, target.triple))
.arg("--legacy-manifest-dirs=rustlib,cargo")
.arg("--component-name=llvm-tools-preview");
builder.run(&mut cmd);
- Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
+ Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple)))
}
}
// Build cargo command.
let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
- cargo.env(
- "RUSTDOCFLAGS",
- "--document-private-items \
- --enable-index-page -Zunstable-options",
- );
+ cargo.rustdocflag("--document-private-items");
+ cargo.rustdocflag("--enable-index-page");
+ cargo.rustdocflag("-Zunstable-options");
compile::rustc_cargo(builder, &mut cargo, target);
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("--no-deps");
cargo.arg("-p").arg("rustdoc");
- cargo.env("RUSTDOCFLAGS", "--document-private-items");
+ cargo.rustdocflag("--document-private-items");
builder.run(&mut cargo.into());
}
}
t!(fs::create_dir_all(&empty_dir));
let package_name = if let Some(host) = host {
- format!("{}-{}", pkgname(builder, name), host)
+ format!("{}-{}", pkgname(builder, name), host.triple)
} else {
pkgname(builder, name)
};
+use std::ffi::{OsStr, OsString};
+use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::time::{SystemTime, UNIX_EPOCH};
};
}
+/// Reads an environment variable and adds it to dependencies.
+/// Supposed to be used for all variables except those set for build scripts by cargo
+/// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts
+pub fn tracked_env_var_os<K: AsRef<OsStr> + Display>(key: K) -> Option<OsString> {
+ println!("cargo:rerun-if-env-changed={}", key);
+ env::var_os(key)
+}
+
// Because Cargo adds the compiler's dylib path to our library search path, llvm-config may
// break: the dylib path for the compiler, as of this writing, contains a copy of the LLVM
// shared library, which means that when our freshly built llvm-config goes to load it's
// perfect -- we might actually want to see something from Cargo's added library paths -- but
// for now it works.
pub fn restore_library_path() {
- println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH_VAR");
- println!("cargo:rerun-if-env-changed=REAL_LIBRARY_PATH");
- let key = env::var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
- if let Some(env) = env::var_os("REAL_LIBRARY_PATH") {
+ let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR");
+ if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") {
env::set_var(&key, &env);
} else {
env::remove_var(&key);
#####################################
#
-# Azure Pipelines "auto" branch build for Rust on Linux, macOS, and Windows.
+# Azure Pipelines "auto" branch build for Rust on macOS
#
pr: none
trigger:
- auto
-variables:
-- group: prod-credentials
-
jobs:
-- job: Linux
- timeoutInMinutes: 600
- pool:
- vmImage: ubuntu-16.04
- steps:
- - template: steps/run.yml
- strategy:
- matrix:
- x86_64-gnu-llvm-8:
- RUST_BACKTRACE: 1
- dist-x86_64-linux: {}
- dist-x86_64-linux-alt:
- IMAGE: dist-x86_64-linux
- arm-android: {}
- armhf-gnu: {}
- dist-various-1: {}
- dist-various-2: {}
- dist-aarch64-linux: {}
- dist-android: {}
- dist-arm-linux: {}
- dist-armhf-linux: {}
- dist-armv7-linux: {}
- dist-i586-gnu-i586-i686-musl: {}
- dist-i686-freebsd: {}
- dist-i686-linux: {}
- dist-mips-linux: {}
- dist-mips64-linux: {}
- dist-mips64el-linux: {}
- dist-mipsel-linux: {}
- dist-powerpc-linux: {}
- dist-powerpc64-linux: {}
- dist-powerpc64le-linux: {}
- dist-riscv64-linux: {}
- dist-s390x-linux: {}
- dist-x86_64-freebsd: {}
- dist-x86_64-illumos: {}
- dist-x86_64-musl: {}
- dist-x86_64-netbsd: {}
- i686-gnu: {}
- i686-gnu-nopt: {}
- test-various: {}
- wasm32: {}
- x86_64-gnu: {}
- x86_64-gnu-full-bootstrap: {}
- x86_64-gnu-aux: {}
- x86_64-gnu-tools:
- DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
- x86_64-gnu-debug: {}
- x86_64-gnu-nopt: {}
- x86_64-gnu-distcheck: {}
- mingw-check: {}
-
- job: macOS
timeoutInMinutes: 600
pool:
vmImage: macos-10.15
steps:
- template: steps/run.yml
+ variables:
+ # We're still uploading macOS builds from Azure Pipelines.
+ - group: prod-credentials
strategy:
matrix:
# OSX builders running tests, these run the full test suite.
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
-
-
-- job: Windows
- timeoutInMinutes: 600
- pool:
- vmImage: 'vs2017-win2016'
- steps:
- - template: steps/run.yml
- strategy:
- matrix:
- # 32/64 bit MSVC tests
- x86_64-msvc-1:
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
- SCRIPT: make ci-subset-1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- x86_64-msvc-2:
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
- SCRIPT: make ci-subset-2
- i686-msvc-1:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
- SCRIPT: make ci-subset-1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- i686-msvc-2:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
- SCRIPT: make ci-subset-2
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- x86_64-msvc-cargo:
- SCRIPT: python x.py test src/tools/cargotest src/tools/cargo
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld
- VCVARS_BAT: vcvars64.bat
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- # MSVC tools tests
- x86_64-msvc-tools:
- SCRIPT: src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh x.py
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --save-toolstates=/tmp/toolstate/toolstates.json
-
- # 32/64-bit MinGW builds.
- #
- # We are using MinGW with posix threads since LLVM does not compile with
- # the win32 threads version due to missing support for C++'s std::thread.
- #
- # Instead of relying on the MinGW version installed on appveryor we download
- # and install one ourselves so we won't be surprised by changes to appveyor's
- # build image.
- #
- # Finally, note that the downloads below are all in the `rust-lang-ci` S3
- # bucket, but they cleraly didn't originate there! The downloads originally
- # came from the mingw-w64 SourceForge download site. Unfortunately
- # SourceForge is notoriously flaky, so we mirror it on our own infrastructure.
- i686-mingw-1:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
- SCRIPT: make ci-mingw-subset-1
- CUSTOM_MINGW: 1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- i686-mingw-2:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
- SCRIPT: make ci-mingw-subset-2
- CUSTOM_MINGW: 1
- x86_64-mingw-1:
- SCRIPT: make ci-mingw-subset-1
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
- CUSTOM_MINGW: 1
- # FIXME(#59637)
- NO_DEBUG_ASSERTIONS: 1
- NO_LLVM_ASSERTIONS: 1
- x86_64-mingw-2:
- SCRIPT: make ci-mingw-subset-2
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
- CUSTOM_MINGW: 1
-
- # 32/64 bit MSVC and GNU deployment
- dist-x86_64-msvc:
- INITIAL_RUST_CONFIGURE_ARGS: >-
- --build=x86_64-pc-windows-msvc
- --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
- --enable-full-tools
- --enable-profiler
- SCRIPT: python x.py dist
- DIST_REQUIRE_ALL_TOOLS: 1
- dist-i686-msvc:
- INITIAL_RUST_CONFIGURE_ARGS: >-
- --build=i686-pc-windows-msvc
- --target=i586-pc-windows-msvc
- --enable-full-tools
- --enable-profiler
- SCRIPT: python x.py dist
- DIST_REQUIRE_ALL_TOOLS: 1
- dist-i686-mingw:
- INITIAL_RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
- SCRIPT: python x.py dist
- CUSTOM_MINGW: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- dist-x86_64-mingw:
- SCRIPT: python x.py dist
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
- CUSTOM_MINGW: 1
- DIST_REQUIRE_ALL_TOOLS: 1
-
- # "alternate" deployment, see .travis.yml for more info
- dist-x86_64-msvc-alt:
- INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
- SCRIPT: python x.py dist
+++ /dev/null
-#####################################
-## READ BEFORE CHANGING THIS ##
-#####################################
-
-# We're in the process of evaluating GitHub Actions as a possible replacement
-# for Azure Pipelines, and at the moment the configuration is duplicated
-# between the two CI providers. Be sure to also change the configuration in
-# src/ci/github-actions when changing this file.
-
-#####################################
-
-#
-# Azure Pipelines job to publish toolstate. Only triggers on pushes to master.
-#
-
-pr: none
-trigger:
- - master
-
-variables:
-- group: prod-credentials
-
-pool:
- vmImage: ubuntu-16.04
-
-steps:
-- checkout: self
- fetchDepth: 2
-
-- script: src/ci/publish_toolstate.sh
- displayName: Publish toolstate
- env:
- TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN)
+++ /dev/null
-#####################################
-## READ BEFORE CHANGING THIS ##
-#####################################
-
-# We're in the process of evaluating GitHub Actions as a possible replacement
-# for Azure Pipelines, and at the moment the configuration is duplicated
-# between the two CI providers. Be sure to also change the configuration in
-# src/ci/github-actions when changing this file.
-
-#####################################
-
-#
-# Azure Pipelines pull request build for Rust
-#
-
-trigger: none
-pr:
-- master
-
-variables:
-- group: public-credentials
-
-jobs:
-- job: Linux
- timeoutInMinutes: 600
- pool:
- vmImage: ubuntu-16.04
- steps:
- - template: steps/run.yml
- strategy:
- matrix:
- x86_64-gnu-llvm-8: {}
- mingw-check: {}
- x86_64-gnu-tools:
- CI_ONLY_WHEN_SUBMODULES_CHANGED: 1
trigger:
- try
-variables:
-- group: prod-credentials
-
jobs:
-- job: Linux
+- job: Dummy
timeoutInMinutes: 600
pool:
vmImage: ubuntu-16.04
steps:
- - template: steps/run.yml
- strategy:
- matrix:
- dist-x86_64-linux: {}
-
-# The macOS and Windows builds here are currently disabled due to them not being
-# overly necessary on `try` builds. We also don't actually have anything that
-# consumes the artifacts currently. Perhaps one day we can re-enable, but for now
-# it helps free up capacity on Azure.
-# - job: macOS
-# timeoutInMinutes: 600
-# pool:
-# vmImage: macos-10.15
-# steps:
-# - template: steps/run.yml
-# strategy:
-# matrix:
-# dist-x86_64-apple:
-# SCRIPT: ./x.py dist
-# INITIAL_RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc
-# DEPLOY: 1
-# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-# MACOSX_DEPLOYMENT_TARGET: 10.7
-# NO_LLVM_ASSERTIONS: 1
-# NO_DEBUG_ASSERTIONS: 1
-# DIST_REQUIRE_ALL_TOOLS: 1
-#
-# dist-x86_64-apple-alt:
-# SCRIPT: ./x.py dist
-# INITIAL_RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc
-# DEPLOY_ALT: 1
-# RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-# MACOSX_DEPLOYMENT_TARGET: 10.7
-# NO_LLVM_ASSERTIONS: 1
-# NO_DEBUG_ASSERTIONS: 1
-#
-# - job: Windows
-# timeoutInMinutes: 600
-# pool:
-# vmImage: 'vs2017-win2016'
-# steps:
-# - template: steps/run.yml
-# strategy:
-# matrix:
-# dist-x86_64-msvc:
-# INITIAL_RUST_CONFIGURE_ARGS: >
-# --build=x86_64-pc-windows-msvc
-# --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc
-# --enable-full-tools
-# --enable-profiler
-# SCRIPT: python x.py dist
-# DIST_REQUIRE_ALL_TOOLS: 1
-# DEPLOY: 1
-#
-# dist-x86_64-msvc-alt:
-# INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
-# SCRIPT: python x.py dist
-# DEPLOY_ALT: 1
+ - bash: echo "We're running this job since bors is still gating on Azure"
- Target options > Emit assembly for CPU = powerpc -- pure 32-bit PowerPC
- Operating System > Target OS = linux
- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
+- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
- C compiler > gcc version = 5.2.0
- C compiler > C++ = ENABLE -- to cross compile LLVM
- Target options > Tune for CPU = power6 -- (+)
- Operating System > Target OS = linux
- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
+- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
- C compiler > gcc version = 5.2.0
- C compiler > C++ = ENABLE -- to cross compile LLVM
- Target options > Bitness = 64-bit
- Operating System > Target OS = linux
- Operating System > Linux kernel version = 2.6.32.68 -- ~RHEL6 kernel
-- C-library > glibc version = 2.12.2 -- ~RHEL6 glibc
+- C-library > glibc version = 2.11.1 -- ~SLE11-SP4 glibc
- C compiler > gcc version = 5.2.0
- C compiler > gcc extra config = --with-arch=z10 -- LLVM's minimum support
- C compiler > C++ = ENABLE -- to cross compile LLVM
--- /dev/null
+From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
+From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
+Date: Thu, 1 Nov 2012 18:00:06 -0500
+Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
+
+---
+ sysdeps/powerpc/Makefile | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
+index 79dd6fa976d5..7442b6709ad1 100644
+--- a/sysdeps/powerpc/Makefile
++++ b/sysdeps/powerpc/Makefile
+@@ -1,7 +1,3 @@
+-# We always want to use the new mnemonic syntax even if we are on a RS6000
+-# machine.
+-+cflags += -mnew-mnemonics
+-
+ ifeq ($(subdir),gmon)
+ sysdep_routines += ppc-mcount
+ endif
+--
+2.9.3
+
--- /dev/null
+diff --git a/configure b/configure
+index b6752d147c6b..6089a3403410 100755
+--- a/configure
++++ b/configure
+@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
+ ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
+ case $ac_prog_version in
+ '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+- 3.4* | 4.[0-9]* )
++ 3.4* | [4-9].* )
+ ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+ *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+
+diff --git a/configure.in b/configure.in
+index 56849dfc489a..09677eb3d0c1 100644
+--- a/configure.in
++++ b/configure.in
+@@ -960,7 +960,7 @@ fi
+ # These programs are version sensitive.
+ AC_CHECK_TOOL_PREFIX
+ AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
+- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
++ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
+ critic_missing="$critic_missing gcc")
+ AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
+ [GNU Make[^0-9]*\([0-9][0-9.]*\)],
+++ /dev/null
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
---
-2.9.3
-
+++ /dev/null
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
- ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
- case $ac_prog_version in
- '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-- 3.4* | 4.[0-9]* )
-+ 3.4* | [4-9].* )
- ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
- *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
-
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
-- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
- critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
- [GNU Make[^0-9]*\([0-9][0-9.]*\)],
# C-library
#
CT_LIBC="glibc"
-CT_LIBC_VERSION="2.12.2"
+CT_LIBC_VERSION="2.11.1"
CT_LIBC_glibc=y
# CT_LIBC_musl is not set
# CT_LIBC_uClibc is not set
# CT_LIBC_GLIBC_V_2_14_1 is not set
# CT_LIBC_GLIBC_V_2_14 is not set
# CT_LIBC_GLIBC_V_2_13 is not set
-CT_LIBC_GLIBC_V_2_12_2=y
+# CT_LIBC_GLIBC_V_2_12_2 is not set
# CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
+CT_LIBC_GLIBC_V_2_11_1=y
# CT_LIBC_GLIBC_V_2_11 is not set
# CT_LIBC_GLIBC_V_2_10_1 is not set
# CT_LIBC_GLIBC_V_2_9 is not set
--- /dev/null
+From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
+From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
+Date: Thu, 1 Nov 2012 18:00:06 -0500
+Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
+
+---
+ sysdeps/powerpc/Makefile | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
+index 79dd6fa976d5..7442b6709ad1 100644
+--- a/sysdeps/powerpc/Makefile
++++ b/sysdeps/powerpc/Makefile
+@@ -1,7 +1,3 @@
+-# We always want to use the new mnemonic syntax even if we are on a RS6000
+-# machine.
+-+cflags += -mnew-mnemonics
+-
+ ifeq ($(subdir),gmon)
+ sysdep_routines += ppc-mcount
+ endif
+--
+2.9.3
+
--- /dev/null
+From a4f388e111ce05e2ab7912cff3c9070334bb74ae Mon Sep 17 00:00:00 2001
+From: Josh Stone <jistone@redhat.com>
+Date: Fri, 20 Jan 2017 15:41:56 -0800
+Subject: [PATCH] Prevent inlining in PPC64 initfini.s
+
+Ref: https://sourceware.org/ml/libc-alpha/2012-01/msg00195.html
+---
+ sysdeps/powerpc/powerpc64/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile
+index 78d4f07e575f..fe96aae4d43e 100644
+--- a/sysdeps/powerpc/powerpc64/Makefile
++++ b/sysdeps/powerpc/powerpc64/Makefile
+@@ -28,7 +28,7 @@ elide-routines.os += hp-timing
+ ifneq ($(elf),no)
+ # The initfini generation code doesn't work in the presence of -fPIC, so
+ # we use -fpic instead which is much better.
+-CFLAGS-initfini.s += -fpic -O1
++CFLAGS-initfini.s += -fpic -O1 -fno-inline
+ endif
+ endif
+
+--
+2.9.3
+
--- /dev/null
+diff --git a/configure b/configure
+index b6752d147c6b..6089a3403410 100755
+--- a/configure
++++ b/configure
+@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
+ ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
+ case $ac_prog_version in
+ '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+- 3.4* | 4.[0-9]* )
++ 3.4* | [4-9].* )
+ ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+ *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+
+diff --git a/configure.in b/configure.in
+index 56849dfc489a..09677eb3d0c1 100644
+--- a/configure.in
++++ b/configure.in
+@@ -960,7 +960,7 @@ fi
+ # These programs are version sensitive.
+ AC_CHECK_TOOL_PREFIX
+ AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
+- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
++ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
+ critic_missing="$critic_missing gcc")
+ AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
+ [GNU Make[^0-9]*\([0-9][0-9.]*\)],
+++ /dev/null
-From b3563932f85d60bb0d38b0a5f3b8f4abc133f890 Mon Sep 17 00:00:00 2001
-From: Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com>
-Date: Thu, 1 Nov 2012 18:00:06 -0500
-Subject: [PATCH] PowerPC: Remove unnecessary -mnew-mnemonics.
-
----
- sysdeps/powerpc/Makefile | 4 ----
- 1 file changed, 4 deletions(-)
-
-diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
-index 79dd6fa976d5..7442b6709ad1 100644
---- a/sysdeps/powerpc/Makefile
-+++ b/sysdeps/powerpc/Makefile
-@@ -1,7 +1,3 @@
--# We always want to use the new mnemonic syntax even if we are on a RS6000
--# machine.
--+cflags += -mnew-mnemonics
--
- ifeq ($(subdir),gmon)
- sysdep_routines += ppc-mcount
- endif
---
-2.9.3
-
+++ /dev/null
-From a4f388e111ce05e2ab7912cff3c9070334bb74ae Mon Sep 17 00:00:00 2001
-From: Josh Stone <jistone@redhat.com>
-Date: Fri, 20 Jan 2017 15:41:56 -0800
-Subject: [PATCH] Prevent inlining in PPC64 initfini.s
-
-Ref: https://sourceware.org/ml/libc-alpha/2012-01/msg00195.html
----
- sysdeps/powerpc/powerpc64/Makefile | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/sysdeps/powerpc/powerpc64/Makefile b/sysdeps/powerpc/powerpc64/Makefile
-index 78d4f07e575f..fe96aae4d43e 100644
---- a/sysdeps/powerpc/powerpc64/Makefile
-+++ b/sysdeps/powerpc/powerpc64/Makefile
-@@ -28,7 +28,7 @@ elide-routines.os += hp-timing
- ifneq ($(elf),no)
- # The initfini generation code doesn't work in the presence of -fPIC, so
- # we use -fpic instead which is much better.
--CFLAGS-initfini.s += -fpic -O1
-+CFLAGS-initfini.s += -fpic -O1 -fno-inline
- endif
- endif
-
---
-2.9.3
-
+++ /dev/null
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
- ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
- case $ac_prog_version in
- '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-- 3.4* | 4.[0-9]* )
-+ 3.4* | [4-9].* )
- ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
- *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
-
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
-- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
- critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
- [GNU Make[^0-9]*\([0-9][0-9.]*\)],
# C-library
#
CT_LIBC="glibc"
-CT_LIBC_VERSION="2.12.2"
+CT_LIBC_VERSION="2.11.1"
CT_LIBC_glibc=y
# CT_LIBC_musl is not set
# CT_LIBC_uClibc is not set
# CT_LIBC_GLIBC_V_2_14_1 is not set
# CT_LIBC_GLIBC_V_2_14 is not set
# CT_LIBC_GLIBC_V_2_13 is not set
-CT_LIBC_GLIBC_V_2_12_2=y
+# CT_LIBC_GLIBC_V_2_12_2 is not set
# CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
+CT_LIBC_GLIBC_V_2_11_1=y
# CT_LIBC_GLIBC_V_2_11 is not set
# CT_LIBC_GLIBC_V_2_10_1 is not set
# CT_LIBC_GLIBC_V_2_9 is not set
--- /dev/null
+From 2739047682590b1df473401b4febf424f857fccf Mon Sep 17 00:00:00 2001
+From: Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
+Date: Sun, 17 Apr 2011 20:43:59 -0400
+Subject: [PATCH] Use .machine to prevent AS from complaining about z9-109
+ instructions in iconv modules
+
+---
+ sysdeps/s390/s390-64/utf16-utf32-z9.c | 5 ++++-
+ sysdeps/s390/s390-64/utf8-utf16-z9.c | 5 ++++-
+ sysdeps/s390/s390-64/utf8-utf32-z9.c | 5 ++++-
+ 3 files changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/sysdeps/s390/s390-64/utf16-utf32-z9.c b/sysdeps/s390/s390-64/utf16-utf32-z9.c
+index 14daf2118fe5..5bcaaaedec9c 100644
+--- a/sysdeps/s390/s390-64/utf16-utf32-z9.c
++++ b/sysdeps/s390/s390-64/utf16-utf32-z9.c
+@@ -169,7 +169,10 @@ gconv_end (struct __gconv_step *data)
+ register unsigned long long outlen asm("11") = outend - outptr; \
+ uint64_t cc = 0; \
+ \
+- asm volatile ("0: " INSTRUCTION " \n\t" \
++ asm volatile (".machine push \n\t" \
++ ".machine \"z9-109\" \n\t" \
++ "0: " INSTRUCTION " \n\t" \
++ ".machine pop \n\t" \
+ " jo 0b \n\t" \
+ " ipm %2 \n" \
+ : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
+diff --git a/sysdeps/s390/s390-64/utf8-utf16-z9.c b/sysdeps/s390/s390-64/utf8-utf16-z9.c
+index 5f73f3c59e21..812a42fae44c 100644
+--- a/sysdeps/s390/s390-64/utf8-utf16-z9.c
++++ b/sysdeps/s390/s390-64/utf8-utf16-z9.c
+@@ -151,7 +151,10 @@ gconv_end (struct __gconv_step *data)
+ register unsigned long long outlen asm("11") = outend - outptr; \
+ uint64_t cc = 0; \
+ \
+- asm volatile ("0: " INSTRUCTION " \n\t" \
++ asm volatile (".machine push \n\t" \
++ ".machine \"z9-109\" \n\t" \
++ "0: " INSTRUCTION " \n\t" \
++ ".machine pop \n\t" \
+ " jo 0b \n\t" \
+ " ipm %2 \n" \
+ : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
+diff --git a/sysdeps/s390/s390-64/utf8-utf32-z9.c b/sysdeps/s390/s390-64/utf8-utf32-z9.c
+index 17ef8bc890c3..0ffd848c8124 100644
+--- a/sysdeps/s390/s390-64/utf8-utf32-z9.c
++++ b/sysdeps/s390/s390-64/utf8-utf32-z9.c
+@@ -155,7 +155,10 @@ gconv_end (struct __gconv_step *data)
+ register unsigned long long outlen asm("11") = outend - outptr; \
+ uint64_t cc = 0; \
+ \
+- asm volatile ("0: " INSTRUCTION " \n\t" \
++ asm volatile (".machine push \n\t" \
++ ".machine \"z9-109\" \n\t" \
++ "0: " INSTRUCTION " \n\t" \
++ ".machine pop \n\t" \
+ " jo 0b \n\t" \
+ " ipm %2 \n" \
+ : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
+--
+2.9.3
+
--- /dev/null
+diff --git a/configure b/configure
+index b6752d147c6b..6089a3403410 100755
+--- a/configure
++++ b/configure
+@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
+ ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
+ case $ac_prog_version in
+ '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
+- 3.4* | 4.[0-9]* )
++ 3.4* | [4-9].* )
+ ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
+ *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
+
+diff --git a/configure.in b/configure.in
+index 56849dfc489a..09677eb3d0c1 100644
+--- a/configure.in
++++ b/configure.in
+@@ -960,7 +960,7 @@ fi
+ # These programs are version sensitive.
+ AC_CHECK_TOOL_PREFIX
+ AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
+- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
++ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
+ critic_missing="$critic_missing gcc")
+ AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
+ [GNU Make[^0-9]*\([0-9][0-9.]*\)],
+++ /dev/null
-From 2739047682590b1df473401b4febf424f857fccf Mon Sep 17 00:00:00 2001
-From: Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
-Date: Sun, 17 Apr 2011 20:43:59 -0400
-Subject: [PATCH] Use .machine to prevent AS from complaining about z9-109
- instructions in iconv modules
-
----
- sysdeps/s390/s390-64/utf16-utf32-z9.c | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf16-z9.c | 5 ++++-
- sysdeps/s390/s390-64/utf8-utf32-z9.c | 5 ++++-
- 3 files changed, 12 insertions(+), 3 deletions(-)
-
-diff --git a/sysdeps/s390/s390-64/utf16-utf32-z9.c b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-index 14daf2118fe5..5bcaaaedec9c 100644
---- a/sysdeps/s390/s390-64/utf16-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf16-utf32-z9.c
-@@ -169,7 +169,10 @@ gconv_end (struct __gconv_step *data)
- register unsigned long long outlen asm("11") = outend - outptr; \
- uint64_t cc = 0; \
- \
-- asm volatile ("0: " INSTRUCTION " \n\t" \
-+ asm volatile (".machine push \n\t" \
-+ ".machine \"z9-109\" \n\t" \
-+ "0: " INSTRUCTION " \n\t" \
-+ ".machine pop \n\t" \
- " jo 0b \n\t" \
- " ipm %2 \n" \
- : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
-diff --git a/sysdeps/s390/s390-64/utf8-utf16-z9.c b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-index 5f73f3c59e21..812a42fae44c 100644
---- a/sysdeps/s390/s390-64/utf8-utf16-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf16-z9.c
-@@ -151,7 +151,10 @@ gconv_end (struct __gconv_step *data)
- register unsigned long long outlen asm("11") = outend - outptr; \
- uint64_t cc = 0; \
- \
-- asm volatile ("0: " INSTRUCTION " \n\t" \
-+ asm volatile (".machine push \n\t" \
-+ ".machine \"z9-109\" \n\t" \
-+ "0: " INSTRUCTION " \n\t" \
-+ ".machine pop \n\t" \
- " jo 0b \n\t" \
- " ipm %2 \n" \
- : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
-diff --git a/sysdeps/s390/s390-64/utf8-utf32-z9.c b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-index 17ef8bc890c3..0ffd848c8124 100644
---- a/sysdeps/s390/s390-64/utf8-utf32-z9.c
-+++ b/sysdeps/s390/s390-64/utf8-utf32-z9.c
-@@ -155,7 +155,10 @@ gconv_end (struct __gconv_step *data)
- register unsigned long long outlen asm("11") = outend - outptr; \
- uint64_t cc = 0; \
- \
-- asm volatile ("0: " INSTRUCTION " \n\t" \
-+ asm volatile (".machine push \n\t" \
-+ ".machine \"z9-109\" \n\t" \
-+ "0: " INSTRUCTION " \n\t" \
-+ ".machine pop \n\t" \
- " jo 0b \n\t" \
- " ipm %2 \n" \
- : "+a" (pOutput), "+a" (pInput), "+d" (cc), \
---
-2.9.3
-
+++ /dev/null
-diff --git a/configure b/configure
-index b6752d147c6b..6089a3403410 100755
---- a/configure
-+++ b/configure
-@@ -5079,7 +5079,7 @@ $as_echo_n "checking version of $CC... " >&6; }
- ac_prog_version=`$CC -v 2>&1 | sed -n 's/^.*version \([egcygnustpi-]*[0-9.]*\).*$/\1/p'`
- case $ac_prog_version in
- '') ac_prog_version="v. ?.??, bad"; ac_verc_fail=yes;;
-- 3.4* | 4.[0-9]* )
-+ 3.4* | [4-9].* )
- ac_prog_version="$ac_prog_version, ok"; ac_verc_fail=no;;
- *) ac_prog_version="$ac_prog_version, bad"; ac_verc_fail=yes;;
-
-diff --git a/configure.in b/configure.in
-index 56849dfc489a..09677eb3d0c1 100644
---- a/configure.in
-+++ b/configure.in
-@@ -960,7 +960,7 @@ fi
- # These programs are version sensitive.
- AC_CHECK_TOOL_PREFIX
- AC_CHECK_PROG_VER(CC, ${ac_tool_prefix}gcc ${ac_tool_prefix}cc, -v,
-- [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | 4.[0-9]* ],
-+ [version \([egcygnustpi-]*[0-9.]*\)], [3.4* | [4-9].* ],
- critic_missing="$critic_missing gcc")
- AC_CHECK_PROG_VER(MAKE, gnumake gmake make, --version,
- [GNU Make[^0-9]*\([0-9][0-9.]*\)],
# C-library
#
CT_LIBC="glibc"
-CT_LIBC_VERSION="2.12.2"
+CT_LIBC_VERSION="2.11.1"
CT_LIBC_glibc=y
# CT_LIBC_musl is not set
# CT_LIBC_uClibc is not set
# CT_LIBC_GLIBC_V_2_14_1 is not set
# CT_LIBC_GLIBC_V_2_14 is not set
# CT_LIBC_GLIBC_V_2_13 is not set
-CT_LIBC_GLIBC_V_2_12_2=y
+# CT_LIBC_GLIBC_V_2_12_2 is not set
# CT_LIBC_GLIBC_V_2_12_1 is not set
-# CT_LIBC_GLIBC_V_2_11_1 is not set
+CT_LIBC_GLIBC_V_2_11_1=y
# CT_LIBC_GLIBC_V_2_11 is not set
# CT_LIBC_GLIBC_V_2_10_1 is not set
# CT_LIBC_GLIBC_V_2_9 is not set
CI_JOB_NAME: ${{ matrix.name }}
- &public-variables
- SCCACHE_BUCKET: rust-lang-gha-caches
- TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate
- CACHE_DOMAIN: ci-caches-gha.rust-lang.org
+ SCCACHE_BUCKET: rust-lang-ci-sccache2
+ TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate
+ CACHE_DOMAIN: ci-caches.rust-lang.org
- &prod-variables
+ SCCACHE_BUCKET: rust-lang-ci-sccache2
+ DEPLOY_BUCKET: rust-lang-ci2
+ TOOLSTATE_REPO: https://github.com/rust-lang-nursery/rust-toolstate
+ TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
+ TOOLSTATE_PUBLISH: 1
+ # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named
+ # AWS_SECRET_ACCESS_KEY_<keyid>. Including the key id in the name allows to
+ # rotate them in a single branch while keeping the old key in another
+ # branch, which wouldn't be possible if the key was named with the kind
+ # (caches, artifacts...).
+ CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL
+ ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55
+ CACHE_DOMAIN: ci-caches.rust-lang.org
+
+ - &dummy-variables
SCCACHE_BUCKET: rust-lang-gha-caches
DEPLOY_BUCKET: rust-lang-gha
TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate
if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'
<<: *step
+ # Rust Log Analyzer can't currently detect the PR number of a GitHub
+ # Actions build on its own, so a hint in the log message is needed to
+ # point it in the right direction.
+ - name: configure the PR in which the error message will be posted
+ run: echo "[CI_PR_NUMBER=$num]"
+ env:
+ num: ${{ github.event.number }}
+ if: success() && !env.SKIP_JOBS && github.event_name == 'pull_request'
+
- name: add extra environment variables
run: src/ci/scripts/setup-environment.sh
env:
branches:
- auto
- try
+ - try-perf
- master
pull_request:
branches:
name: try
env:
<<: [*shared-ci-variables, *prod-variables]
- if: github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'
+ if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'
strategy:
matrix:
include:
<<: *base-ci-job
name: auto-fallible
env:
- <<: [*shared-ci-variables, *prod-variables]
+ <<: [*shared-ci-variables, *dummy-variables]
if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'
strategy:
matrix:
# successful listening to webhooks only.
try-success:
needs: [try]
- if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
<<: *base-success-job
try-failure:
needs: [try]
- if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
+ if: "!success() && github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust'"
<<: *base-failure-job
auto-success:
needs: [auto]
-Subproject commit 84a31397b34f9d405df44f2899ff17a4828dba18
+Subproject commit a914f2c7e5cdb771fa465de142381a51c53b580e
-Subproject commit 82bec5877c77cfad530ca11095db4456d757f668
+Subproject commit bd6e4a9f59c5c1545f572266af77f5c7a5bad6d1
-Subproject commit 0ea7bc494f1289234d8800bb9185021e0ad946f0
+Subproject commit b329ce37424874ad4db94f829a55807c6e21d2cb
This option lets you choose which code model to use. \
Code models put constraints on address ranges that the program and its symbols may use. \
With smaller address ranges machine instructions
-may be able to use use more compact addressing modes.
+may be able to use more compact addressing modes.
The specific ranges depend on target architectures and addressing modes available to them. \
For x86 more detailed description of its code models can be found in
The default value, if not specified, is 16 for non-incremental builds. For
incremental builds the default is 256 which allows caching to be more granular.
+## control-flow-guard
+
+This flag controls whether LLVM enables the Windows [Control Flow
+Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard)
+platform security feature. This flag is currently ignored for non-Windows targets.
+It takes one of the following values:
+
+* `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard.
+* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this
+should only be used for testing purposes as it does not provide security enforcement).
+* `n`, `no`, `off`: do not enable Control Flow Guard (the default).
+
## debug-assertions
This flag lets you turn `cfg(debug_assertions)` [conditional
* Double-free, invalid free
* Memory leaks
+The memory leak detection is enabled by default on Linux, and can be enabled
+with runtime flag `ASAN_OPTIONS=detect_leaks=1` on macOS.
+
AddressSanitizer is supported on the following targets:
* `x86_64-apple-darwin`
```shell
$ export \
- CC=clang \
- CXX=clang++ \
- CFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \
- CXXFLAGS='-fsanitize=memory -fsanitize-memory-track-origins' \
RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \
RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins'
$ cargo clean
#![stable(feature = "rust1", since = "1.0.0")]
use core::any::Any;
-use core::array::LengthAtMost32;
use core::borrow;
use core::cmp::Ordering;
use core::convert::{From, TryFrom};
}
#[stable(feature = "box_from_array", since = "1.45.0")]
-impl<T, const N: usize> From<[T; N]> for Box<[T]>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> From<[T; N]> for Box<[T]> {
/// Converts a `[T; N]` into a `Box<[T]>`
///
/// This conversion moves the array to newly heap-allocated memory.
}
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
-impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> TryFrom<Box<[T]>> for Box<[T; N]> {
type Error = Box<[T]>;
fn try_from(boxed_slice: Box<[T]>) -> Result<Self, Self::Error> {
//! A priority queue implemented with a binary heap.
//!
-//! Insertion and popping the largest element have `O(log(n))` time complexity.
-//! Checking the largest element is `O(1)`. Converting a vector to a binary heap
-//! can be done in-place, and has `O(n)` complexity. A binary heap can also be
-//! converted to a sorted vector in-place, allowing it to be used for an `O(n * log(n))`
+//! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
+//! Checking the largest element is *O*(1). Converting a vector to a binary heap
+//! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
+//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*))
//! in-place heapsort.
//!
//! # Examples
///
/// | [push] | [pop] | [peek]/[peek\_mut] |
/// |--------|-----------|--------------------|
-/// | O(1)~ | O(log(n)) | O(1) |
+/// | O(1)~ | *O*(log(*n*)) | *O*(1) |
///
/// The value for `push` is an expected cost; the method documentation gives a
/// more detailed analysis.
///
/// # Time complexity
///
- /// Cost is `O(1)` in the worst case.
+ /// Cost is *O*(1) in the worst case.
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
pub fn peek_mut(&mut self) -> Option<PeekMut<'_, T>> {
if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) }
///
/// # Time complexity
///
- /// The worst case cost of `pop` on a heap containing *n* elements is `O(log(n))`.
+ /// The worst case cost of `pop` on a heap containing *n* elements is *O*(log(*n*)).
#[stable(feature = "rust1", since = "1.0.0")]
pub fn pop(&mut self) -> Option<T> {
self.data.pop().map(|mut item| {
///
/// The expected cost of `push`, averaged over every possible ordering of
/// the elements being pushed, and over a sufficiently large number of
- /// pushes, is `O(1)`. This is the most meaningful cost metric when pushing
+ /// pushes, is *O*(1). This is the most meaningful cost metric when pushing
/// elements that are *not* already in any sorted pattern.
///
/// The time complexity degrades if elements are pushed in predominantly
/// ascending order. In the worst case, elements are pushed in ascending
- /// sorted order and the amortized cost per push is `O(log(n))` against a heap
+ /// sorted order and the amortized cost per push is *O*(log(*n*)) against a heap
/// containing *n* elements.
///
- /// The worst case cost of a *single* call to `push` is `O(n)`. The worst case
+ /// The worst case cost of a *single* call to `push` is *O*(*n*). The worst case
/// occurs when capacity is exhausted and needs a resize. The resize cost
/// has been amortized in the previous figures.
#[stable(feature = "rust1", since = "1.0.0")]
/// The remaining elements will be removed on drop in heap order.
///
/// Note:
- /// * `.drain_sorted()` is `O(n * log(n))`; much slower than `.drain()`.
+ /// * `.drain_sorted()` is *O*(*n* \* log(*n*)); much slower than `.drain()`.
/// You should use the latter for most cases.
///
/// # Examples
///
/// # Time complexity
///
- /// Cost is `O(1)` in the worst case.
+ /// Cost is *O*(1) in the worst case.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&self) -> Option<&T> {
self.data.get(0)
impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
/// Converts a `Vec<T>` into a `BinaryHeap<T>`.
///
- /// This conversion happens in-place, and has `O(n)` time complexity.
+ /// This conversion happens in-place, and has *O*(*n*) time complexity.
fn from(vec: Vec<T>) -> BinaryHeap<T> {
let mut heap = BinaryHeap { data: vec };
heap.rebuild();
edge.reborrow().next_kv().ok().map(|kv| kv.into_kv())
}
- unsafe fn next_kv(
- &mut self,
- ) -> Option<Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV>> {
- let edge = self.cur_leaf_edge.as_ref()?;
- unsafe { ptr::read(edge).next_kv().ok() }
- }
-
/// Implementation of a typical `DrainFilter::next` method, given the predicate.
pub(super) fn next<F>(&mut self, pred: &mut F) -> Option<(K, V)>
where
F: FnMut(&K, &mut V) -> bool,
{
- while let Some(mut kv) = unsafe { self.next_kv() } {
+ while let Ok(mut kv) = self.cur_leaf_edge.take()?.next_kv() {
let (k, v) = kv.kv_mut();
if pred(k, v) {
*self.length -= 1;
/// This reuses all the nodes from `other` and moves them into `self`. After
/// this operation, `other` becomes empty.
///
- /// This operation should compute in `O(1)` time and `O(1)` memory.
+ /// This operation should compute in *O*(1) time and *O*(1) memory.
///
/// # Examples
///
/// Returns `true` if the `LinkedList` is empty.
///
- /// This operation should compute in `O(1)` time.
+ /// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// Returns the length of the `LinkedList`.
///
- /// This operation should compute in `O(1)` time.
+ /// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// Removes all elements from the `LinkedList`.
///
- /// This operation should compute in `O(n)` time.
+ /// This operation should compute in *O*(*n*) time.
///
/// # Examples
///
/// Adds an element first in the list.
///
- /// This operation should compute in `O(1)` time.
+ /// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// Removes the first element and returns it, or `None` if the list is
/// empty.
///
- /// This operation should compute in `O(1)` time.
+ /// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// Appends an element to the back of a list.
///
- /// This operation should compute in `O(1)` time.
+ /// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// Removes the last element from a list and returns it, or `None` if
/// it is empty.
///
- /// This operation should compute in `O(1)` time.
+ /// This operation should compute in *O*(1) time.
///
/// # Examples
///
/// Splits the list into two at the given index. Returns everything after the given index,
/// including the index.
///
- /// This operation should compute in `O(n)` time.
+ /// This operation should compute in *O*(*n*) time.
///
/// # Panics
///
/// Removes the element at the given index and returns it.
///
- /// This operation should compute in `O(n)` time.
+ /// This operation should compute in *O*(*n*) time.
///
/// # Panics
/// Panics if at >= len
//! A double-ended queue implemented with a growable ring buffer.
//!
-//! This queue has `O(1)` amortized inserts and removals from both ends of the
-//! container. It also has `O(1)` indexing like a vector. The contained elements
+//! This queue has *O*(1) amortized inserts and removals from both ends of the
+//! container. It also has *O*(1) indexing like a vector. The contained elements
//! are not required to be copyable, and the queue will be sendable if the
//! contained type is sendable.
// ignore-tidy-filelength
-use core::array::LengthAtMost32;
use core::cmp::{self, Ordering};
use core::fmt;
use core::hash::{Hash, Hasher};
/// Removes an element from anywhere in the `VecDeque` and returns it,
/// replacing it with the first element.
///
- /// This does not preserve ordering, but is `O(1)`.
+ /// This does not preserve ordering, but is *O*(1).
///
/// Returns `None` if `index` is out of bounds.
///
/// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
/// last element.
///
- /// This does not preserve ordering, but is `O(1)`.
+ /// This does not preserve ordering, but is *O*(1).
///
/// Returns `None` if `index` is out of bounds.
///
///
/// # Complexity
///
- /// Takes `O(min(mid, len() - mid))` time and no extra space.
+ /// Takes `*O*(min(mid, len() - mid))` time and no extra space.
///
/// # Examples
///
///
/// # Complexity
///
- /// Takes `O(min(k, len() - k))` time and no extra space.
+ /// Takes `*O*(min(k, len() - k))` time and no extra space.
///
/// # Examples
///
__impl_slice_eq1! { [] VecDeque<A>, Vec<B>, }
__impl_slice_eq1! { [] VecDeque<A>, &[B], }
__impl_slice_eq1! { [] VecDeque<A>, &mut [B], }
-__impl_slice_eq1! { [const N: usize] VecDeque<A>, [B; N], [B; N]: LengthAtMost32 }
-__impl_slice_eq1! { [const N: usize] VecDeque<A>, &[B; N], [B; N]: LengthAtMost32 }
-__impl_slice_eq1! { [const N: usize] VecDeque<A>, &mut [B; N], [B; N]: LengthAtMost32 }
+__impl_slice_eq1! { [const N: usize] VecDeque<A>, [B; N], }
+__impl_slice_eq1! { [const N: usize] VecDeque<A>, &[B; N], }
+__impl_slice_eq1! { [const N: usize] VecDeque<A>, &mut [B; N], }
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: PartialOrd> PartialOrd for VecDeque<A> {
/// [`Vec<T>`]: crate::vec::Vec
/// [`VecDeque<T>`]: crate::collections::VecDeque
///
- /// This never needs to re-allocate, but does need to do `O(n)` data movement if
+ /// This never needs to re-allocate, but does need to do *O*(*n*) data movement if
/// the circular buffer doesn't happen to be at the beginning of the allocation.
///
/// # Examples
/// ```
/// use std::collections::VecDeque;
///
- /// // This one is O(1).
+ /// // This one is *O*(1).
/// let deque: VecDeque<_> = (1..5).collect();
/// let ptr = deque.as_slices().0.as_ptr();
/// let vec = Vec::from(deque);
#![feature(cfg_target_has_atomic)]
#![feature(coerce_unsized)]
#![feature(const_btree_new)]
-#![feature(const_generic_impls_guard)]
#![feature(const_generics)]
#![feature(const_in_array_repeat_expressions)]
#![feature(cow_is_borrowed)]
use std::boxed::Box;
use core::any::Any;
-use core::array::LengthAtMost32;
use core::borrow;
use core::cell::Cell;
use core::cmp::Ordering;
}
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
-impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]> {
type Error = Rc<[T]>;
fn try_from(boxed_slice: Rc<[T]>) -> Result<Self, Self::Error> {
///
/// # Examples
///
-/// You can create a `String` from [a literal string][str] with [`String::from`]:
+/// You can create a `String` from [a literal string][`str`] with [`String::from`]:
///
/// [`String::from`]: From::from
///
///
/// Here, there's no need to allocate more memory inside the loop.
///
-/// [`&str`]: str
+/// [`str`]: type@str
+/// [`&str`]: type@str
/// [`Deref`]: core::ops::Deref
/// [`as_str()`]: String::as_str
#[derive(PartialOrd, Eq, Ord)]
/// This is highly unsafe, due to the number of invariants that aren't
/// checked:
///
- /// * The memory at `ptr` needs to have been previously allocated by the
+ /// * The memory at `buf` needs to have been previously allocated by the
/// same allocator the standard library uses, with a required alignment of exactly 1.
/// * `length` needs to be less than or equal to `capacity`.
/// * `capacity` needs to be the correct value.
+ /// * The first `length` bytes at `buf` need to be valid UTF-8.
///
/// Violating these may cause problems like corrupting the allocator's
/// internal data structures.
///
- /// The ownership of `ptr` is effectively transferred to the
+ /// The ownership of `buf` is effectively transferred to the
/// `String` which may then deallocate, reallocate or change the
/// contents of memory pointed to by the pointer at will. Ensure
/// that nothing else uses the pointer after calling this
/// Removes a [`char`] from this `String` at a byte position and returns it.
///
- /// This is an `O(n)` operation, as it requires copying every element in the
+ /// This is an *O*(*n*) operation, as it requires copying every element in the
/// buffer.
///
/// # Panics
/// Inserts a character into this `String` at a byte position.
///
- /// This is an `O(n)` operation as it requires copying every element in the
+ /// This is an *O*(*n*) operation as it requires copying every element in the
/// buffer.
///
/// # Panics
/// Inserts a string slice into this `String` at a byte position.
///
- /// This is an `O(n)` operation as it requires copying every element in the
+ /// This is an *O*(*n*) operation as it requires copying every element in the
/// buffer.
///
/// # Panics
///
/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
-/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by
+/// every operation, which would lead to *O*(*n*^2) running time when building an *n*-byte string by
/// repeated concatenation.
///
/// The string on the right-hand side is only borrowed; its contents are copied into the returned
//! [arc]: struct.Arc.html
use core::any::Any;
-use core::array::LengthAtMost32;
use core::borrow;
use core::cmp::Ordering;
use core::convert::{From, TryFrom};
}
#[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
-impl<T, const N: usize> TryFrom<Arc<[T]>> for Arc<[T; N]>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> TryFrom<Arc<[T]>> for Arc<[T; N]> {
type Error = Arc<[T]>;
fn try_from(boxed_slice: Arc<[T]>) -> Result<Self, Self::Error> {
use std::convert::TryFrom;
use std::fmt::Debug;
use std::iter::FromIterator;
+use std::mem;
use std::ops::Bound::{self, Excluded, Included, Unbounded};
use std::ops::RangeBounds;
use std::panic::{catch_unwind, AssertUnwindSafe};
// It's not the minimum size: removing an element from such a tree does not always reduce height.
const MIN_INSERTS_HEIGHT_2: usize = NODE_CAPACITY + (NODE_CAPACITY + 1) * NODE_CAPACITY + 1;
+// Gather all references from a mutable iterator and make sure Miri notices if
+// using them is dangerous.
+fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator<Item = &'a mut T>) {
+ // Gather all those references.
+ let mut refs: Vec<&mut T> = iter.collect();
+ // Use them all. Twice, to be sure we got all interleavings.
+ for r in refs.iter_mut() {
+ mem::swap(dummy, r);
+ }
+ for r in refs {
+ mem::swap(dummy, r);
+ }
+}
+
#[test]
fn test_basic_large() {
let mut map = BTreeMap::new();
}
#[test]
+#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
fn test_values_mut() {
+ let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect();
+ test_all_refs(&mut 13, a.values_mut());
+}
+
+#[test]
+fn test_values_mut_mutation() {
let mut a = BTreeMap::new();
a.insert(1, String::from("hello"));
a.insert(2, String::from("goodbye"));
assert_eq!(values, [String::from("hello!"), String::from("goodbye!")]);
}
+#[test]
+#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
+fn test_iter_entering_root_twice() {
+ let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect();
+ let mut it = map.iter_mut();
+ let front = it.next().unwrap();
+ let back = it.next_back().unwrap();
+ assert_eq!(front, (&0, &mut 0));
+ assert_eq!(back, (&1, &mut 1));
+ *front.1 = 24;
+ *back.1 = 42;
+ assert_eq!(front, (&0, &mut 24));
+ assert_eq!(back, (&1, &mut 42));
+}
+
+#[test]
+#[cfg_attr(miri, ignore)] // FIXME: fails in Miri <https://github.com/rust-lang/rust/issues/73915>
+fn test_iter_descending_to_same_node_twice() {
+ let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect();
+ let mut it = map.iter_mut();
+ // Descend into first child.
+ let front = it.next().unwrap();
+ // Descend into first child again, after running through second child.
+ while it.next_back().is_some() {}
+ // Check immutable access.
+ assert_eq!(front, (&0, &mut 0));
+ // Perform mutable access.
+ *front.1 = 42;
+}
+
#[test]
fn test_iter_mixed() {
// Miri is too slow
}
}
- let mut map = BTreeMap::new();
- map.insert(0, D);
- map.insert(4, D);
- map.insert(8, D);
+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
+ let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
catch_unwind(move || {
drop(map.drain_filter(|i, _| {
true
}))
})
- .ok();
+ .unwrap_err();
assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
assert_eq!(DROPS.load(Ordering::SeqCst), 3);
}
}
- let mut map = BTreeMap::new();
- map.insert(0, D);
- map.insert(4, D);
- map.insert(8, D);
+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
+ let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
catch_unwind(AssertUnwindSafe(|| {
drop(map.drain_filter(|i, _| {
}
}))
}))
- .ok();
+ .unwrap_err();
+
+ assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
+ assert_eq!(DROPS.load(Ordering::SeqCst), 1);
+ assert_eq!(map.len(), 2);
+ assert_eq!(map.first_entry().unwrap().key(), &4);
+ assert_eq!(map.last_entry().unwrap().key(), &8);
+ }
+
+ // Same as above, but attempt to use the iterator again after the panic in the predicate
+ #[test]
+ fn pred_panic_reuse() {
+ static PREDS: AtomicUsize = AtomicUsize::new(0);
+ static DROPS: AtomicUsize = AtomicUsize::new(0);
+
+ struct D;
+ impl Drop for D {
+ fn drop(&mut self) {
+ DROPS.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+
+ // Keys are multiples of 4, so that each key is counted by a hexadecimal digit.
+ let mut map = (0..3).map(|i| (i * 4, D)).collect::<BTreeMap<_, _>>();
+
+ {
+ let mut it = map.drain_filter(|i, _| {
+ PREDS.fetch_add(1usize << i, Ordering::SeqCst);
+ match i {
+ 0 => true,
+ _ => panic!(),
+ }
+ });
+ catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err();
+ // Iterator behaviour after a panic is explicitly unspecified,
+ // so this is just the current implementation:
+ let result = catch_unwind(AssertUnwindSafe(|| it.next()));
+ assert!(matches!(result, Ok(None)));
+ }
assert_eq!(PREDS.load(Ordering::SeqCst), 0x011);
assert_eq!(DROPS.load(Ordering::SeqCst), 1);
assert!(right.into_iter().eq(data));
}
+// In a tree with 3 levels, if all but a part of the first leaf node is split off,
+// make sure fix_top eliminates both top levels.
+#[test]
+fn test_split_off_tiny_left_height_2() {
+ let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
+ let mut left: BTreeMap<_, _> = pairs.clone().collect();
+ let right = left.split_off(&1);
+ assert_eq!(left.len(), 1);
+ assert_eq!(right.len(), MIN_INSERTS_HEIGHT_2 - 1);
+ assert_eq!(*left.first_key_value().unwrap().0, 0);
+ assert_eq!(*right.first_key_value().unwrap().0, 1);
+}
+
+// In a tree with 3 levels, if only part of the last leaf node is split off,
+// make sure fix_top eliminates both top levels.
+#[test]
+fn test_split_off_tiny_right_height_2() {
+ let pairs = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i));
+ let last = MIN_INSERTS_HEIGHT_2 - 1;
+ let mut left: BTreeMap<_, _> = pairs.clone().collect();
+ assert_eq!(*left.last_key_value().unwrap().0, last);
+ let right = left.split_off(&last);
+ assert_eq!(left.len(), MIN_INSERTS_HEIGHT_2 - 1);
+ assert_eq!(right.len(), 1);
+ assert_eq!(*left.last_key_value().unwrap().0, last - 1);
+ assert_eq!(*right.last_key_value().unwrap().0, last);
+}
+
#[test]
fn test_split_off_large_random_sorted() {
// Miri is too slow
map.insert("d", D);
map.insert("e", D);
- catch_unwind(move || drop(map.into_iter())).ok();
+ catch_unwind(move || drop(map.into_iter())).unwrap_err();
assert_eq!(DROPS.load(Ordering::SeqCst), 5);
}
DROPS.store(0, Ordering::SeqCst);
PANIC_POINT.store(panic_point, Ordering::SeqCst);
let map: BTreeMap<_, _> = (0..size).map(|i| (i, D)).collect();
- catch_unwind(move || drop(map.into_iter())).ok();
+ catch_unwind(move || drop(map.into_iter())).unwrap_err();
assert_eq!(DROPS.load(Ordering::SeqCst), size);
}
}
#![stable(feature = "rust1", since = "1.0.0")]
-use core::array::LengthAtMost32;
use core::cmp::{self, Ordering};
use core::fmt;
use core::hash::{Hash, Hasher};
/// Creates a draining iterator that removes the specified range in the vector
/// and yields the removed items.
///
- /// Note 1: The element range is removed even if the iterator is only
- /// partially consumed or not consumed at all.
- ///
- /// Note 2: It is unspecified how many elements are removed from the vector
- /// if the `Drain` value is leaked.
+ /// When the iterator **is** dropped, all elements in the range are removed
+ /// from the vector, even if the iterator was not fully consumed. If the
+ /// iterator **is not** dropped (with [`mem::forget`] for example), it is
+ /// unspecified how many elements are removed.
///
/// # Panics
///
__impl_slice_eq1! { [] Cow<'_, [A]>, Vec<B> where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
__impl_slice_eq1! { [] Cow<'_, [A]>, &[B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
__impl_slice_eq1! { [] Cow<'_, [A]>, &mut [B] where A: Clone, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N] where [B; N]: LengthAtMost32, #[stable(feature = "rust1", since = "1.0.0")] }
-__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N] where [B; N]: LengthAtMost32, #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [const N: usize] Vec<A>, [B; N], #[stable(feature = "rust1", since = "1.0.0")] }
+__impl_slice_eq1! { [const N: usize] Vec<A>, &[B; N], #[stable(feature = "rust1", since = "1.0.0")] }
// NOTE: some less important impls are omitted to reduce code bloat
// FIXME(Centril): Reconsider this?
-//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], [B; N]: LengthAtMost32 }
-//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, [A; N]: LengthAtMost32 }
-//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, [A; N]: LengthAtMost32 }
-//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, [A; N]: LengthAtMost32 }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], [B; N]: LengthAtMost32 }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], [B; N]: LengthAtMost32 }
-//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], [B; N]: LengthAtMost32 }
+//__impl_slice_eq1! { [const N: usize] Vec<A>, &mut [B; N], }
+//__impl_slice_eq1! { [const N: usize] [A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] &[A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] &mut [A; N], Vec<B>, }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, [B; N], }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &[B; N], }
+//__impl_slice_eq1! { [const N: usize] Cow<'a, [A]>, &mut [B; N], }
/// Implements comparison of vectors, lexicographically.
#[stable(feature = "rust1", since = "1.0.0")]
}
#[stable(feature = "vec_from_array", since = "1.44.0")]
-impl<T, const N: usize> From<[T; N]> for Vec<T>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> From<[T; N]> for Vec<T> {
#[cfg(not(test))]
fn from(s: [T; N]) -> Vec<T> {
<[T]>::into_vec(box s)
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
debug_assert!(Layout::from_size_align(size, align).is_ok());
- // SAFETY: see rationale in `new` for why this is using an unsafe variant below
+ // SAFETY: see rationale in `new` for why this is using the unsafe variant
+ unsafe { Layout::from_size_align_unchecked(size, align) }
+ }
+
+ /// Produces layout describing a record that could be used to
+ /// allocate backing structure for `T` (which could be a trait
+ /// or other unsized type like a slice).
+ ///
+ /// # Safety
+ ///
+ /// This function is only safe to call if the following conditions hold:
+ ///
+ /// - If `T` is `Sized`, this function is always safe to call.
+ /// - If the unsized tail of `T` is:
+ /// - a [slice], then the length of the slice tail must be an intialized
+ /// integer, and the size of the *entire value*
+ /// (dynamic tail length + statically sized prefix) must fit in `isize`.
+ /// - a [trait object], then the vtable part of the pointer must point
+ /// to a valid vtable for the type `T` acquired by an unsizing coersion,
+ /// and the size of the *entire value*
+ /// (dynamic tail length + statically sized prefix) must fit in `isize`.
+ /// - an (unstable) [extern type], then this function is always safe to
+ /// call, but may panic or otherwise return the wrong value, as the
+ /// extern type's layout is not known. This is the same behavior as
+ /// [`Layout::for_value`] on a reference to an extern type tail.
+ /// - otherwise, it is conservatively not allowed to call this function.
+ ///
+ /// [slice]: ../../std/primitive.slice.html
+ /// [trait object]: ../../book/ch17-02-trait-objects.html
+ /// [extern type]: ../../unstable-book/language-features/extern-types.html
+ #[unstable(feature = "layout_for_ptr", issue = "69835")]
+ pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
+ // SAFETY: we pass along the prerequisites of these functions to the caller
+ let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
+ debug_assert!(Layout::from_size_align(size, align).is_ok());
+ // SAFETY: see rationale in `new` for why this is using the unsafe variant
unsafe { Layout::from_size_align_unchecked(size, align) }
}
//! Defines the `IntoIter` owned iterator for arrays.
-use super::LengthAtMost32;
use crate::{
fmt,
iter::{ExactSizeIterator, FusedIterator, TrustedLen},
///
/// [array]: ../../std/primitive.array.html
#[unstable(feature = "array_value_iter", issue = "65798")]
-pub struct IntoIter<T, const N: usize>
-where
- [T; N]: LengthAtMost32,
-{
+pub struct IntoIter<T, const N: usize> {
/// This is the array we are iterating over.
///
/// Elements with index `i` where `alive.start <= i < alive.end` have not
alive: Range<usize>,
}
-impl<T, const N: usize> IntoIter<T, N>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> IntoIter<T, N> {
/// Creates a new iterator over the given `array`.
///
/// *Note*: this method might never get stabilized and/or removed in the
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-impl<T, const N: usize> Iterator for IntoIter<T, N>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> Iterator for IntoIter<T, N> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.alive.start == self.alive.end {
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.alive.start == self.alive.end {
return None;
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-impl<T, const N: usize> Drop for IntoIter<T, N>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> Drop for IntoIter<T, N> {
fn drop(&mut self) {
// SAFETY: This is safe: `as_mut_slice` returns exactly the sub-slice
// of elements that have not been moved out yet and that remain
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> {
fn len(&self) -> usize {
// Will never underflow due to the invariant `alive.start <=
// alive.end`.
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-impl<T, const N: usize> FusedIterator for IntoIter<T, N> where [T; N]: LengthAtMost32 {}
+impl<T, const N: usize> FusedIterator for IntoIter<T, N> {}
// The iterator indeed reports the correct length. The number of "alive"
// elements (that will still be yielded) is the length of the range `alive`.
// This range is decremented in length in either `next` or `next_back`. It is
// always decremented by 1 in those methods, but only if `Some(_)` is returned.
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> where [T; N]: LengthAtMost32 {}
+unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> {}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-impl<T: Clone, const N: usize> Clone for IntoIter<T, N>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
fn clone(&self) -> Self {
// SAFETY: each point of unsafety is documented inside the unsafe block
unsafe {
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
-impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N>
-where
- [T; N]: LengthAtMost32,
-{
+impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Only print the elements that were not yielded yet: we cannot
// access the yielded elements anymore.
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, const N: usize> AsRef<[T]> for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> AsRef<[T]> for [T; N] {
#[inline]
fn as_ref(&self) -> &[T] {
&self[..]
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, const N: usize> AsMut<[T]> for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> AsMut<[T]> for [T; N] {
#[inline]
fn as_mut(&mut self) -> &mut [T] {
&mut self[..]
}
#[stable(feature = "array_borrow", since = "1.4.0")]
-impl<T, const N: usize> Borrow<[T]> for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> Borrow<[T]> for [T; N] {
fn borrow(&self) -> &[T] {
self
}
}
#[stable(feature = "array_borrow", since = "1.4.0")]
-impl<T, const N: usize> BorrowMut<[T]> for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T, const N: usize> BorrowMut<[T]> for [T; N] {
fn borrow_mut(&mut self) -> &mut [T] {
self
}
impl<T, const N: usize> TryFrom<&[T]> for [T; N]
where
T: Copy,
- [T; N]: LengthAtMost32,
{
type Error = TryFromSliceError;
}
#[stable(feature = "try_from", since = "1.34.0")]
-impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<'a, T, const N: usize> TryFrom<&'a [T]> for &'a [T; N] {
type Error = TryFromSliceError;
fn try_from(slice: &[T]) -> Result<&[T; N], TryFromSliceError> {
}
#[stable(feature = "try_from", since = "1.34.0")]
-impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
type Error = TryFromSliceError;
fn try_from(slice: &mut [T]) -> Result<&mut [T; N], TryFromSliceError> {
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Hash, const N: usize> Hash for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T: Hash, const N: usize> Hash for [T; N] {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
Hash::hash(&self[..], state)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&&self[..], f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, const N: usize> IntoIterator for &'a [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<'a, T, const N: usize> IntoIterator for &'a [T; N] {
type Item = &'a T;
type IntoIter = Iter<'a, T>;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<'a, T, const N: usize> IntoIterator for &'a mut [T; N] {
type Item = &'a mut T;
type IntoIter = IterMut<'a, T>;
impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
where
A: PartialEq<B>,
- [A; N]: LengthAtMost32,
- [B; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[B; N]) -> bool {
impl<A, B, const N: usize> PartialEq<[B]> for [A; N]
where
A: PartialEq<B>,
- [A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[B]) -> bool {
impl<A, B, const N: usize> PartialEq<[A; N]> for [B]
where
B: PartialEq<A>,
- [A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
impl<'b, A, B, const N: usize> PartialEq<&'b [B]> for [A; N]
where
A: PartialEq<B>,
- [A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &&'b [B]) -> bool {
impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b [B]
where
B: PartialEq<A>,
- [A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
impl<'b, A, B, const N: usize> PartialEq<&'b mut [B]> for [A; N]
where
A: PartialEq<B>,
- [A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &&'b mut [B]) -> bool {
impl<'b, A, B, const N: usize> PartialEq<[A; N]> for &'b mut [B]
where
B: PartialEq<A>,
- [A; N]: LengthAtMost32,
{
#[inline]
fn eq(&self, other: &[A; N]) -> bool {
// __impl_slice_eq2! { [A; $N], &'b mut [B; $N] }
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq, const N: usize> Eq for [T; N] where [T; N]: LengthAtMost32 {}
+impl<T: Eq, const N: usize> Eq for [T; N] {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd, const N: usize> PartialOrd for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T: PartialOrd, const N: usize> PartialOrd for [T; N] {
#[inline]
fn partial_cmp(&self, other: &[T; N]) -> Option<Ordering> {
PartialOrd::partial_cmp(&&self[..], &&other[..])
/// Implements comparison of arrays lexicographically.
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord, const N: usize> Ord for [T; N]
-where
- [T; N]: LengthAtMost32,
-{
+impl<T: Ord, const N: usize> Ord for [T; N] {
#[inline]
fn cmp(&self, other: &[T; N]) -> Ordering {
Ord::cmp(&&self[..], &&other[..])
}
}
-/// Implemented for lengths where trait impls are allowed on arrays in core/std
-#[rustc_on_unimplemented(message = "arrays only have std trait implementations for lengths 0..=32")]
-#[unstable(
- feature = "const_generic_impls_guard",
- issue = "none",
- reason = "will never be stable, just a temporary step until const generics are stable"
-)]
-pub trait LengthAtMost32 {}
-
-macro_rules! array_impls {
- ($($N:literal)+) => {
- $(
- #[unstable(feature = "const_generic_impls_guard", issue = "none")]
- impl<T> LengthAtMost32 for [T; $N] {}
- )+
- }
-}
-
-array_impls! {
- 0 1 2 3 4 5 6 7 8 9
- 10 11 12 13 14 15 16 17 18 19
- 20 21 22 23 24 25 26 27 28 29
- 30 31 32
-}
-
// The Default impls cannot be generated using the array_impls! macro because
// they require array literals.
///
///
/// However there is one case where `!` syntax can be used
-/// before `!` is stabilized as a full-fleged type: in the position of a function’s return type.
+/// before `!` is stabilized as a full-fledged type: in the position of a function’s return type.
/// Specifically, it is possible implementations for two different function pointer types:
///
/// ```
Unknown,
}
+/// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
#[derive(Copy, Clone)]
pub enum Count {
+ /// Specified with a literal number, stores the value
Is(usize),
+ /// Specified using `$` and `*` syntaxes, stores the index into `args`
Param(usize),
+ /// Not specified
Implied,
}
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
-/// hashing. This lets you key your hashtables from a strong RNG, such as
+/// hashing. This lets you key your hash tables from a strong RNG, such as
/// [`rand::os::OsRng`](https://doc.rust-lang.org/rand/rand/os/struct.OsRng.html).
///
/// Although the SipHash algorithm is considered to be generally strong,
//!
//! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute,
//! the intrinsic's attribute must be `rustc_const_stable`, too. Such a change should not be done
-//! without T-lang consulation, because it bakes a feature into the language that cannot be
+//! without T-lang consultation, because it bakes a feature into the language that cannot be
//! replicated in user code without compiler support.
//!
//! # Volatiles
/// [`std::mem::align_of`](../../std/mem/fn.align_of.html).
#[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")]
pub fn min_align_of<T>() -> usize;
- /// The prefered alignment of a type.
+ /// The preferred alignment of a type.
///
/// This intrinsic does not have a stable counterpart.
#[rustc_const_unstable(feature = "const_pref_align_of", issue = "none")]
/// assert!(mid <= len);
/// unsafe {
/// let slice2 = mem::transmute::<&mut [T], &mut [T]>(slice);
- /// // first: transmute is not typesafe; all it checks is that T and
+ /// // first: transmute is not type safe; all it checks is that T and
/// // U are of the same size. Second, right here, you have two
/// // mutable references pointing to the same memory.
/// (&mut slice[0..mid], &mut slice2[mid..len])
/// }
/// }
///
- /// // This gets rid of the typesafety problems; `&mut *` will *only* give
+ /// // This gets rid of the type safety problems; `&mut *` will *only* give
/// // you an `&mut T` from an `&mut T` or `*mut T`.
/// fn split_at_mut_casts<T>(slice: &mut [T], mid: usize)
/// -> (&mut [T], &mut [T]) {
#[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
- /// Internal hook used by Miri to implement unwinding.
- /// ICEs when encountered during non-Miri codegen.
- ///
- /// The `payload` ptr here will be exactly the one `do_catch` gets passed by `try`.
- ///
- /// Perma-unstable: do not use.
- pub fn miri_start_panic(payload: *mut u8) -> !;
-
/// Internal placeholder for injecting code coverage counters when the "instrument-coverage"
/// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code
/// generation.
/// * `steps_between(&a, &b) == Some(n)` only if `a <= b`
/// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b`
/// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
- /// this is the case wheen it would require more than `usize::MAX` steps to get to `b`
+ /// this is the case when it would require more than `usize::MAX` steps to get to `b`
/// * `steps_between(&a, &b) == None` if `a > b`
fn steps_between(start: &Self, end: &Self) -> Option<usize>;
/// let vec = iter.collect::<Vec<_>>();
///
/// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3`
- /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` entcountered.
+ /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` encountered.
/// assert_eq!(vec, vec![0, 1, 2]);
/// ```
///
};
}
- /// Includes a utf8-encoded file as a string.
+ /// Includes a UTF-8 encoded file as a string.
///
/// The file is located relative to the current file (similarly to how
/// modules are found). The provided path is interpreted in a platform-specific
///
/// - If `T` is `Sized`, this function is always safe to call.
/// - If the unsized tail of `T` is:
-/// - a [slice], then the length of the slice tail must be an intialized
+/// - a [slice], then the length of the slice tail must be an initialized
/// integer, and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// - a [trait object], then the vtable part of the pointer must point
-/// to a valid vtable acquired by an unsizing coersion, and the size
+/// to a valid vtable acquired by an unsizing coercion, and the size
/// of the *entire value* (dynamic tail length + statically sized prefix)
/// must fit in `isize`.
/// - an (unstable) [extern type], then this function is always safe to
///
/// - If `T` is `Sized`, this function is always safe to call.
/// - If the unsized tail of `T` is:
-/// - a [slice], then the length of the slice tail must be an intialized
+/// - a [slice], then the length of the slice tail must be an initialized
/// integer, and the size of the *entire value*
/// (dynamic tail length + statically sized prefix) must fit in `isize`.
/// - a [trait object], then the vtable part of the pointer must point
-/// to a valid vtable acquired by an unsizing coersion, and the size
+/// to a valid vtable acquired by an unsizing coercion, and the size
/// of the *entire value* (dynamic tail length + statically sized prefix)
/// must fit in `isize`.
/// - an (unstable) [extern type], then this function is always safe to
/// The full circle constant (Ï„)
///
/// Equal to 2Ï€.
- #[unstable(feature = "tau_constant", issue = "66770")]
+ #[stable(feature = "tau_constant", since = "1.47.0")]
pub const TAU: f32 = 6.28318530717958647692528676655900577_f32;
/// π/2
/// The full circle constant (Ï„)
///
/// Equal to 2Ï€.
- #[unstable(feature = "tau_constant", issue = "66770")]
+ #[stable(feature = "tau_constant", since = "1.47.0")]
pub const TAU: f64 = 6.28318530717958647692528676655900577_f64;
/// π/2
/// signaling NaNs on MIPS are quiet NaNs on x86, and vice-versa.
///
/// Rather than trying to preserve signaling-ness cross-platform, this
- /// implementation favours preserving the exact bits. This means that
+ /// implementation favors preserving the exact bits. This means that
/// any payloads encoded in NaNs will be preserved even if the result of
/// this method is sent over the network from an x86 machine to a MIPS one.
///
///
/// If the input isn't NaN, then there is no portability concern.
///
- /// If you don't care about signalingness (very likely), then there is no
+ /// If you don't care about signaling-ness (very likely), then there is no
/// portability concern.
///
/// Note that this function is distinct from `as` casting, which attempts to
without modifying the original"]
#[inline]
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+ if exp == 0 {
+ return Some(1);
+ }
let mut base = self;
let mut acc: Self = 1;
exp /= 2;
base = try_opt!(base.checked_mul(base));
}
-
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- acc = try_opt!(acc.checked_mul(base));
- }
-
- Some(acc)
+ Some(try_opt!(acc.checked_mul(base)))
}
}
without modifying the original"]
#[inline]
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
let mut base = self;
let mut acc: Self = 1;
base = base.wrapping_mul(base);
}
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- acc = acc.wrapping_mul(base);
- }
-
- acc
+ acc.wrapping_mul(base)
}
}
without modifying the original"]
#[inline]
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+ if exp == 0 {
+ return (1,false);
+ }
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
overflown |= r.1;
}
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- r = acc.overflowing_mul(base);
- acc = r.0;
- overflown |= r.1;
- }
-
- (acc, overflown)
+ r = acc.overflowing_mul(base);
+ r.1 |= overflown;
+ r
}
}
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
let mut base = self;
let mut acc = 1;
base = base * base;
}
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- acc = acc * base;
- }
-
- acc
+ acc * base
}
}
without modifying the original"]
#[inline]
pub const fn checked_pow(self, mut exp: u32) -> Option<Self> {
+ if exp == 0 {
+ return Some(1);
+ }
let mut base = self;
let mut acc: Self = 1;
base = try_opt!(base.checked_mul(base));
}
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- acc = try_opt!(acc.checked_mul(base));
- }
- Some(acc)
+ Some(try_opt!(acc.checked_mul(base)))
}
}
without modifying the original"]
#[inline]
pub const fn wrapping_pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
let mut base = self;
let mut acc: Self = 1;
base = base.wrapping_mul(base);
}
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- acc = acc.wrapping_mul(base);
- }
-
- acc
+ acc.wrapping_mul(base)
}
}
without modifying the original"]
#[inline]
pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) {
+ if exp == 0{
+ return (1,false);
+ }
let mut base = self;
let mut acc: Self = 1;
let mut overflown = false;
overflown |= r.1;
}
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- r = acc.overflowing_mul(base);
- acc = r.0;
- overflown |= r.1;
- }
+ r = acc.overflowing_mul(base);
+ r.1 |= overflown;
- (acc, overflown)
+ r
}
}
#[inline]
#[rustc_inherit_overflow_checks]
pub const fn pow(self, mut exp: u32) -> Self {
+ if exp == 0 {
+ return 1;
+ }
let mut base = self;
let mut acc = 1;
base = base * base;
}
+ // since exp!=0, finally the exp must be 1.
// Deal with the final bit of the exponent separately, since
// squaring the base afterwards is not necessary and may cause a
// needless overflow.
- if exp == 1 {
- acc = acc * base;
- }
-
- acc
+ acc * base
}
}
#[rustc_on_unimplemented(
on(
Args = "()",
- note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"
+ note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
label = "expected an `Fn<{Args}>` closure, found `{Self}`"
#[rustc_on_unimplemented(
on(
Args = "()",
- note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"
+ note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
#[rustc_on_unimplemented(
on(
Args = "()",
- note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}"
+ note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
),
message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
/// [`Iterator`]: ../iter/trait.IntoIterator.html
/// [slicing index]: ../slice/trait.SliceIndex.html
#[doc(alias = "..")]
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Default, PartialEq, Eq, Hash)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct RangeFull;
/// assert_eq!(arr[1..=3], [ 1,2,3 ]);
/// ```
#[doc(alias = "..")]
-#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186
+#[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Range<Idx> {
/// The lower bound of the range (inclusive).
//!
//! Crucially, we have to be able to rely on [`drop`] being called. If an element
//! could be deallocated or otherwise invalidated without calling [`drop`], the pointers into it
-//! from its neighbouring elements would become invalid, which would break the data structure.
+//! from its neighboring elements would become invalid, which would break the data structure.
//!
//! Therefore, pinning also comes with a [`drop`]-related guarantee.
//!
intrinsics::ptr_guaranteed_eq(self, other)
}
- /// Returns whether two pointers are guaranteed to be inequal.
+ /// Returns whether two pointers are guaranteed to be unequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be inequal.
- /// But when it returns `true`, the pointers are guaranteed to be inequal.
+ /// spuriously return `false` for pointers that later actually turn out to be unequal.
+ /// But when it returns `true`, the pointers are guaranteed to be unequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
/// operation because the returned value could be pointing to invalid
/// memory.
///
- /// When calling this method, you have to ensure that if the pointer is
- /// non-NULL, then it is properly aligned, dereferenceable (for the whole
- /// size of `T`) and points to an initialized instance of `T`. This applies
- /// even if the result of this method is unused!
+ /// When calling this method, you have to ensure that *either* the pointer is NULL *or*
+ /// all of the following is true:
+ /// - it is properly aligned
+ /// - it must point to an initialized instance of T; in particular, the pointer must be
+ /// "dereferencable" in the sense defined [here].
+ ///
+ /// This applies even if the result of this method is unused!
/// (The part about being initialized is not yet fully decided, but until
/// it is, the only safe approach is to ensure that they are indeed initialized.)
///
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
- /// not necessarily reflect the actual lifetime of the data. It is up to the
- /// caller to ensure that for the duration of this lifetime, the memory this
- /// pointer points to does not get written to outside of `UnsafeCell<U>`.
+ /// not necessarily reflect the actual lifetime of the data. *You* must enforce
+ /// Rust's aliasing rules. In particular, for the duration of this lifetime,
+ /// the memory the pointer points to must not get mutated (except inside `UnsafeCell`).
+ ///
+ /// [here]: crate::ptr#safety
///
/// # Examples
///
intrinsics::ptr_guaranteed_eq(self as *const _, other as *const _)
}
- /// Returns whether two pointers are guaranteed to be inequal.
+ /// Returns whether two pointers are guaranteed to be unequal.
///
/// At runtime this function behaves like `self != other`.
/// However, in some contexts (e.g., compile-time evaluation),
/// it is not always possible to determine the inequality of two pointers, so this function may
- /// spuriously return `false` for pointers that later actually turn out to be inequal.
- /// But when it returns `true`, the pointers are guaranteed to be inequal.
+ /// spuriously return `false` for pointers that later actually turn out to be unequal.
+ /// But when it returns `true`, the pointers are guaranteed to be unequal.
///
/// This function is the mirror of [`guaranteed_eq`], but not its inverse. There are pointer
/// comparisons for which both functions return `false`.
/// assert_eq!(unsafe { slice.as_ref()[2] }, 7);
/// ```
///
- /// (Note that this example artifically demonstrates a use of this method,
+ /// (Note that this example artificially demonstrates a use of this method,
/// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
#[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
#[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
/// Sorts the slice, but may not preserve the order of equal elements.
///
/// This sort is unstable (i.e., may reorder equal elements), in-place
- /// (i.e., does not allocate), and `O(n * log(n))` worst-case.
+ /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case.
///
/// # Current implementation
///
/// elements.
///
/// This sort is unstable (i.e., may reorder equal elements), in-place
- /// (i.e., does not allocate), and `O(n * log(n))` worst-case.
+ /// (i.e., does not allocate), and *O*(*n* \* log(*n*)) worst-case.
///
/// The comparator function must define a total ordering for the elements in the slice. If
/// the ordering is not total, the order of the elements is unspecified. An order is a
/// elements.
///
/// This sort is unstable (i.e., may reorder equal elements), in-place
- /// (i.e., does not allocate), and `O(m * n * log(n))` worst-case, where the key function is
- /// `O(m)`.
+ /// (i.e., does not allocate), and *O*(m \* *n* \* log(*n*)) worst-case, where the key function is
+ /// *O*(*m*).
///
/// # Current implementation
///
/// This reordering has the additional property that any value at position `i < index` will be
/// less than or equal to any value at a position `j > index`. Additionally, this reordering is
/// unstable (i.e. any number of equal elements may end up at position `index`), in-place
- /// (i.e. does not allocate), and `O(n)` worst-case. This function is also/ known as "kth
+ /// (i.e. does not allocate), and *O*(*n*) worst-case. This function is also/ known as "kth
/// element" in other libraries. It returns a triplet of the following values: all elements less
/// than the one at the given index, the value at the given index, and all elements greater than
/// the one at the given index.
/// This reordering has the additional property that any value at position `i < index` will be
/// less than or equal to any value at a position `j > index` using the comparator function.
/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
- /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function
+ /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
/// is also known as "kth element" in other libraries. It returns a triplet of the following
/// values: all elements less than the one at the given index, the value at the given index,
/// and all elements greater than the one at the given index, using the provided comparator
/// This reordering has the additional property that any value at position `i < index` will be
/// less than or equal to any value at a position `j > index` using the key extraction function.
/// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at
- /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function
+ /// position `index`), in-place (i.e. does not allocate), and *O*(*n*) worst-case. This function
/// is also known as "kth element" in other libraries. It returns a triplet of the following
/// values: all elements less than the one at the given index, the value at the given index, and
/// all elements greater than the one at the given index, using the provided key extraction
#[inline(never)]
#[cold]
#[track_caller]
-fn slice_index_len_fail(index: usize, len: usize) -> ! {
- panic!("index {} out of range for slice of length {}", index, len);
+fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
+ panic!("range start index {} out of range for slice of length {}", index, len);
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
+ panic!("range end index {} out of range for slice of length {}", index, len);
}
#[inline(never)]
if self.start > self.end {
slice_index_order_fail(self.start, self.end);
} else if self.end > slice.len() {
- slice_index_len_fail(self.end, slice.len());
+ slice_end_index_len_fail(self.end, slice.len());
}
unsafe { &*self.get_unchecked(slice) }
}
if self.start > self.end {
slice_index_order_fail(self.start, self.end);
} else if self.end > slice.len() {
- slice_index_len_fail(self.end, slice.len());
+ slice_end_index_len_fail(self.end, slice.len());
}
unsafe { &mut *self.get_unchecked_mut(slice) }
}
#[inline]
fn index(self, slice: &[T]) -> &[T] {
- (self.start..slice.len()).index(slice)
+ if self.start > slice.len() {
+ slice_start_index_len_fail(self.start, slice.len());
+ }
+ unsafe { &*self.get_unchecked(slice) }
}
#[inline]
fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- (self.start..slice.len()).index_mut(slice)
+ if self.start > slice.len() {
+ slice_start_index_len_fail(self.start, slice.len());
+ }
+ unsafe { &mut *self.get_unchecked_mut(slice) }
}
}
/// Partially sorts a slice by shifting several out-of-order elements around.
///
-/// Returns `true` if the slice is sorted at the end. This function is `O(n)` worst-case.
+/// Returns `true` if the slice is sorted at the end. This function is *O*(*n*) worst-case.
#[cold]
fn partial_insertion_sort<T, F>(v: &mut [T], is_less: &mut F) -> bool
where
false
}
-/// Sorts a slice using insertion sort, which is `O(n^2)` worst-case.
+/// Sorts a slice using insertion sort, which is *O*(*n*^2) worst-case.
fn insertion_sort<T, F>(v: &mut [T], is_less: &mut F)
where
F: FnMut(&T, &T) -> bool,
}
}
-/// Sorts `v` using heapsort, which guarantees `O(n * log(n))` worst-case.
+/// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case.
#[cold]
pub fn heapsort<T, F>(v: &mut [T], is_less: &mut F)
where
}
}
-/// Sorts `v` using pattern-defeating quicksort, which is `O(n * log(n))` worst-case.
+/// Sorts `v` using pattern-defeating quicksort, which is *O*(*n* \* log(*n*)) worst-case.
pub fn quicksort<T, F>(v: &mut [T], mut is_less: F)
where
F: FnMut(&T, &T) -> bool,
#[test]
fn test_pow() {
let mut r = 2 as $T;
-
assert_eq!(r.pow(2), 4 as $T);
assert_eq!(r.pow(0), 1 as $T);
+ assert_eq!(r.wrapping_pow(2), 4 as $T);
+ assert_eq!(r.wrapping_pow(0), 1 as $T);
+ assert_eq!(r.checked_pow(2), Some(4 as $T));
+ assert_eq!(r.checked_pow(0), Some(1 as $T));
+ assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+ assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+ assert_eq!(r.saturating_pow(2), 4 as $T);
+ assert_eq!(r.saturating_pow(0), 1 as $T);
+
+ r = MAX;
+ // use `^` to represent .pow() with no overflow.
+ // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+ // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+ // thussaturating_pow the overflowing result is exactly 1.
+ assert_eq!(r.wrapping_pow(2), 1 as $T);
+ assert_eq!(r.checked_pow(2), None);
+ assert_eq!(r.overflowing_pow(2), (1 as $T, true));
+ assert_eq!(r.saturating_pow(2), MAX);
+ //test for negative exponent.
r = -2 as $T;
assert_eq!(r.pow(2), 4 as $T);
assert_eq!(r.pow(3), -8 as $T);
+ assert_eq!(r.pow(0), 1 as $T);
+ assert_eq!(r.wrapping_pow(2), 4 as $T);
+ assert_eq!(r.wrapping_pow(3), -8 as $T);
+ assert_eq!(r.wrapping_pow(0), 1 as $T);
+ assert_eq!(r.checked_pow(2), Some(4 as $T));
+ assert_eq!(r.checked_pow(3), Some(-8 as $T));
+ assert_eq!(r.checked_pow(0), Some(1 as $T));
+ assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+ assert_eq!(r.overflowing_pow(3), (-8 as $T, false));
+ assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+ assert_eq!(r.saturating_pow(2), 4 as $T);
+ assert_eq!(r.saturating_pow(3), -8 as $T);
+ assert_eq!(r.saturating_pow(0), 1 as $T);
}
}
};
assert_eq!($T::from_str_radix("Z", 10).ok(), None::<$T>);
assert_eq!($T::from_str_radix("_", 2).ok(), None::<$T>);
}
+
+ #[test]
+ fn test_pow() {
+ let mut r = 2 as $T;
+ assert_eq!(r.pow(2), 4 as $T);
+ assert_eq!(r.pow(0), 1 as $T);
+ assert_eq!(r.wrapping_pow(2), 4 as $T);
+ assert_eq!(r.wrapping_pow(0), 1 as $T);
+ assert_eq!(r.checked_pow(2), Some(4 as $T));
+ assert_eq!(r.checked_pow(0), Some(1 as $T));
+ assert_eq!(r.overflowing_pow(2), (4 as $T, false));
+ assert_eq!(r.overflowing_pow(0), (1 as $T, false));
+ assert_eq!(r.saturating_pow(2), 4 as $T);
+ assert_eq!(r.saturating_pow(0), 1 as $T);
+
+ r = MAX;
+ // use `^` to represent .pow() with no overflow.
+ // if itest::MAX == 2^j-1, then itest is a `j` bit int,
+ // so that `itest::MAX*itest::MAX == 2^(2*j)-2^(j+1)+1`,
+ // thussaturating_pow the overflowing result is exactly 1.
+ assert_eq!(r.wrapping_pow(2), 1 as $T);
+ assert_eq!(r.checked_pow(2), None);
+ assert_eq!(r.overflowing_pow(2), (1 as $T, true));
+ assert_eq!(r.saturating_pow(2), MAX);
+ }
}
};
}
good: data[6..] == [];
bad: data[7..];
- message: "but ends at"; // perhaps not ideal
+ message: "out of range";
}
in mod rangeto_len {
// Must be pointer-sized.
type Payload = Box<Box<dyn Any + Send>>;
+extern "Rust" {
+ /// Miri-provided extern function to begin unwinding.
+ fn miri_start_panic(payload: *mut u8) -> !;
+}
+
pub unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 {
// The payload we pass to `miri_start_panic` will be exactly the argument we get
// in `cleanup` below. So we just box it up once, to get something pointer-sized.
let payload_box: Payload = Box::new(payload);
- core::intrinsics::miri_start_panic(Box::into_raw(payload_box) as *mut u8)
+ miri_start_panic(Box::into_raw(payload_box) as *mut u8)
}
pub unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> {
[package]
authors = ["The Rust Project Developers"]
-build = "build.rs"
name = "profiler_builtins"
version = "0.0.0"
edition = "2018"
let target = env::var("TARGET").expect("TARGET was not set");
let cfg = &mut cc::Build::new();
+ // FIXME: `rerun-if-changed` directives are not currently emitted and the build script
+ // will not rerun on changes in these source files or headers included into them.
let mut profile_sources = vec![
"GCDAProfiling.c",
"InstrProfiling.c",
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
- println!("cargo:rerun-if-env-changed=CFG_DISABLE_UNSTABLE_FEATURES");
-}
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::Res;
-use rustc_span::source_map::{respan, DesugaringKind, ForLoopLoc, Span, Spanned};
+use rustc_span::hygiene::ForLoopLoc;
+use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
})
});
- let mut lowered_params: Vec<_> =
- lowered_generics.params.into_iter().chain(in_band_defs).collect();
-
- // FIXME(const_generics): the compiler doesn't always cope with
- // unsorted generic parameters at the moment, so we make sure
- // that they're ordered correctly here for now. (When we chain
- // the `in_band_defs`, we might make the order unsorted.)
- lowered_params.sort_by_key(|param| match param.kind {
- hir::GenericParamKind::Lifetime { .. } => ParamKindOrd::Lifetime,
- hir::GenericParamKind::Type { .. } => ParamKindOrd::Type,
- hir::GenericParamKind::Const { .. } => ParamKindOrd::Const,
- });
-
- lowered_generics.params = lowered_params.into();
+ lowered_generics.params.extend(in_band_defs);
let lowered_generics = lowered_generics.into_generics(self.arena);
(lowered_generics, res)
fn visit_generics(&mut self, generics: &'a Generics) {
let mut prev_ty_default = None;
for param in &generics.params {
- if let GenericParamKind::Type { ref default, .. } = param.kind {
- if default.is_some() {
+ match param.kind {
+ GenericParamKind::Lifetime => (),
+ GenericParamKind::Type { default: Some(_), .. } => {
prev_ty_default = Some(param.ident.span);
- } else if let Some(span) = prev_ty_default {
- self.err_handler()
- .span_err(span, "type parameters with a default must be trailing");
- break;
+ }
+ GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
+ if let Some(span) = prev_ty_default {
+ let mut err = self.err_handler().struct_span_err(
+ span,
+ "type parameters with a default must be trailing",
+ );
+ if matches!(param.kind, GenericParamKind::Const { .. }) {
+ err.note(
+ "using type defaults and const parameters \
+ in the same parameter list is currently not permitted",
+ );
+ }
+ err.emit();
+ break;
+ }
}
}
}
name = "rustc_attr"
version = "0.0.0"
edition = "2018"
-build = "build.rs"
[lib]
name = "rustc_attr"
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-}
///
/// - `#[stable]`
/// - `#[unstable]`
-/// - `#[rustc_deprecated]`
#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[derive(HashStable_Generic)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: Symbol,
- pub rustc_depr: Option<RustcDeprecation>,
}
/// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
}
}
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)]
-#[derive(HashStable_Generic)]
-pub struct RustcDeprecation {
- pub since: Symbol,
- pub reason: Symbol,
- /// A text snippet used to completely replace any use of the deprecated item in an expression.
- pub suggestion: Option<Symbol>,
-}
-
/// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
/// This will not perform any "sanity checks" on the form of the attributes.
pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
use StabilityLevel::*;
let mut stab: Option<Stability> = None;
- let mut rustc_depr: Option<RustcDeprecation> = None;
let mut const_stab: Option<ConstStability> = None;
let mut promotable = false;
let mut allow_const_fn_ptr = false;
'outer: for attr in attrs_iter {
if ![
- sym::rustc_deprecated,
sym::rustc_const_unstable,
sym::rustc_const_stable,
sym::unstable,
}
};
- macro_rules! get_meta {
- ($($name:ident),+) => {
- $(
- let mut $name = None;
- )+
- for meta in metas {
- if let Some(mi) = meta.meta_item() {
- match mi.name_or_empty() {
- $(
- sym::$name => if !get(mi, &mut $name) { continue 'outer },
- )+
- _ => {
- let expected = &[ $( stringify!($name) ),+ ];
- handle_errors(
- sess,
- mi.span,
- AttrError::UnknownMetaItem(
- pprust::path_to_string(&mi.path),
- expected,
- ),
- );
- continue 'outer
- }
- }
- } else {
- handle_errors(
- sess,
- meta.span(),
- AttrError::UnsupportedLiteral(
- "unsupported literal",
- false,
- ),
- );
- continue 'outer
- }
- }
- }
- }
-
let meta_name = meta.name_or_empty();
match meta_name {
- sym::rustc_deprecated => {
- if rustc_depr.is_some() {
- struct_span_err!(
- diagnostic,
- item_sp,
- E0540,
- "multiple rustc_deprecated attributes"
- )
- .emit();
- continue 'outer;
- }
-
- get_meta!(since, reason, suggestion);
-
- match (since, reason) {
- (Some(since), Some(reason)) => {
- rustc_depr = Some(RustcDeprecation { since, reason, suggestion })
- }
- (None, _) => {
- handle_errors(sess, attr.span, AttrError::MissingSince);
- continue;
- }
- _ => {
- struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'")
- .emit();
- continue;
- }
- }
- }
sym::rustc_const_unstable | sym::unstable => {
if meta_name == sym::unstable && stab.is_some() {
handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
(Some(feature), reason, Some(_)) => {
let level = Unstable { reason, issue: issue_num, is_soft };
if sym::unstable == meta_name {
- stab = Some(Stability { level, feature, rustc_depr: None });
+ stab = Some(Stability { level, feature });
} else {
const_stab = Some(ConstStability {
level,
(Some(feature), Some(since)) => {
let level = Stable { since };
if sym::stable == meta_name {
- stab = Some(Stability { level, feature, rustc_depr: None });
+ stab = Some(Stability { level, feature });
} else {
const_stab = Some(ConstStability {
level,
}
}
- // Merge the deprecation info into the stability info
- if let Some(rustc_depr) = rustc_depr {
- if let Some(ref mut stab) = stab {
- stab.rustc_depr = Some(rustc_depr);
- } else {
- struct_span_err!(
- diagnostic,
- item_sp,
- E0549,
- "rustc_deprecated attribute must be paired with \
- either stable or unstable attribute"
- )
- .emit();
- }
- }
-
// Merge the const-unstable info into the stability info
if promotable || allow_const_fn_ptr {
if let Some(ref mut stab) = const_stab {
#[derive(RustcEncodable, RustcDecodable, Clone, HashStable_Generic)]
pub struct Deprecation {
pub since: Option<Symbol>,
+ /// The note to issue a reason.
pub note: Option<Symbol>,
+ /// A text snippet used to completely replace any use of the deprecated item in an expression.
+ ///
+ /// This is currently unstable.
+ pub suggestion: Option<Symbol>,
+
+ /// Whether to treat the since attribute as being a Rust version identifier
+ /// (rather than an opaque string).
+ pub is_since_rustc_version: bool,
}
/// Finds the deprecation attribute. `None` if none exists.
let diagnostic = &sess.span_diagnostic;
'outer: for attr in attrs_iter {
- if !attr.check_name(sym::deprecated) {
+ if !(attr.check_name(sym::deprecated) || attr.check_name(sym::rustc_deprecated)) {
continue;
}
Some(meta) => meta,
None => continue,
};
- depr = match &meta.kind {
- MetaItemKind::Word => Some(Deprecation { since: None, note: None }),
- MetaItemKind::NameValue(..) => {
- meta.value_str().map(|note| Deprecation { since: None, note: Some(note) })
- }
+ let mut since = None;
+ let mut note = None;
+ let mut suggestion = None;
+ match &meta.kind {
+ MetaItemKind::Word => {}
+ MetaItemKind::NameValue(..) => note = meta.value_str(),
MetaItemKind::List(list) => {
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() {
}
};
- let mut since = None;
- let mut note = None;
for meta in list {
match meta {
NestedMetaItem::MetaItem(mi) => match mi.name_or_empty() {
continue 'outer;
}
}
- sym::note => {
+ sym::note if attr.check_name(sym::deprecated) => {
+ if !get(mi, &mut note) {
+ continue 'outer;
+ }
+ }
+ sym::reason if attr.check_name(sym::rustc_deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
}
+ sym::suggestion if attr.check_name(sym::rustc_deprecated) => {
+ if !get(mi, &mut suggestion) {
+ continue 'outer;
+ }
+ }
_ => {
handle_errors(
sess,
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
- &["since", "note"],
+ if attr.check_name(sym::deprecated) {
+ &["since", "note"]
+ } else {
+ &["since", "reason", "suggestion"]
+ },
),
);
continue 'outer;
}
}
}
+ }
+ }
+
+ if suggestion.is_some() && attr.check_name(sym::deprecated) {
+ unreachable!("only allowed on rustc_deprecated")
+ }
- Some(Deprecation { since, note })
+ if attr.check_name(sym::rustc_deprecated) {
+ if since.is_none() {
+ handle_errors(sess, attr.span, AttrError::MissingSince);
+ continue;
}
- };
+
+ if note.is_none() {
+ struct_span_err!(diagnostic, attr.span, E0543, "missing 'reason'").emit();
+ continue;
+ }
+ }
+
+ mark_used(&attr);
+
+ let is_since_rustc_version = attr.check_name(sym::rustc_deprecated);
+ depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version });
}
depr
unsafe {
llvm::LLVMPointerType(
self.llvm_type(cx),
- cx.data_layout().instruction_address_space as c_uint,
+ cx.data_layout().instruction_address_space.0 as c_uint,
)
}
}
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
- println!("cargo:rerun-if-env-changed=CFG_PREFIX");
- println!("cargo:rerun-if-env-changed=CFG_LLVM_ROOT");
-}
self.call(lifetime_intrinsic, &[self.cx.const_u64(size), ptr], None);
}
- fn phi(&mut self, ty: &'ll Type, vals: &[&'ll Value], bbs: &[&'ll BasicBlock]) -> &'ll Value {
+ pub(crate) fn phi(
+ &mut self,
+ ty: &'ll Type,
+ vals: &[&'ll Value],
+ bbs: &[&'ll BasicBlock],
+ ) -> &'ll Value {
assert_eq!(vals.len(), bbs.len());
let phi = unsafe { llvm::LLVMBuildPhi(self.llbuilder, ty, UNNAMED) };
unsafe {
use rustc_codegen_ssa::traits::*;
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt};
-use rustc_middle::ty::{Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeFoldable};
/// Codegens a reference to a fn/method item, monomorphizing and
/// inlining as it goes.
assert!(!instance.substs.needs_infer());
assert!(!instance.substs.has_escaping_bound_vars());
- assert!(!instance.substs.has_param_types_or_consts());
if let Some(&llfn) = cx.instances.borrow().get(&instance) {
return llfn;
}
let sym = tcx.symbol_name(instance).name;
- debug!("get_fn({:?}: {:?}) => {}", instance, instance.monomorphic_ty(cx.tcx()), sym);
+ debug!(
+ "get_fn({:?}: {:?}) => {}",
+ instance,
+ instance.ty(cx.tcx(), ty::ParamEnv::reveal_all()),
+ sym
+ );
let fn_abi = FnAbi::of_instance(cx, instance, &[]);
use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
use rustc_span::symbol::Symbol;
-use rustc_target::abi::{self, HasDataLayout, LayoutOf, Pointer, Size};
+use rustc_target::abi::{self, AddressSpace, HasDataLayout, LayoutOf, Pointer, Size};
use libc::{c_char, c_uint};
use log::debug;
}
}
Scalar::Ptr(ptr) => {
- let base_addr = match self.tcx.global_alloc(ptr.alloc_id) {
+ let (base_addr, base_addr_space) = match self.tcx.global_alloc(ptr.alloc_id) {
GlobalAlloc::Memory(alloc) => {
let init = const_alloc_to_llvm(self, alloc);
let value = match alloc.mutability {
if !self.sess().fewer_names() {
llvm::set_value_name(value, format!("{:?}", ptr.alloc_id).as_bytes());
}
- value
+ (value, AddressSpace::DATA)
}
- GlobalAlloc::Function(fn_instance) => self.get_fn_addr(fn_instance),
+ GlobalAlloc::Function(fn_instance) => (
+ self.get_fn_addr(fn_instance.polymorphize(self.tcx)),
+ self.data_layout().instruction_address_space,
+ ),
GlobalAlloc::Static(def_id) => {
assert!(self.tcx.is_static(def_id));
assert!(!self.tcx.is_thread_local_static(def_id));
- self.get_static(def_id)
+ (self.get_static(def_id), AddressSpace::DATA)
}
};
let llval = unsafe {
llvm::LLVMConstInBoundsGEP(
- self.const_bitcast(base_addr, self.type_i8p()),
+ self.const_bitcast(base_addr, self.type_i8p_ext(base_addr_space)),
&self.const_usize(ptr.offset.bytes()),
1,
)
use rustc_hir::Node;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{
- read_target_uint, Allocation, ConstValue, ErrorHandled, Pointer,
+ read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer,
};
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
use rustc_span::symbol::sym;
use rustc_span::Span;
-use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
+use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size};
use std::ffi::CStr;
)
.expect("const_alloc_to_llvm: could not read relocation pointer")
as u64;
+
+ let address_space = match cx.tcx.global_alloc(alloc_id) {
+ GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
+ GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) => AddressSpace::DATA,
+ };
+
llvals.push(cx.scalar_to_backend(
Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
&Scalar { value: Primitive::Pointer, valid_range: 0..=!0 },
- cx.type_i8p(),
+ cx.type_i8p_ext(address_space),
));
next_offset = offset + pointer_size;
}
def_id
);
- let ty = instance.monomorphic_ty(self.tcx);
+ let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let sym = self.tcx.symbol_name(instance).name;
debug!("get_static: sym={} instance={:?}", sym, instance);
};
let instance = Instance::mono(self.tcx, def_id);
- let ty = instance.monomorphic_ty(self.tcx);
+ let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let llty = self.layout_of(ty).llvm_type(self);
let g = if val_llty == llty {
g
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.target.options.is_like_msvc {
- match sess.opts.debugging_opts.control_flow_guard {
+ match sess.opts.cg.control_flow_guard {
CFGuard::Disabled => {}
CFGuard::NoChecks => {
// Set `cfguard=1` module flag to emit metadata only.
ifn!("llvm.wasm.trunc.saturate.signed.i32.f64", fn(t_f64) -> t_i32);
ifn!("llvm.wasm.trunc.saturate.signed.i64.f32", fn(t_f32) -> t_i64);
ifn!("llvm.wasm.trunc.saturate.signed.i64.f64", fn(t_f64) -> t_i64);
+ ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
+ ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);
+ ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64);
+ ifn!("llvm.wasm.trunc.unsigned.i64.f64", fn(t_f64) -> t_i64);
+ ifn!("llvm.wasm.trunc.signed.i32.f32", fn(t_f32) -> t_i32);
+ ifn!("llvm.wasm.trunc.signed.i32.f64", fn(t_f64) -> t_i32);
+ ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64);
+ ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64);
ifn!("llvm.trap", fn() -> void);
ifn!("llvm.debugtrap", fn() -> void);
prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
.finalize(cx)
}
+ // Type parameters from polymorphized functions.
+ ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false),
_ => bug!("debuginfo: unexpected type in type_metadata: {:?}", t),
};
}
}
+fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
+ debug!("param_type_metadata: {:?}", t);
+ let name = format!("{:?}", t);
+ return unsafe {
+ llvm::LLVMRustDIBuilderCreateBasicType(
+ DIB(cx),
+ name.as_ptr().cast(),
+ name.len(),
+ Size::ZERO.bits(),
+ DW_ATE_unsigned,
+ )
+ };
+}
+
pub fn compile_unit_metadata(
tcx: TyCtxt<'_>,
codegen_unit_name: &str,
};
let is_local_to_unit = is_node_local_to_unit(cx, def_id);
- let variable_type = Instance::mono(cx.tcx, def_id).monomorphic_ty(cx.tcx);
+ let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
let type_metadata = type_metadata(cx, variable_type, span);
let var_name = tcx.item_name(def_id).as_str();
let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
use rustc_middle::mir;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, Instance, ParamEnv, Ty};
+use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeFoldable};
use rustc_session::config::{self, DebugInfo};
use rustc_span::symbol::Symbol;
use rustc_span::{self, BytePos, Span};
match impl_self_ty.kind {
ty::Adt(def, ..) if !def.is_box() => {
// Again, only create type information if full debuginfo is enabled
- if cx.sess().opts.debuginfo == DebugInfo::Full {
+ if cx.sess().opts.debuginfo == DebugInfo::Full
+ && !impl_self_ty.needs_subst()
+ {
Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
} else {
Some(namespace::item_namespace(cx, def.did))
caller_instance: ty::Instance<'tcx>,
) {
let tcx = self.tcx;
- let callee_ty = instance.monomorphic_ty(tcx);
+ let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
let (def_id, substs) = match callee_ty.kind {
ty::FnDef(def_id, substs) => (def_id, substs),
}
sym::float_to_int_unchecked => {
- if float_type_width(arg_tys[0]).is_none() {
- span_invalid_monomorphization_error(
- tcx.sess,
- span,
- &format!(
- "invalid monomorphization of `float_to_int_unchecked` \
+ let float_width = match float_type_width(arg_tys[0]) {
+ Some(width) => width,
+ None => {
+ span_invalid_monomorphization_error(
+ tcx.sess,
+ span,
+ &format!(
+ "invalid monomorphization of `float_to_int_unchecked` \
intrinsic: expected basic float type, \
found `{}`",
- arg_tys[0]
- ),
- );
- return;
- }
- match int_type_width_signed(ret_ty, self.cx) {
- Some((width, signed)) => {
- if signed {
- self.fptosi(args[0].immediate(), self.cx.type_ix(width))
- } else {
- self.fptoui(args[0].immediate(), self.cx.type_ix(width))
- }
+ arg_tys[0]
+ ),
+ );
+ return;
}
+ };
+ let (width, signed) = match int_type_width_signed(ret_ty, self.cx) {
+ Some(pair) => pair,
None => {
span_invalid_monomorphization_error(
tcx.sess,
);
return;
}
+ };
+
+ // The LLVM backend can reorder and speculate `fptosi` and
+ // `fptoui`, so on WebAssembly the codegen for this instruction
+ // is quite heavyweight. To avoid this heavyweight codegen we
+ // instead use the raw wasm intrinsics which will lower to one
+ // instruction in WebAssembly (`iNN.trunc_fMM_{s,u}`). This one
+ // instruction will trap if the operand is out of bounds, but
+ // that's ok since this intrinsic is UB if the operands are out
+ // of bounds, so the behavior can be different on WebAssembly
+ // than other targets.
+ //
+ // Note, however, that when the `nontrapping-fptoint` feature is
+ // enabled in LLVM then LLVM will lower `fptosi` to
+ // `iNN.trunc_sat_fMM_{s,u}`, so if that's the case we don't
+ // bother with intrinsics.
+ let mut result = None;
+ if self.sess().target.target.arch == "wasm32"
+ && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint)
+ {
+ let name = match (width, float_width, signed) {
+ (32, 32, true) => Some("llvm.wasm.trunc.signed.i32.f32"),
+ (32, 64, true) => Some("llvm.wasm.trunc.signed.i32.f64"),
+ (64, 32, true) => Some("llvm.wasm.trunc.signed.i64.f32"),
+ (64, 64, true) => Some("llvm.wasm.trunc.signed.i64.f64"),
+ (32, 32, false) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
+ (32, 64, false) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
+ (64, 32, false) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
+ (64, 64, false) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
+ _ => None,
+ };
+ if let Some(name) = name {
+ let intrinsic = self.get_intrinsic(name);
+ result = Some(self.call(intrinsic, &[args[0].immediate()], None));
+ }
}
+ result.unwrap_or_else(|| {
+ if signed {
+ self.fptosi(args[0].immediate(), self.cx.type_ix(width))
+ } else {
+ self.fptoui(args[0].immediate(), self.cx.type_ix(width))
+ }
+ })
}
sym::discriminant_value => {
pub use rustc_middle::mir::mono::MonoItem;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::layout::FnAbiExt;
-use rustc_middle::ty::{Instance, TypeFoldable};
+use rustc_middle::ty::{self, Instance, TypeFoldable};
use rustc_target::abi::LayoutOf;
impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
symbol_name: &str,
) {
let instance = Instance::mono(self.tcx, def_id);
- let ty = instance.monomorphic_ty(self.tcx);
+ let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
let llty = self.layout_of(ty).llvm_type(self);
let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
visibility: Visibility,
symbol_name: &str,
) {
- assert!(!instance.substs.needs_infer() && !instance.substs.has_param_types_or_consts());
+ assert!(!instance.substs.needs_infer());
let fn_abi = FnAbi::of_instance(self, instance, &[]);
let lldecl = self.declare_fn(symbol_name, &fn_abi);
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::Ty;
use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
-use rustc_target::abi::{Align, Integer, Size};
+use rustc_target::abi::{AddressSpace, Align, Integer, Size};
use std::fmt;
use std::ptr;
assert_ne!(
self.type_kind(ty),
TypeKind::Function,
- "don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead"
+ "don't call ptr_to on function types, use ptr_to_llvm_type on FnAbi instead or explicitly specify an address space if it makes sense"
);
- ty.ptr_to()
+ ty.ptr_to(AddressSpace::DATA)
+ }
+
+ fn type_ptr_to_ext(&self, ty: &'ll Type, address_space: AddressSpace) -> &'ll Type {
+ ty.ptr_to(address_space)
}
fn element_type(&self, ty: &'ll Type) -> &'ll Type {
}
pub fn i8p_llcx(llcx: &llvm::Context) -> &Type {
- Type::i8_llcx(llcx).ptr_to()
+ Type::i8_llcx(llcx).ptr_to(AddressSpace::DATA)
}
- fn ptr_to(&self) -> &Type {
- unsafe { llvm::LLVMPointerType(&self, 0) }
+ fn ptr_to(&self, address_space: AddressSpace) -> &Type {
+ unsafe { llvm::LLVMPointerType(&self, address_space.0) }
}
}
use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout};
use rustc_middle::ty::print::obsolete::DefPathBasedNames;
use rustc_middle::ty::{self, Ty, TypeFoldable};
-use rustc_target::abi::{Abi, Align, FieldsShape};
+use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{LayoutOf, PointeeInfo, Scalar, Size, TyAndLayoutMethods, Variants};
F64 => cx.type_f64(),
Pointer => {
// If we know the alignment, pick something better than i8.
- let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
- cx.type_pointee_for_align(pointee.align)
- } else {
- cx.type_i8()
- };
- cx.type_ptr_to(pointee)
+ let (pointee, address_space) =
+ if let Some(pointee) = self.pointee_info_at(cx, offset) {
+ (cx.type_pointee_for_align(pointee.align), pointee.address_space)
+ } else {
+ (cx.type_i8(), AddressSpace::DATA)
+ };
+ cx.type_ptr_to_ext(pointee, address_space)
}
}
}
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
use rustc_codegen_ssa::mir::operand::OperandRef;
-use rustc_codegen_ssa::traits::{
- BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods,
+use rustc_codegen_ssa::{
+ common::IntPredicate,
+ traits::{BaseTypeMethods, BuilderMethods, ConstMethods, DerivedTypeMethods},
};
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::Ty;
}
}
+fn emit_aapcs_va_arg(
+ bx: &mut Builder<'a, 'll, 'tcx>,
+ list: OperandRef<'tcx, &'ll Value>,
+ target_ty: Ty<'tcx>,
+) -> &'ll Value {
+ // Implementation of the AAPCS64 calling convention for va_args see
+ // https://github.com/ARM-software/abi-aa/blob/master/aapcs64/aapcs64.rst
+ let va_list_addr = list.immediate();
+ let layout = bx.cx.layout_of(target_ty);
+
+ let mut maybe_reg = bx.build_sibling_block("va_arg.maybe_reg");
+ let mut in_reg = bx.build_sibling_block("va_arg.in_reg");
+ let mut on_stack = bx.build_sibling_block("va_arg.on_stack");
+ let mut end = bx.build_sibling_block("va_arg.end");
+ let zero = bx.const_i32(0);
+ let offset_align = Align::from_bytes(4).unwrap();
+ assert!(&*bx.tcx().sess.target.target.target_endian == "little");
+
+ let gr_type = target_ty.is_any_ptr() || target_ty.is_integral();
+ let (reg_off, reg_top_index, slot_size) = if gr_type {
+ let gr_offs = bx.struct_gep(va_list_addr, 7);
+ let nreg = (layout.size.bytes() + 7) / 8;
+ (gr_offs, 3, nreg * 8)
+ } else {
+ let vr_off = bx.struct_gep(va_list_addr, 9);
+ let nreg = (layout.size.bytes() + 15) / 16;
+ (vr_off, 5, nreg * 16)
+ };
+
+ // if the offset >= 0 then the value will be on the stack
+ let mut reg_off_v = bx.load(reg_off, offset_align);
+ let use_stack = bx.icmp(IntPredicate::IntSGE, reg_off_v, zero);
+ bx.cond_br(use_stack, &on_stack.llbb(), &maybe_reg.llbb());
+
+ // The value at this point might be in a register, but there is a chance that
+ // it could be on the stack so we have to update the offset and then check
+ // the offset again.
+
+ if gr_type && layout.align.abi.bytes() > 8 {
+ reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(15));
+ reg_off_v = maybe_reg.and(reg_off_v, bx.const_i32(-16));
+ }
+ let new_reg_off_v = maybe_reg.add(reg_off_v, bx.const_i32(slot_size as i32));
+
+ maybe_reg.store(new_reg_off_v, reg_off, offset_align);
+
+ // Check to see if we have overflowed the registers as a result of this.
+ // If we have then we need to use the stack for this value
+ let use_stack = maybe_reg.icmp(IntPredicate::IntSGT, new_reg_off_v, zero);
+ maybe_reg.cond_br(use_stack, &on_stack.llbb(), &in_reg.llbb());
+
+ let top = in_reg.struct_gep(va_list_addr, reg_top_index);
+ let top = in_reg.load(top, bx.tcx().data_layout.pointer_align.abi);
+
+ // reg_value = *(@top + reg_off_v);
+ let top = in_reg.gep(top, &[reg_off_v]);
+ let top = in_reg.bitcast(top, bx.cx.type_ptr_to(layout.llvm_type(bx)));
+ let reg_value = in_reg.load(top, layout.align.abi);
+ in_reg.br(&end.llbb());
+
+ // On Stack block
+ let stack_value =
+ emit_ptr_va_arg(&mut on_stack, list, target_ty, false, Align::from_bytes(8).unwrap(), true);
+ on_stack.br(&end.llbb());
+
+ let val = end.phi(
+ layout.immediate_llvm_type(bx),
+ &[reg_value, stack_value],
+ &[&in_reg.llbb(), &on_stack.llbb()],
+ );
+
+ *bx = end;
+ val
+}
+
pub(super) fn emit_va_arg(
bx: &mut Builder<'a, 'll, 'tcx>,
addr: OperandRef<'tcx, &'ll Value>,
("aarch64", _) if target.target_os == "ios" => {
emit_ptr_va_arg(bx, addr, target_ty, false, Align::from_bytes(8).unwrap(), true)
}
+ ("aarch64", _) => emit_aapcs_va_arg(bx, addr, target_ty),
// Windows x86_64
("x86_64", true) => {
let target_ty_size = bx.cx.size_of(target_ty).bytes();
}
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
- cmd.add_eh_frame_header();
+ if sess.target.target.options.eh_frame_header {
+ cmd.add_eh_frame_header();
+ }
// NO-OPT-OUT, OBJECT-FILES-NO
if crt_objects_fallback {
}
// OBJECT-FILES-NO, AUDIT-ORDER
- if sess.opts.debugging_opts.control_flow_guard != CFGuard::Disabled {
+ if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
cmd.control_flow_guard();
}
// Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't,
// so we just always add it.
fn add_eh_frame_header(&mut self) {
- if !self.sess.target.target.options.is_like_osx
- && !self.sess.target.target.options.is_like_windows
- && !self.sess.target.target.options.is_like_solaris
- && self.sess.target.target.target_os != "uefi"
- {
- self.linker_arg("--eh-frame-hdr");
- }
+ self.linker_arg("--eh-frame-hdr");
}
}
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE_CHANNEL");
-}
tcx.def_key(def_id).disambiguated_data.disambiguator
));
}
+ // Type parameters from polymorphized functions.
+ ty::Param(_) => {
+ output.push_str(&format!("{:?}", t));
+ }
ty::Error(_)
| ty::Infer(_)
| ty::Placeholder(..)
| ty::Projection(..)
| ty::Bound(..)
| ty::Opaque(..)
- | ty::GeneratorWitness(..)
- | ty::Param(_) => {
+ | ty::GeneratorWitness(..) => {
bug!(
"debuginfo: Trying to create type name for \
unexpected type: {:?}",
}
// Not in the cache; build it.
- let nullptr = cx.const_null(cx.type_i8p());
+ let nullptr = cx.const_null(cx.type_i8p_ext(cx.data_layout().instruction_address_space));
let methods_root;
let methods = if let Some(trait_ref) = trait_ref {
def_id,
substs,
)
- .unwrap(),
+ .unwrap()
+ .polymorphize(cx.tcx()),
)
})
});
let base_ty = self.fx.monomorphize(&base_ty);
// ZSTs don't require any actual memory access.
- let elem_ty = base_ty.projection_ty(cx.tcx(), elem).ty;
- let elem_ty = self.fx.monomorphize(&elem_ty);
+ let elem_ty = base_ty.projection_ty(cx.tcx(), self.fx.monomorphize(&elem)).ty;
let span = self.fx.mir.local_decls[place_ref.local].source_info.span;
if cx.spanned_layout_of(elem_ty, span).is_zst() {
return;
Some(
ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs)
.unwrap()
- .unwrap(),
+ .unwrap()
+ .polymorphize(bx.tcx()),
),
None,
),
return;
}
- // For normal codegen, this Miri-specific intrinsic should never occur.
- if intrinsic == Some(sym::miri_start_panic) {
- bug!("`miri_start_panic` should never end up in compiled code");
- }
-
if self.codegen_panic_intrinsic(
&helper,
&mut bx,
let ptr = Pointer::new(AllocId(0), offset);
alloc
.read_scalar(&bx, ptr, size)
- .and_then(|s| s.not_undef())
+ .and_then(|s| s.check_init())
.unwrap_or_else(|e| {
bx.tcx().sess.span_err(
span,
use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_target::abi::call::{FnAbi, PassMode};
+use rustc_target::abi::HasDataLayout;
use std::iter;
// C++ personality function, but `catch (...)` has no type so
// it's null. The 64 here is actually a bitfield which
// represents that this is a catch-all block.
- let null = bx.const_null(bx.type_i8p());
+ let null = bx.const_null(
+ bx.type_i8p_ext(bx.cx().data_layout().instruction_address_space),
+ );
let sixty_four = bx.const_i32(64);
funclet = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
cp_bx.br(llbb);
if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) {
bug!("reifying a fn ptr that requires const arguments");
}
- OperandValue::Immediate(
- bx.get_fn_addr(
- ty::Instance::resolve_for_fn_ptr(
- bx.tcx(),
- ty::ParamEnv::reveal_all(),
- def_id,
- substs,
- )
- .unwrap(),
- ),
+ let instance = ty::Instance::resolve_for_fn_ptr(
+ bx.tcx(),
+ ty::ParamEnv::reveal_all(),
+ def_id,
+ substs,
)
+ .unwrap()
+ .polymorphize(bx.cx().tcx());
+ OperandValue::Immediate(bx.get_fn_addr(instance))
}
_ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
}
def_id,
substs,
ty::ClosureKind::FnOnce,
- );
+ )
+ .polymorphize(bx.cx().tcx());
OperandValue::Immediate(bx.cx().get_fn_addr(instance))
}
_ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
use rustc_middle::ty::{self, Ty};
use rustc_span::DUMMY_SP;
use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
-use rustc_target::abi::Integer;
+use rustc_target::abi::{AddressSpace, Integer};
// This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
// `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves.
fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type;
fn type_kind(&self, ty: Self::Type) -> TypeKind;
fn type_ptr_to(&self, ty: Self::Type) -> Self::Type;
+ fn type_ptr_to_ext(&self, ty: Self::Type, address_space: AddressSpace) -> Self::Type;
fn element_type(&self, ty: Self::Type) -> Self::Type;
/// Returns the number of elements in `self` if it is a LLVM vector type.
pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> {
fn type_i8p(&self) -> Self::Type {
- self.type_ptr_to(self.type_i8())
+ self.type_i8p_ext(AddressSpace::DATA)
+ }
+
+ fn type_i8p_ext(&self, address_space: AddressSpace) -> Self::Type {
+ self.type_ptr_to_ext(self.type_i8(), address_space)
}
fn type_int(&self) -> Self::Type {
use crate::stable_hasher::{HashStable, StableHasher};
use rustc_index::vec::{Idx, IndexVec};
-/// An indexed multi-map that preserves insertion order while permitting both `O(log n)` lookup of
-/// an item by key and `O(1)` lookup by index.
+/// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of
+/// an item by key and *O*(1) lookup by index.
///
/// This data structure is a hybrid of an [`IndexVec`] and a [`SortedMap`]. Like `IndexVec`,
/// `SortedIndexMultiMap` assigns a typed index to each item while preserving insertion order.
/// items will be yielded in insertion order.
///
/// Unlike a general-purpose map like `BTreeSet` or `HashSet`, `SortedMap` and
-/// `SortedIndexMultiMap` require `O(n)` time to insert a single item. This is because we may need
+/// `SortedIndexMultiMap` require *O*(*n*) time to insert a single item. This is because we may need
/// to insert into the middle of the sorted array. Users should avoid mutating this data structure
/// in-place.
///
}
}
+impl<T, CTX> HashStable<CTX> for bit_set::FiniteBitSet<T>
+where
+ T: HashStable<CTX> + bit_set::FiniteBitSetTy,
+{
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ self.0.hash_stable(hcx, hasher);
+ }
+}
+
impl_stable_hash_via_hash!(::std::path::Path);
impl_stable_hash_via_hash!(::std::path::PathBuf);
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_RELEASE");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
- println!("cargo:rerun-if-env-changed=CFG_VER_DATE");
- println!("cargo:rerun-if-env-changed=CFG_VER_HASH");
-}
E0768: include_str!("./error_codes/E0768.md"),
E0769: include_str!("./error_codes/E0769.md"),
E0770: include_str!("./error_codes/E0770.md"),
+E0771: include_str!("./error_codes/E0771.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
E0521, // borrowed data escapes outside of closure
E0523,
// E0526, // shuffle indices are not constant
- E0540, // multiple rustc_deprecated attributes
+// E0540, // multiple rustc_deprecated attributes
E0542, // missing 'since'
E0543, // missing 'reason'
E0544, // multiple stability levels
E0755, // `#[ffi_pure]` is only allowed on foreign functions
E0756, // `#[ffi_const]` is only allowed on foreign functions
E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]`
+ E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
}
-The value for an associated type has already been specified.
+An associated type value was specified more than once.
Erroneous code example:
trait BarTrait {}
trait FooBarTrait: FooTrait + BarTrait {}
-struct Foo<T: Iterator<Item: FooBarTrait>> { f: T }
+struct Foo<T: Iterator<Item: FooBarTrait>> { f: T } // ok!
```
For more information about associated types, see [the book][bk-at]. For more
-`#[ffi_returns_twice]` was used on non-foreign function.
+`#[ffi_returns_twice]` was used on something other than a foreign function
+declaration.
Erroneous code example:
A `yield` clause was used in an `async` context.
-Example of erroneous code:
+Erroneous code example:
```compile_fail,E0727,edition2018
#![feature(generators)]
--- /dev/null
+A non-`'static` lifetime was used in a const generic. This is currently not
+allowed.
+
+Erroneous code example:
+
+```compile_fail,E0771
+#![feature(const_generics)]
+
+fn function_with_str<'a, const STRING: &'a str>() {} // error!
+```
+
+To fix this issue, the lifetime in the const generic need to be changed to
+`'static`:
+
+```
+#![feature(const_generics)]
+
+fn function_with_str<const STRING: &'static str>() {} // ok!
+```
+
+For more information, see [GitHub issue #74052].
+
+[GitHub issue #74052]: https://github.com/rust-lang/rust/issues/74052
use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
use rustc_session::{parse::ParseSess, Limit};
-use rustc_span::def_id::DefId;
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
use rustc_span::source_map::SourceMap;
local_inner_macros: self.local_inner_macros,
edition: self.edition,
macro_def_id,
+ krate: LOCAL_CRATE,
+ orig_id: None,
}
}
}
use crate::base::*;
use crate::config::StripUnconfigured;
use crate::configure;
-use crate::hygiene::{ExpnData, ExpnId, ExpnKind, SyntaxContext};
+use crate::hygiene::{ExpnData, ExpnKind, SyntaxContext};
use crate::mbe::macro_rules::annotate_err_with_kind;
use crate::module::{parse_external_mod, push_directory, Directory, DirectoryOwnership};
use crate::placeholders::{placeholder, PlaceholderExpander};
use rustc_ast_pretty::pprust;
use rustc_attr::{self as attr, is_builtin_attr, HasAttrs};
use rustc_data_structures::map_in_place::MapInPlace;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, PResult};
use rustc_feature::Features;
use rustc_parse::parser::Parser;
use rustc_session::Limit;
use rustc_span::source_map::respan;
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{FileName, Span, DUMMY_SP};
+use rustc_span::{ExpnId, FileName, Span, DUMMY_SP};
use smallvec::{smallvec, SmallVec};
use std::io::ErrorKind;
self.check_attributes(&expr.attrs);
self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr().into_inner()
} else {
- noop_visit_expr(&mut expr, self);
+ ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
expr
}
});
/// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
(accepted, slice_patterns, "1.42.0", Some(62254), None),
/// Allows the use of `if` and `match` in constants.
- (accepted, const_if_match, "1.45.0", Some(49146), None),
+ (accepted, const_if_match, "1.46.0", Some(49146), None),
/// Allows the use of `loop` and `while` in constants.
- (accepted, const_loop, "1.45.0", Some(52000), None),
+ (accepted, const_loop, "1.46.0", Some(52000), None),
/// Allows `#[track_caller]` to be used which provides
/// accurate caller location reporting during panic (RFC 2091).
(accepted, track_caller, "1.46.0", Some(47809), None),
),
rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)),
+ rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")),
rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
NotAsync,
}
-#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+#[derive(
+ Copy,
+ Clone,
+ PartialEq,
+ RustcEncodable,
+ RustcDecodable,
+ Debug,
+ HashStable_Generic,
+ Eq,
+ Hash
+)]
pub enum Defaultness {
Default { has_value: bool },
Final,
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
-}
use std::iter;
use std::marker::PhantomData;
use std::mem;
+use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Not, Range, Shl};
use std::slice;
#[cfg(test)]
}
/// Returns those indices that are true in rows `a` and `b`. This
- /// is an O(n) operation where `n` is the number of elements
+ /// is an *O*(*n*) operation where *n* is the number of elements
/// (somewhat independent from the actual size of the
/// intersection, in particular).
pub fn intersect_rows(&self, row1: R, row2: R) -> Vec<C> {
let mask = 1 << (elem % WORD_BITS);
(word_index, mask)
}
+
+/// Integral type used to represent the bit set.
+pub trait FiniteBitSetTy:
+ BitAnd<Output = Self>
+ + BitAndAssign
+ + BitOrAssign
+ + Clone
+ + Copy
+ + Shl
+ + Not<Output = Self>
+ + PartialEq
+ + Sized
+{
+ /// Size of the domain representable by this type, e.g. 64 for `u64`.
+ const DOMAIN_SIZE: u32;
+
+ /// Value which represents the `FiniteBitSet` having every bit set.
+ const FILLED: Self;
+ /// Value which represents the `FiniteBitSet` having no bits set.
+ const EMPTY: Self;
+
+ /// Value for one as the integral type.
+ const ONE: Self;
+ /// Value for zero as the integral type.
+ const ZERO: Self;
+
+ /// Perform a checked left shift on the integral type.
+ fn checked_shl(self, rhs: u32) -> Option<Self>;
+ /// Perform a checked right shift on the integral type.
+ fn checked_shr(self, rhs: u32) -> Option<Self>;
+}
+
+impl FiniteBitSetTy for u64 {
+ const DOMAIN_SIZE: u32 = 64;
+
+ const FILLED: Self = Self::MAX;
+ const EMPTY: Self = Self::MIN;
+
+ const ONE: Self = 1u64;
+ const ZERO: Self = 0u64;
+
+ fn checked_shl(self, rhs: u32) -> Option<Self> {
+ self.checked_shl(rhs)
+ }
+
+ fn checked_shr(self, rhs: u32) -> Option<Self> {
+ self.checked_shr(rhs)
+ }
+}
+
+impl std::fmt::Debug for FiniteBitSet<u64> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:064b}", self.0)
+ }
+}
+
+impl FiniteBitSetTy for u128 {
+ const DOMAIN_SIZE: u32 = 128;
+
+ const FILLED: Self = Self::MAX;
+ const EMPTY: Self = Self::MIN;
+
+ const ONE: Self = 1u128;
+ const ZERO: Self = 0u128;
+
+ fn checked_shl(self, rhs: u32) -> Option<Self> {
+ self.checked_shl(rhs)
+ }
+
+ fn checked_shr(self, rhs: u32) -> Option<Self> {
+ self.checked_shr(rhs)
+ }
+}
+
+impl std::fmt::Debug for FiniteBitSet<u128> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:0128b}", self.0)
+ }
+}
+
+/// A fixed-sized bitset type represented by an integer type. Indices outwith than the range
+/// representable by `T` are considered set.
+#[derive(Copy, Clone, Eq, PartialEq, RustcDecodable, RustcEncodable)]
+pub struct FiniteBitSet<T: FiniteBitSetTy>(pub T);
+
+impl<T: FiniteBitSetTy> FiniteBitSet<T> {
+ /// Creates a new, empty bitset.
+ pub fn new_empty() -> Self {
+ Self(T::EMPTY)
+ }
+
+ /// Sets the `index`th bit.
+ pub fn set(&mut self, index: u32) {
+ self.0 |= T::ONE.checked_shl(index).unwrap_or(T::ZERO);
+ }
+
+ /// Unsets the `index`th bit.
+ pub fn clear(&mut self, index: u32) {
+ self.0 &= !T::ONE.checked_shl(index).unwrap_or(T::ZERO);
+ }
+
+ /// Sets the `i`th to `j`th bits.
+ pub fn set_range(&mut self, range: Range<u32>) {
+ let bits = T::FILLED
+ .checked_shl(range.end - range.start)
+ .unwrap_or(T::ZERO)
+ .not()
+ .checked_shl(range.start)
+ .unwrap_or(T::ZERO);
+ self.0 |= bits;
+ }
+
+ /// Is the set empty?
+ pub fn is_empty(&self) -> bool {
+ self.0 == T::EMPTY
+ }
+
+ /// Returns the domain size of the bitset.
+ pub fn within_domain(&self, index: u32) -> bool {
+ index < T::DOMAIN_SIZE
+ }
+
+ /// Returns if the `index`th bit is set.
+ pub fn contains(&self, index: u32) -> Option<bool> {
+ self.within_domain(index)
+ .then(|| ((self.0.checked_shr(index).unwrap_or(T::ONE)) & T::ONE) == T::ONE)
+ }
+}
+
+impl<T: FiniteBitSetTy> Default for FiniteBitSet<T> {
+ fn default() -> Self {
+ Self::new_empty()
+ }
+}
#![feature(allow_internal_unstable)]
+#![feature(bool_to_option)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(extend_one)]
use rustc_ast::ast;
use rustc_hir::def_id::DefId;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{IntType, UintType};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
};
debug!("generalize: for_universe = {:?}", for_universe);
+ debug!("generalize: trace = {:?}", self.trace);
let mut generalize = Generalizer {
infcx: self.infcx,
- span: self.trace.cause.span,
+ cause: &self.trace.cause,
for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
for_universe,
ambient_variance,
infcx: &'cx InferCtxt<'cx, 'tcx>,
/// The span, used when creating new type variables and things.
- span: Span,
+ cause: &'cx ObligationCause<'tcx>,
/// The vid of the type variable that is in the process of being
/// instantiated; if we find this within the type we are folding,
// FIXME: This is non-ideal because we don't give a
// very descriptive origin for this region variable.
- Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
+ Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe))
}
fn consts(
}
debug!("note_type_err(diag={:?})", diag);
+ enum Mismatch<'a> {
+ Variable(ty::error::ExpectedFound<Ty<'a>>),
+ Fixed(&'static str),
+ }
let (expected_found, exp_found, is_simple_error) = match values {
- None => (None, None, false),
+ None => (None, Mismatch::Fixed("type"), false),
Some(values) => {
let (is_simple_error, exp_found) = match values {
ValuePairs::Types(exp_found) => {
)
.report(diag);
- (is_simple_err, Some(exp_found))
+ (is_simple_err, Mismatch::Variable(exp_found))
}
- _ => (false, None),
+ ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
+ _ => (false, Mismatch::Fixed("type")),
};
let vals = match self.values_str(&values) {
Some((expected, found)) => Some((expected, found)),
}
};
if let Some((expected, found)) = expected_found {
- let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string());
- let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string());
+ let expected_label = match exp_found {
+ Mismatch::Variable(ef) => ef.expected.prefix_string(),
+ Mismatch::Fixed(s) => s.into(),
+ };
+ let found_label = match exp_found {
+ Mismatch::Variable(ef) => ef.found.prefix_string(),
+ Mismatch::Fixed(s) => s.into(),
+ };
+ let exp_found = match exp_found {
+ Mismatch::Variable(exp_found) => Some(exp_found),
+ Mismatch::Fixed(_) => None,
+ };
match (&terr, expected == found) {
(TypeError::Sorts(values), extra) => {
let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) {
}
}
}
+ let exp_found = match exp_found {
+ Mismatch::Variable(exp_found) => Some(exp_found),
+ Mismatch::Fixed(_) => None,
+ };
if let Some(exp_found) = exp_found {
self.suggest_as_ref_where_appropriate(span, &exp_found, diag);
}
infer::MiscVariable(_) => String::new(),
infer::PatternRegion(_) => " for pattern".to_string(),
infer::AddrOfRegion(_) => " for borrow expression".to_string(),
- infer::Autoref(_) => " for autoref".to_string(),
+ infer::Autoref(_, _) => " for autoref".to_string(),
infer::Coercion(_) => " for automatic coercion".to_string(),
infer::LateBoundRegion(_, br, infer::FnCall) => {
format!(" for lifetime parameter {}in function call", br_string(br))
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
-use rustc_errors::{struct_span_err, Applicability, ErrorReported};
-use rustc_hir::{GenericBound, ItemKind, Lifetime, LifetimeName, TyKind};
-use rustc_middle::ty::RegionKind;
+use crate::infer::{SubregionOrigin, TypeTrace};
+use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::{
+ self as hir, GenericBound, ImplItem, Item, ItemKind, Lifetime, LifetimeName, Node, TraitItem,
+ TyKind,
+};
+use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor};
+use rustc_span::symbol::Ident;
+use rustc_span::{MultiSpan, Span};
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
- /// Print the error message for lifetime errors when the return type is a static impl Trait.
+ /// Print the error message for lifetime errors when the return type is a static `impl Trait`,
+ /// `dyn Trait` or if a method call on a trait object introduces a static requirement.
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
debug!("try_report_static_impl_trait(error={:?})", self.error);
- if let Some(RegionResolutionError::SubSupConflict(
- _,
- var_origin,
- ref sub_origin,
- sub_r,
- ref sup_origin,
- sup_r,
- )) = self.error
- {
- debug!(
- "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
- var_origin, sub_origin, sub_r, sup_origin, sup_r
- );
- let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?;
- debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
- let fn_returns = self.tcx().return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
- if fn_returns.is_empty() {
+ let tcx = self.tcx();
+ let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
+ RegionResolutionError::SubSupConflict(
+ _,
+ var_origin,
+ sub_origin,
+ sub_r,
+ sup_origin,
+ sup_r,
+ ) if **sub_r == RegionKind::ReStatic => {
+ (var_origin, sub_origin, sub_r, sup_origin, sup_r)
+ }
+ RegionResolutionError::ConcreteFailure(
+ SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
+ sub_r,
+ sup_r,
+ ) if **sub_r == RegionKind::ReStatic => {
+ // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
+ if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
+ let param = self.find_param_with_region(sup_r, sub_r)?;
+ let lifetime = if sup_r.has_name() {
+ format!("lifetime `{}`", sup_r)
+ } else {
+ "an anonymous lifetime `'_`".to_string()
+ };
+ let mut err = struct_span_err!(
+ tcx.sess,
+ cause.span,
+ E0772,
+ "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
+ requirement",
+ param
+ .param
+ .pat
+ .simple_ident()
+ .map(|s| format!("`{}`", s))
+ .unwrap_or_else(|| "`fn` parameter".to_string()),
+ lifetime,
+ ctxt.assoc_item.ident,
+ );
+ err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
+ err.span_label(
+ cause.span,
+ &format!(
+ "...is captured and required to live as long as `'static` here \
+ because of an implicit lifetime bound on the {}",
+ match ctxt.assoc_item.container {
+ AssocItemContainer::TraitContainer(id) =>
+ format!("`impl` of `{}`", tcx.def_path_str(id)),
+ AssocItemContainer::ImplContainer(_) =>
+ "inherent `impl`".to_string(),
+ },
+ ),
+ );
+ if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
+ err.emit();
+ return Some(ErrorReported);
+ } else {
+ err.cancel();
+ }
+ }
return None;
}
- debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
- if *sub_r == RegionKind::ReStatic {
- let sp = var_origin.span();
- let return_sp = sub_origin.span();
- let param_info = self.find_param_with_region(sup_r, sub_r)?;
- let (lifetime_name, lifetime) = if sup_r.has_name() {
- (sup_r.to_string(), format!("lifetime `{}`", sup_r))
- } else {
- ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
- };
- let mut err = struct_span_err!(
- self.tcx().sess,
- sp,
- E0759,
- "cannot infer an appropriate lifetime"
- );
+ _ => return None,
+ };
+ debug!(
+ "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
+ var_origin, sub_origin, sub_r, sup_origin, sup_r
+ );
+ let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+ debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
+ let sp = var_origin.span();
+ let return_sp = sub_origin.span();
+ let param = self.find_param_with_region(sup_r, sub_r)?;
+ let (lifetime_name, lifetime) = if sup_r.has_name() {
+ (sup_r.to_string(), format!("lifetime `{}`", sup_r))
+ } else {
+ ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
+ };
+ let param_name = param
+ .param
+ .pat
+ .simple_ident()
+ .map(|s| format!("`{}`", s))
+ .unwrap_or_else(|| "`fn` parameter".to_string());
+ let mut err = struct_span_err!(
+ tcx.sess,
+ sp,
+ E0759,
+ "{} has {} but it needs to satisfy a `'static` lifetime requirement",
+ param_name,
+ lifetime,
+ );
+ err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
+ debug!("try_report_static_impl_trait: param_info={:?}", param);
+
+ // We try to make the output have fewer overlapping spans if possible.
+ if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
+ && sup_origin.span() != return_sp
+ {
+ // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
+
+ // Customize the spans and labels depending on their relative order so
+ // that split sentences flow correctly.
+ if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
+ // Avoid the following:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ---------^-
+ //
+ // and instead show:
+ //
+ // error: cannot infer an appropriate lifetime
+ // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+ // |
+ // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
+ // | ---- ^
err.span_label(
- param_info.param_ty_span,
- &format!("this data with {}...", lifetime),
+ sup_origin.span(),
+ "...is captured here, requiring it to live as long as `'static`",
);
- debug!("try_report_static_impl_trait: param_info={:?}", param_info);
+ } else {
+ err.span_label(sup_origin.span(), "...is captured here...");
+ if return_sp < sup_origin.span() {
+ err.span_note(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ } else {
+ err.span_label(
+ return_sp,
+ "...and is required to live as long as `'static` here",
+ );
+ }
+ }
+ } else {
+ err.span_label(
+ return_sp,
+ "...is captured and required to live as long as `'static` here",
+ );
+ }
+
+ let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
- // We try to make the output have fewer overlapping spans if possible.
- if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
- && sup_origin.span() != return_sp
+ let mut override_error_code = None;
+ if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin {
+ if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code {
+ // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
+ // `'static` lifetime when called as a method on a binding: `bar.qux()`.
+ if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
+ override_error_code = Some(ctxt.assoc_item.ident);
+ }
+ }
+ }
+ if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin {
+ if let ObligationCauseCode::ItemObligation(item_def_id) = cause.code {
+ // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
+ // lifetime as above, but called using a fully-qualified path to the method:
+ // `Foo::qux(bar)`.
+ let mut v = TraitObjectVisitor(vec![]);
+ v.visit_ty(param.param_ty);
+ if let Some((ident, self_ty)) =
+ self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0[..])
{
- // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
-
- // Customize the spans and labels depending on their relative order so
- // that split sentences flow correctly.
- if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
- // Avoid the following:
- //
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ---------^-
- //
- // and instead show:
- //
- // error: cannot infer an appropriate lifetime
- // --> $DIR/must_outlive_least_region_or_bound.rs:18:50
- // |
- // LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
- // | ---- ^
- err.span_label(
- sup_origin.span(),
- "...is captured here, requiring it to live as long as `'static`",
+ if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0[..], ident, self_ty)
+ {
+ override_error_code = Some(ident);
+ }
+ }
+ }
+ }
+ if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
+ // Provide a more targetted error code and description.
+ err.code(rustc_errors::error_code!(E0772));
+ err.set_primary_message(&format!(
+ "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
+ requirement",
+ param_name, lifetime, ident,
+ ));
+ }
+
+ debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
+ // FIXME: account for the need of parens in `&(dyn Trait + '_)`
+ let consider = "consider changing the";
+ let declare = "to declare that the";
+ let arg = match param.param.pat.simple_ident() {
+ Some(simple_ident) => format!("argument `{}`", simple_ident),
+ None => "the argument".to_string(),
+ };
+ let explicit = format!("you can add an explicit `{}` lifetime bound", lifetime_name);
+ let explicit_static = format!("explicit `'static` bound to the lifetime of {}", arg);
+ let captures = format!("captures data from {}", arg);
+ let add_static_bound = "alternatively, add an explicit `'static` bound to this reference";
+ let plus_lt = format!(" + {}", lifetime_name);
+ for fn_return in fn_returns {
+ if fn_return.span.desugaring_kind().is_some() {
+ // Skip `async` desugaring `impl Future`.
+ continue;
+ }
+ match fn_return.kind {
+ TyKind::OpaqueDef(item_id, _) => {
+ let item = tcx.hir().item(item_id.id);
+ let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
+ opaque
+ } else {
+ err.emit();
+ return Some(ErrorReported);
+ };
+
+ if let Some(span) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime {
+ name: LifetimeName::Static,
+ span,
+ ..
+ }) => Some(*span),
+ _ => None,
+ })
+ .next()
+ {
+ err.span_suggestion_verbose(
+ span,
+ &format!("{} `impl Trait`'s {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param.param_ty_span,
+ add_static_bound,
+ param.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
);
+ } else if let Some(_) = opaque
+ .bounds
+ .iter()
+ .filter_map(|arg| match arg {
+ GenericBound::Outlives(Lifetime { name, span, .. })
+ if name.ident().to_string() == lifetime_name =>
+ {
+ Some(*span)
+ }
+ _ => None,
+ })
+ .next()
+ {
} else {
- err.span_label(sup_origin.span(), "...is captured here...");
- if return_sp < sup_origin.span() {
- err.span_note(
- return_sp,
- "...and is required to live as long as `'static` here",
- );
- } else {
- err.span_label(
- return_sp,
- "...and is required to live as long as `'static` here",
- );
- }
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} `impl Trait` {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
+ );
}
- } else {
- err.span_label(
- return_sp,
- "...is captured and required to live as long as `'static` here",
- );
}
+ TyKind::TraitObject(_, lt) => match lt.name {
+ LifetimeName::ImplicitObjectLifetimeDefault => {
+ err.span_suggestion_verbose(
+ fn_return.span.shrink_to_hi(),
+ &format!(
+ "{declare} trait object {captures}, {explicit}",
+ declare = declare,
+ captures = captures,
+ explicit = explicit,
+ ),
+ plus_lt.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ name if name.ident().to_string() != lifetime_name => {
+ // With this check we avoid suggesting redundant bounds. This
+ // would happen if there are nested impl/dyn traits and only
+ // one of them has the bound we'd suggest already there, like
+ // in `impl Foo<X = dyn Bar> + '_`.
+ err.span_suggestion_verbose(
+ lt.span,
+ &format!("{} trait object's {}", consider, explicit_static),
+ lifetime_name.clone(),
+ Applicability::MaybeIncorrect,
+ );
+ err.span_suggestion_verbose(
+ param.param_ty_span,
+ add_static_bound,
+ param.param_ty.to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ _ => {}
+ },
+ _ => {}
+ }
+ }
+ err.emit();
+ Some(ErrorReported)
+ }
- // FIXME: account for the need of parens in `&(dyn Trait + '_)`
- let consider = "consider changing the";
- let declare = "to declare that the";
- let arg = match param_info.param.pat.simple_ident() {
- Some(simple_ident) => format!("argument `{}`", simple_ident),
- None => "the argument".to_string(),
- };
- let explicit =
- format!("you can add an explicit `{}` lifetime bound", lifetime_name);
- let explicit_static =
- format!("explicit `'static` bound to the lifetime of {}", arg);
- let captures = format!("captures data from {}", arg);
- let add_static_bound =
- "alternatively, add an explicit `'static` bound to this reference";
- let plus_lt = format!(" + {}", lifetime_name);
- for fn_return in fn_returns {
- if fn_return.span.desugaring_kind().is_some() {
- // Skip `async` desugaring `impl Future`.
- continue;
+ fn get_impl_ident_and_self_ty_from_trait(
+ &self,
+ def_id: DefId,
+ trait_objects: &[DefId],
+ ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
+ let tcx = self.tcx();
+ match tcx.hir().get_if_local(def_id) {
+ Some(Node::ImplItem(ImplItem { ident, hir_id, .. })) => {
+ match tcx.hir().find(tcx.hir().get_parent_item(*hir_id)) {
+ Some(Node::Item(Item { kind: ItemKind::Impl { self_ty, .. }, .. })) => {
+ Some((*ident, self_ty))
}
- match fn_return.kind {
- TyKind::OpaqueDef(item_id, _) => {
- let item = self.tcx().hir().item(item_id.id);
- let opaque = if let ItemKind::OpaqueTy(opaque) = &item.kind {
- opaque
- } else {
- err.emit();
- return Some(ErrorReported);
- };
-
- if let Some(span) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime {
- name: LifetimeName::Static,
- span,
+ _ => None,
+ }
+ }
+ Some(Node::TraitItem(TraitItem { ident, hir_id, .. })) => {
+ let parent_id = tcx.hir().get_parent_item(*hir_id);
+ match tcx.hir().find(parent_id) {
+ Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
+ // The method being called is defined in the `trait`, but the `'static`
+ // obligation comes from the `impl`. Find that `impl` so that we can point
+ // at it in the suggestion.
+ let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();
+ match tcx
+ .hir()
+ .trait_impls(trait_did)
+ .iter()
+ .filter_map(|impl_node| {
+ let impl_did = tcx.hir().local_def_id(*impl_node);
+ match tcx.hir().get_if_local(impl_did.to_def_id()) {
+ Some(Node::Item(Item {
+ kind: ItemKind::Impl { self_ty, .. },
..
- }) => Some(*span),
- _ => None,
- })
- .next()
- {
- err.span_suggestion_verbose(
- span,
- &format!("{} `impl Trait`'s {}", consider, explicit_static),
- lifetime_name.clone(),
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion_verbose(
- param_info.param_ty_span,
- add_static_bound,
- param_info.param_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- } else if let Some(_) = opaque
- .bounds
- .iter()
- .filter_map(|arg| match arg {
- GenericBound::Outlives(Lifetime { name, span, .. })
- if name.ident().to_string() == lifetime_name =>
+ })) if trait_objects.iter().all(|did| {
+ // FIXME: we should check `self_ty` against the receiver
+ // type in the `UnifyReceiver` context, but for now, use
+ // this imperfect proxy. This will fail if there are
+ // multiple `impl`s for the same trait like
+ // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+ // In that case, only the first one will get suggestions.
+ let mut hir_v = HirTraitObjectVisitor(vec![], *did);
+ hir_v.visit_ty(self_ty);
+ !hir_v.0.is_empty()
+ }) =>
{
- Some(*span)
+ Some(self_ty)
}
_ => None,
- })
- .next()
- {
- } else {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} `impl Trait` {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
- plus_lt.clone(),
- Applicability::MaybeIncorrect,
- );
- }
+ }
+ })
+ .next()
+ {
+ Some(self_ty) => Some((*ident, self_ty)),
+ _ => None,
}
- TyKind::TraitObject(_, lt) => match lt.name {
- LifetimeName::ImplicitObjectLifetimeDefault => {
- err.span_suggestion_verbose(
- fn_return.span.shrink_to_hi(),
- &format!(
- "{declare} trait object {captures}, {explicit}",
- declare = declare,
- captures = captures,
- explicit = explicit,
- ),
- plus_lt.clone(),
- Applicability::MaybeIncorrect,
- );
- }
- name if name.ident().to_string() != lifetime_name => {
- // With this check we avoid suggesting redundant bounds. This
- // would happen if there are nested impl/dyn traits and only
- // one of them has the bound we'd suggest already there, like
- // in `impl Foo<X = dyn Bar> + '_`.
- err.span_suggestion_verbose(
- lt.span,
- &format!("{} trait object's {}", consider, explicit_static),
- lifetime_name.clone(),
- Applicability::MaybeIncorrect,
- );
- err.span_suggestion_verbose(
- param_info.param_ty_span,
- add_static_bound,
- param_info.param_ty.to_string(),
- Applicability::MaybeIncorrect,
- );
- }
- _ => {}
- },
- _ => {}
+ }
+ _ => None,
+ }
+ }
+ _ => None,
+ }
+ }
+
+ /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
+ /// `'static` obligation. Suggest relaxing that implicit bound.
+ fn find_impl_on_dyn_trait(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ ty: Ty<'_>,
+ ctxt: &UnifyReceiverContext<'tcx>,
+ ) -> bool {
+ let tcx = self.tcx();
+
+ // Find the method being called.
+ let instance = match ty::Instance::resolve(
+ tcx,
+ ctxt.param_env,
+ ctxt.assoc_item.def_id,
+ self.infcx.resolve_vars_if_possible(&ctxt.substs),
+ ) {
+ Ok(Some(instance)) => instance,
+ _ => return false,
+ };
+
+ let mut v = TraitObjectVisitor(vec![]);
+ v.visit_ty(ty);
+
+ // Get the `Ident` of the method being called and the corresponding `impl` (to point at
+ // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
+ let (ident, self_ty) =
+ match self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0[..]) {
+ Some((ident, self_ty)) => (ident, self_ty),
+ None => return false,
+ };
+
+ // Find the trait object types in the argument, so we point at *only* the trait object.
+ self.suggest_constrain_dyn_trait_in_impl(err, &v.0[..], ident, self_ty)
+ }
+
+ fn suggest_constrain_dyn_trait_in_impl(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ found_dids: &[DefId],
+ ident: Ident,
+ self_ty: &hir::Ty<'_>,
+ ) -> bool {
+ let mut suggested = false;
+ for found_did in found_dids {
+ let mut hir_v = HirTraitObjectVisitor(vec![], *found_did);
+ hir_v.visit_ty(&self_ty);
+ for span in &hir_v.0 {
+ let mut multi_span: MultiSpan = vec![*span].into();
+ multi_span.push_span_label(
+ *span,
+ "this has an implicit `'static` lifetime requirement".to_string(),
+ );
+ multi_span.push_span_label(
+ ident.span,
+ "calling this method introduces the `impl`'s 'static` requirement".to_string(),
+ );
+ err.span_note(multi_span, "the used `impl` has a `'static` requirement");
+ err.span_suggestion_verbose(
+ span.shrink_to_hi(),
+ "consider relaxing the implicit `'static` requirement",
+ " + '_".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ suggested = true;
+ }
+ }
+ suggested
+ }
+}
+
+/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
+struct TraitObjectVisitor(Vec<DefId>);
+
+impl TypeVisitor<'_> for TraitObjectVisitor {
+ fn visit_ty(&mut self, t: Ty<'_>) -> bool {
+ match t.kind {
+ ty::Dynamic(preds, RegionKind::ReStatic) => {
+ if let Some(def_id) = preds.principal_def_id() {
+ self.0.push(def_id);
+ }
+ false
+ }
+ _ => t.super_visit_with(self),
+ }
+ }
+}
+
+/// Collect all `hir::Ty<'_>` `Span`s for trait objects with an implicit lifetime.
+struct HirTraitObjectVisitor(Vec<Span>, DefId);
+
+impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor {
+ type Map = ErasedMap<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
+ match t.kind {
+ TyKind::TraitObject(
+ poly_trait_refs,
+ Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. },
+ ) => {
+ for ptr in poly_trait_refs {
+ if Some(self.1) == ptr.trait_ref.trait_def_id() {
+ self.0.push(ptr.span);
}
}
- err.emit();
- return Some(ErrorReported);
}
+ _ => {}
}
- None
+ walk_ty(self, t);
}
}
use rustc_middle::ty::{self, DefIdTree, Region, Ty};
use rustc_span::Span;
-// The struct contains the information about the anonymous region
-// we are searching for.
+/// Information about the anonymous region we are searching for.
#[derive(Debug)]
pub(super) struct AnonymousParamInfo<'tcx> {
- // the parameter corresponding to the anonymous region
+ /// The parameter corresponding to the anonymous region.
pub param: &'tcx hir::Param<'tcx>,
- // the type corresponding to the anonymopus region parameter
+ /// The type corresponding to the anonymous region parameter.
pub param_ty: Ty<'tcx>,
- // the ty::BoundRegion corresponding to the anonymous region
+ /// The ty::BoundRegion corresponding to the anonymous region.
pub bound_region: ty::BoundRegion,
- // param_ty_span contains span of parameter type
+ /// The `Span` of the parameter type.
pub param_ty_span: Span,
- // corresponds to id the argument is the first parameter
- // in the declaration
+ /// Signals that the argument is the first parameter in the declaration.
pub is_first: bool,
}
AddrOfRegion(Span),
/// Regions created as part of an autoref of a method receiver
- Autoref(Span),
+ Autoref(Span, ty::AssocItem),
/// Regions created as part of an automatic coercion
Coercion(Span),
impl RegionVariableOrigin {
pub fn span(&self) -> Span {
match *self {
- MiscVariable(a) => a,
- PatternRegion(a) => a,
- AddrOfRegion(a) => a,
- Autoref(a) => a,
- Coercion(a) => a,
- EarlyBoundRegion(a, ..) => a,
- LateBoundRegion(a, ..) => a,
+ MiscVariable(a)
+ | PatternRegion(a)
+ | AddrOfRegion(a)
+ | Autoref(a, _)
+ | Coercion(a)
+ | EarlyBoundRegion(a, ..)
+ | LateBoundRegion(a, ..)
+ | UpvarRegion(_, a) => a,
BoundRegionInCoherence(_) => rustc_span::DUMMY_SP,
- UpvarRegion(_, a) => a,
NLL(..) => bug!("NLL variable used with `span`"),
}
}
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![feature(bindings_after_at)]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=RUSTC_INSTALL_BINDIR");
-}
// Make sure that changing a [TRACKED] option changes the hash.
// This list is in alphabetical order.
tracked!(code_model, Some(CodeModel::Large));
+ tracked!(control_flow_guard, CFGuard::Checks);
tracked!(debug_assertions, Some(true));
tracked!(debuginfo, 0xdeadbeef);
tracked!(embed_bitcode, false);
tracked!(binary_dep_depinfo, true);
tracked!(chalk, true);
tracked!(codegen_backend, Some("abc".to_string()));
- tracked!(control_flow_guard, CFGuard::Checks);
tracked!(crate_attr, vec!["abc".to_string()]);
tracked!(debug_macros, true);
tracked!(dep_info_omit_d_target, true);
authors = ["The Rust Project Developers"]
name = "rustc_llvm"
version = "0.0.0"
-build = "build.rs"
edition = "2018"
[lib]
emscripten = []
[dependencies]
-libc = "0.2"
+libc = "0.2.73"
[build-dependencies]
build_helper = { path = "../build_helper" }
-cc = "1.0.1"
+cc = "1.0.58"
use std::path::{Path, PathBuf};
use std::process::Command;
-use build_helper::output;
+use build_helper::{output, tracked_env_var_os};
fn detect_llvm_link() -> (&'static str, &'static str) {
// Force the link mode we want, preferring static by default, but
// possibly overridden by `configure --enable-llvm-link-shared`.
- if env::var_os("LLVM_LINK_SHARED").is_some() {
+ if tracked_env_var_os("LLVM_LINK_SHARED").is_some() {
("dylib", "--link-shared")
} else {
("static", "--link-static")
}
fn main() {
- println!("cargo:rerun-if-env-changed=RUST_CHECK");
- if env::var_os("RUST_CHECK").is_some() {
+ if tracked_env_var_os("RUST_CHECK").is_some() {
// If we're just running `check`, there's no need for LLVM to be built.
return;
}
let target = env::var("TARGET").expect("TARGET was not set");
let llvm_config =
- env::var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
- if let Some(dir) = env::var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
+ tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| {
+ if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) {
let to_test = dir
.parent()
.unwrap()
}
let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config"));
- println!("cargo:rerun-if-env-changed=LLVM_CONFIG");
-
// Test whether we're cross-compiling LLVM. This is a pretty rare case
// currently where we're producing an LLVM for a different platform than
// what this build script is currently running on.
cfg.define(&flag, None);
}
- println!("cargo:rerun-if-changed-env=LLVM_RUSTLLVM");
- if env::var_os("LLVM_RUSTLLVM").is_some() {
+ if tracked_env_var_os("LLVM_RUSTLLVM").is_some() {
cfg.define("LLVM_RUSTLLVM", None);
}
- if env::var_os("LLVM_NDEBUG").is_some() {
+ if tracked_env_var_os("LLVM_NDEBUG").is_some() {
cfg.define("NDEBUG", None);
cfg.debug(false);
}
// librustc_llvm, for example when using static libc++, we may need to
// manually specify the library search path and -ldl -lpthread as link
// dependencies.
- let llvm_linker_flags = env::var_os("LLVM_LINKER_FLAGS");
+ let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS");
if let Some(s) = llvm_linker_flags {
for lib in s.into_string().unwrap().split_whitespace() {
if lib.starts_with("-l") {
}
}
- let llvm_static_stdcpp = env::var_os("LLVM_STATIC_STDCPP");
- let llvm_use_libcxx = env::var_os("LLVM_USE_LIBCXX");
+ let llvm_static_stdcpp = tracked_env_var_os("LLVM_STATIC_STDCPP");
+ let llvm_use_libcxx = tracked_env_var_os("LLVM_USE_LIBCXX");
let stdcppname = if target.contains("openbsd") {
if target.contains("sparc64") { "estdc++" } else { "c++" }
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_VERSION");
- println!("cargo:rerun-if-env-changed=CFG_VIRTUAL_RUST_SOURCE_BASE_DIR");
-}
let private_dep =
self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false);
- info!("register crate `{}` (private_dep = {})", crate_root.name(), private_dep);
-
// Claim this crate number and cache it
let cnum = self.cstore.alloc_new_crate_num();
+ info!(
+ "register crate `{}` (cnum = {}. private_dep = {})",
+ crate_root.name(),
+ cnum,
+ private_dep
+ );
+
// Maintain a reference to the top most crate.
// Stash paths for top-most crate locally if necessary.
let crate_paths;
None
};
- self.cstore.set_crate_data(
+ let crate_metadata = CrateMetadata::new(
+ self.sess,
+ metadata,
+ crate_root,
+ raw_proc_macros,
cnum,
- CrateMetadata::new(
- self.sess,
- metadata,
- crate_root,
- raw_proc_macros,
- cnum,
- cnum_map,
- dep_kind,
- source,
- private_dep,
- host_hash,
- ),
+ cnum_map,
+ dep_kind,
+ source,
+ private_dep,
+ host_hash,
);
+ self.cstore.set_crate_data(cnum, crate_metadata);
+
Ok(cnum)
}
let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((root, &dep)))?;
crate_num_map.push(cnum);
}
+
+ debug!("resolve_crate_deps: cnum_map for {:?} is {:?}", krate, crate_num_map);
Ok(crate_num_map)
}
#![feature(proc_macro_internals)]
#![feature(min_specialization)]
#![feature(stmt_expr_attributes)]
+#![feature(never_type)]
#![recursion_limit = "256"]
extern crate proc_macro;
use rustc_middle::util::common::record_time;
use rustc_serialize::{opaque, Decodable, Decoder, SpecializedDecoder, UseSpecializedDecodable};
use rustc_session::Session;
+use rustc_span::hygiene::ExpnDataDecodeMode;
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{self, hygiene::MacroKind, BytePos, Pos, Span, DUMMY_SP};
+use rustc_span::{self, hygiene::MacroKind, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP};
use log::debug;
use proc_macro::bridge::client::ProcMacro;
+use std::cell::Cell;
use std::io;
use std::mem;
use std::num::NonZeroUsize;
use std::path::Path;
pub use cstore_impl::{provide, provide_extern};
+use rustc_span::hygiene::HygieneDecodeContext;
mod cstore_impl;
/// The hash for the host proc macro. Used to support `-Z dual-proc-macro`.
host_hash: Option<Svh>,
+ /// Additional data used for decoding `HygieneData` (e.g. `SyntaxContext`
+ /// and `ExpnId`).
+ /// Note that we store a `HygieneDecodeContext` for each `CrateMetadat`. This is
+ /// because `SyntaxContext` ids are not globally unique, so we need
+ /// to track which ids we've decoded on a per-crate basis.
+ hygiene_context: HygieneDecodeContext,
+
// --- Data used only for improving diagnostics ---
/// Information about the `extern crate` item or path that caused this crate to be loaded.
/// If this is `None`, then the crate was injected (e.g., by the allocator).
let lo = BytePos::decode(self)?;
let len = BytePos::decode(self)?;
+ let ctxt = SyntaxContext::decode(self)?;
let hi = lo + len;
let sess = if let Some(sess) = self.sess {
let hi =
(hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos;
- Ok(Span::with_root_ctxt(lo, hi))
+ Ok(Span::new(lo, hi, ctxt))
}
}
!self.is_proc_macro(id) && self.root.tables.mir.get(self, id).is_some()
}
+ fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
+ if let EntryKind::Mod(m) = self.kind(id) {
+ m.decode((self, sess)).expansion
+ } else {
+ panic!("Expected module, found {:?}", self.local_def_id(id))
+ }
+ }
+
fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
self.root
.tables
.decode((self, tcx))
}
+ fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u64> {
+ self.root
+ .tables
+ .unused_generic_params
+ .get(self, id)
+ .filter(|_| !self.is_proc_macro(id))
+ .map(|params| params.decode(self))
+ .unwrap_or_default()
+ }
+
fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
self.root
.tables
private_dep,
host_hash,
extern_crate: Lock::new(None),
+ hygiene_context: Default::default(),
}
}
ProcMacro::Bang { .. } => MacroKind::Bang,
}
}
+
+impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for DecodeContext<'a, 'tcx> {
+ fn specialized_decode(&mut self) -> Result<SyntaxContext, Self::Error> {
+ let cdata = self.cdata();
+ let sess = self.sess.unwrap();
+ let cname = cdata.root.name;
+ rustc_span::hygiene::decode_syntax_context(self, &cdata.hygiene_context, |_, id| {
+ debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
+ Ok(cdata
+ .root
+ .syntax_contexts
+ .get(&cdata, id)
+ .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
+ .decode((&cdata, sess)))
+ })
+ }
+}
+
+impl<'a, 'tcx> SpecializedDecoder<ExpnId> for DecodeContext<'a, 'tcx> {
+ fn specialized_decode(&mut self) -> Result<ExpnId, Self::Error> {
+ let local_cdata = self.cdata();
+ let sess = self.sess.unwrap();
+ let expn_cnum = Cell::new(None);
+ let get_ctxt = |cnum| {
+ expn_cnum.set(Some(cnum));
+ if cnum == LOCAL_CRATE {
+ &local_cdata.hygiene_context
+ } else {
+ &local_cdata.cstore.get_crate_data(cnum).cdata.hygiene_context
+ }
+ };
+
+ rustc_span::hygiene::decode_expn_id(
+ self,
+ ExpnDataDecodeMode::Metadata(get_ctxt),
+ |_this, index| {
+ let cnum = expn_cnum.get().unwrap();
+ // Lookup local `ExpnData`s in our own crate data. Foreign `ExpnData`s
+ // are stored in the owning crate, to avoid duplication.
+ let crate_data = if cnum == LOCAL_CRATE {
+ local_cdata
+ } else {
+ local_cdata.cstore.get_crate_data(cnum)
+ };
+ Ok(crate_data
+ .root
+ .expn_data
+ .get(&crate_data, index)
+ .unwrap()
+ .decode((&crate_data, sess)))
+ },
+ )
+ }
+}
use rustc_session::utils::NativeLibKind;
use rustc_session::{CrateDisambiguator, Session};
use rustc_span::source_map::{self, Span, Spanned};
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Symbol;
use rustc_data_structures::sync::Lrc;
+use rustc_span::ExpnId;
use smallvec::SmallVec;
use std::any::Any;
}
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
+ unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
attr::mark_used(attr);
}
- let ident = data
- .def_key(id.index)
- .disambiguated_data
- .data
- .get_opt_name()
- .map(Ident::with_dummy_span) // FIXME: cross-crate hygiene
- .expect("no name in load_macro");
+ let ident = data.item_ident(id.index, sess);
LoadedMacro::MacroDef(
ast::Item {
pub fn item_generics_num_lifetimes(&self, def_id: DefId, sess: &Session) -> usize {
self.get_crate_data(def_id.krate).get_generics(def_id.index, sess).own_counts().lifetimes
}
+
+ pub fn module_expansion_untracked(&self, def_id: DefId, sess: &Session) -> ExpnId {
+ self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess)
+ }
}
impl CrateStore for CStore {
-use crate::rmeta::table::FixedSizeEncoding;
+use crate::rmeta::table::{FixedSizeEncoding, TableBuilder};
use crate::rmeta::*;
use log::{debug, trace};
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_serialize::{opaque, Encodable, Encoder, SpecializedEncoder, UseSpecializedEncodable};
use rustc_session::config::CrateType;
+use rustc_span::hygiene::{ExpnDataEncodeMode, HygieneEncodeContext};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{self, ExternalSource, FileName, SourceFile, Span};
+use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
use rustc_target::abi::VariantIdx;
use std::hash::Hash;
use std::num::NonZeroUsize;
use std::path::Path;
-struct EncodeContext<'tcx> {
+struct EncodeContext<'a, 'tcx> {
opaque: opaque::Encoder,
tcx: TyCtxt<'tcx>,
// with a result containing a foreign `Span`.
required_source_files: Option<GrowableBitSet<usize>>,
is_proc_macro: bool,
+ hygiene_ctxt: &'a HygieneEncodeContext,
}
macro_rules! encoder_methods {
}
}
-impl<'tcx> Encoder for EncodeContext<'tcx> {
+impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
type Error = <opaque::Encoder as Encoder>::Error;
#[inline]
}
}
-impl<'tcx, T> SpecializedEncoder<Lazy<T, ()>> for EncodeContext<'tcx> {
+impl<'a, 'tcx, T> SpecializedEncoder<Lazy<T, ()>> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, lazy: &Lazy<T>) -> Result<(), Self::Error> {
self.emit_lazy_distance(*lazy)
}
}
-impl<'tcx, T> SpecializedEncoder<Lazy<[T], usize>> for EncodeContext<'tcx> {
+impl<'a, 'tcx, T> SpecializedEncoder<Lazy<[T], usize>> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, lazy: &Lazy<[T]>) -> Result<(), Self::Error> {
self.emit_usize(lazy.meta)?;
if lazy.meta == 0 {
}
}
-impl<'tcx, I: Idx, T> SpecializedEncoder<Lazy<Table<I, T>, usize>> for EncodeContext<'tcx>
+impl<'a, 'tcx, I: Idx, T> SpecializedEncoder<Lazy<Table<I, T>, usize>> for EncodeContext<'a, 'tcx>
where
Option<T>: FixedSizeEncoding,
{
}
}
-impl<'tcx> SpecializedEncoder<CrateNum> for EncodeContext<'tcx> {
+impl<'a, 'tcx> SpecializedEncoder<CrateNum> for EncodeContext<'a, 'tcx> {
#[inline]
fn specialized_encode(&mut self, cnum: &CrateNum) -> Result<(), Self::Error> {
self.emit_u32(cnum.as_u32())
}
}
-impl<'tcx> SpecializedEncoder<DefId> for EncodeContext<'tcx> {
+impl<'a, 'tcx> SpecializedEncoder<DefId> for EncodeContext<'a, 'tcx> {
#[inline]
fn specialized_encode(&mut self, def_id: &DefId) -> Result<(), Self::Error> {
let DefId { krate, index } = *def_id;
}
}
-impl<'tcx> SpecializedEncoder<DefIndex> for EncodeContext<'tcx> {
+impl<'a, 'tcx> SpecializedEncoder<SyntaxContext> for EncodeContext<'a, 'tcx> {
+ fn specialized_encode(&mut self, ctxt: &SyntaxContext) -> Result<(), Self::Error> {
+ rustc_span::hygiene::raw_encode_syntax_context(*ctxt, &self.hygiene_ctxt, self)
+ }
+}
+
+impl<'a, 'tcx> SpecializedEncoder<ExpnId> for EncodeContext<'a, 'tcx> {
+ fn specialized_encode(&mut self, expn: &ExpnId) -> Result<(), Self::Error> {
+ rustc_span::hygiene::raw_encode_expn_id(
+ *expn,
+ &mut self.hygiene_ctxt,
+ ExpnDataEncodeMode::Metadata,
+ self,
+ )
+ }
+}
+
+impl<'a, 'tcx> SpecializedEncoder<DefIndex> for EncodeContext<'a, 'tcx> {
#[inline]
fn specialized_encode(&mut self, def_index: &DefIndex) -> Result<(), Self::Error> {
self.emit_u32(def_index.as_u32())
}
}
-impl<'tcx> SpecializedEncoder<Span> for EncodeContext<'tcx> {
+impl<'a, 'tcx> SpecializedEncoder<Span> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, span: &Span) -> Result<(), Self::Error> {
if span.is_dummy() {
return TAG_INVALID_SPAN.encode(self);
let len = hi - lo;
len.encode(self)?;
+ // Don't serialize any `SyntaxContext`s from a proc-macro crate,
+ // since we don't load proc-macro dependencies during serialization.
+ // This means that any hygiene information from macros used *within*
+ // a proc-macro crate (e.g. invoking a macro that expands to a proc-macro
+ // definition) will be lost.
+ //
+ // This can show up in two ways:
+ //
+ // 1. Any hygiene information associated with identifier of
+ // a proc macro (e.g. `#[proc_macro] pub fn $name`) will be lost.
+ // Since proc-macros can only be invoked from a different crate,
+ // real code should never need to care about this.
+ //
+ // 2. Using `Span::def_site` or `Span::mixed_site` will not
+ // include any hygiene information associated with the defintion
+ // site. This means that a proc-macro cannot emit a `$crate`
+ // identifier which resolves to one of its dependencies,
+ // which also should never come up in practice.
+ //
+ // Additionally, this affects `Span::parent`, and any other
+ // span inspection APIs that would otherwise allow traversing
+ // the `SyntaxContexts` associated with a span.
+ //
+ // None of these user-visible effects should result in any
+ // cross-crate inconsistencies (getting one behavior in the same
+ // crate, and a different behavior in another crate) due to the
+ // limited surface that proc-macros can expose.
+ if self.is_proc_macro {
+ SyntaxContext::root().encode(self)?;
+ } else {
+ span.ctxt.encode(self)?;
+ }
+
if tag == TAG_VALID_SPAN_FOREIGN {
// This needs to be two lines to avoid holding the `self.source_file_cache`
// while calling `cnum.encode(self)`
let cnum = self.source_file_cache.0.cnum;
cnum.encode(self)?;
}
- Ok(())
- // Don't encode the expansion context.
+ Ok(())
}
}
-impl<'tcx> SpecializedEncoder<LocalDefId> for EncodeContext<'tcx> {
+impl<'a, 'tcx> SpecializedEncoder<LocalDefId> for EncodeContext<'a, 'tcx> {
#[inline]
fn specialized_encode(&mut self, def_id: &LocalDefId) -> Result<(), Self::Error> {
self.specialized_encode(&def_id.to_def_id())
}
}
-impl<'a, 'b, 'tcx> SpecializedEncoder<&'a ty::TyS<'b>> for EncodeContext<'tcx>
+impl<'a, 'b, 'c, 'tcx> SpecializedEncoder<&'a ty::TyS<'b>> for EncodeContext<'c, 'tcx>
where
&'a ty::TyS<'b>: UseSpecializedEncodable,
{
}
}
-impl<'b, 'tcx> SpecializedEncoder<ty::Predicate<'b>> for EncodeContext<'tcx> {
+impl<'a, 'b, 'tcx> SpecializedEncoder<ty::Predicate<'b>> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, predicate: &ty::Predicate<'b>) -> Result<(), Self::Error> {
debug_assert!(self.tcx.lift(predicate).is_some());
let predicate =
}
}
-impl<'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'tcx> {
+impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
use std::collections::hash_map::Entry;
let index = match self.interpret_allocs.entry(*alloc_id) {
}
}
-impl<'tcx> SpecializedEncoder<Fingerprint> for EncodeContext<'tcx> {
+impl<'a, 'tcx> SpecializedEncoder<Fingerprint> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> {
f.encode_opaque(&mut self.opaque)
}
}
-impl<'tcx, T> SpecializedEncoder<mir::ClearCrossCrate<T>> for EncodeContext<'tcx>
+impl<'a, 'tcx, T> SpecializedEncoder<mir::ClearCrossCrate<T>> for EncodeContext<'a, 'tcx>
where
mir::ClearCrossCrate<T>: UseSpecializedEncodable,
{
}
}
-impl<'tcx> TyEncoder for EncodeContext<'tcx> {
+impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
fn position(&self) -> usize {
self.opaque.position()
}
/// Helper trait to allow overloading `EncodeContext::lazy` for iterators.
trait EncodeContentsForLazy<T: ?Sized + LazyMeta> {
- fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) -> T::Meta;
+ fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> T::Meta;
}
impl<T: Encodable> EncodeContentsForLazy<T> for &T {
- fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) {
+ fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
self.encode(ecx).unwrap()
}
}
impl<T: Encodable> EncodeContentsForLazy<T> for T {
- fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) {
+ fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) {
self.encode(ecx).unwrap()
}
}
I: IntoIterator,
I::Item: EncodeContentsForLazy<T>,
{
- fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'tcx>) -> usize {
+ fn encode_contents_for_lazy(self, ecx: &mut EncodeContext<'a, 'tcx>) -> usize {
self.into_iter().map(|value| value.encode_contents_for_lazy(ecx)).count()
}
}
}};
}
-impl<'tcx> EncodeContext<'tcx> {
+impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn emit_lazy_distance<T: ?Sized + LazyMeta>(
&mut self,
lazy: Lazy<T>,
let mut i = self.position();
+ // Encode the crate deps
let crate_deps = self.encode_crate_deps();
let dylib_dependency_formats = self.encode_dylib_dependency_formats();
let dep_bytes = self.position() - i;
let proc_macro_data_bytes = self.position() - i;
// Encode exported symbols info. This is prefetched in `encode_metadata` so we encode
- // this late to give the prefetching as much time as possible to complete.
+ // this as late as possible to give the prefetching as much time as possible to complete.
i = self.position();
let exported_symbols = tcx.exported_symbols(LOCAL_CRATE);
let exported_symbols = self.encode_exported_symbols(&exported_symbols);
let exported_symbols_bytes = self.position() - i;
+ // Encode the hygiene data,
+ // IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The process
+ // of encoding other items (e.g. `optimized_mir`) may cause us to load
+ // data from the incremental cache. If this causes us to deserialize a `Span`,
+ // then we may load additional `SyntaxContext`s into the global `HygieneData`.
+ // Therefore, we need to encode the hygiene data last to ensure that we encode
+ // any `SyntaxContext`s that might be used.
+ i = self.position();
+ let (syntax_contexts, expn_data) = self.encode_hygiene();
+ let hygiene_bytes = self.position() - i;
+
// Encode source_map. This needs to be done last,
// since encoding `Span`s tells us which `SourceFiles` we actually
// need to encode.
exported_symbols,
interpret_alloc_index,
tables,
+ syntax_contexts,
+ expn_data,
});
let total_bytes = self.position();
println!(" proc-macro-data-bytes: {}", proc_macro_data_bytes);
println!(" item bytes: {}", item_bytes);
println!(" table bytes: {}", tables_bytes);
+ println!(" hygiene bytes: {}", hygiene_bytes);
println!(" zero bytes: {}", zero_bytes);
println!(" total bytes: {}", total_bytes);
}
}
}
-impl EncodeContext<'tcx> {
+impl EncodeContext<'a, 'tcx> {
fn encode_variances_of(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_variances_of({:?})", def_id);
record!(self.tables.variances[def_id] <- &self.tcx.variances_of(def_id)[..]);
vis: &hir::Visibility<'_>,
) {
let tcx = self.tcx;
- let def_id = tcx.hir().local_def_id(id);
+ let local_def_id = tcx.hir().local_def_id(id);
+ let def_id = local_def_id.to_def_id();
debug!("EncodeContext::encode_info_for_mod({:?})", def_id);
let data = ModData {
- reexports: match tcx.module_exports(def_id) {
+ reexports: match tcx.module_exports(local_def_id) {
Some(exports) => {
let hir_map = self.tcx.hir();
self.lazy(
}
_ => Lazy::empty(),
},
+ expansion: tcx.hir().definitions().expansion_that_defined(local_def_id),
};
- let def_id = def_id.to_def_id();
-
record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx));
record!(self.tables.span[def_id] <- self.tcx.def_span(def_id));
debug!("EntryBuilder::encode_mir({:?})", def_id);
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
+ record!(self.tables.unused_generic_params[def_id.to_def_id()] <-
+ self.tcx.unused_generic_params(def_id));
}
}
self.lazy(foreign_modules.iter().cloned())
}
+ fn encode_hygiene(&mut self) -> (SyntaxContextTable, ExpnDataTable) {
+ let mut syntax_contexts: TableBuilder<_, _> = Default::default();
+ let mut expn_data_table: TableBuilder<_, _> = Default::default();
+
+ let _: Result<(), !> = self.hygiene_ctxt.encode(
+ &mut (&mut *self, &mut syntax_contexts, &mut expn_data_table),
+ |(this, syntax_contexts, _), index, ctxt_data| {
+ syntax_contexts.set(index, this.lazy(ctxt_data));
+ Ok(())
+ },
+ |(this, _, expn_data_table), index, expn_data| {
+ expn_data_table.set(index, this.lazy(expn_data));
+ Ok(())
+ },
+ );
+
+ (syntax_contexts.encode(&mut self.opaque), expn_data_table.encode(&mut self.opaque))
+ }
+
fn encode_proc_macros(&mut self) -> Option<Lazy<[DefIndex]>> {
let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro);
if is_proc_macro {
}
// FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
-impl Visitor<'tcx> for EncodeContext<'tcx> {
+impl Visitor<'tcx> for EncodeContext<'a, 'tcx> {
type Map = Map<'tcx>;
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
}
}
-impl EncodeContext<'tcx> {
+impl EncodeContext<'a, 'tcx> {
fn encode_fields(&mut self, adt_def: &ty::AdtDef) {
for (variant_index, variant) in adt_def.variants.iter_enumerated() {
for (field_index, _field) in variant.fields.iter().enumerate() {
encoder.emit_raw_bytes(&[0, 0, 0, 0]);
let source_map_files = tcx.sess.source_map().files();
+ let hygiene_ctxt = HygieneEncodeContext::default();
let mut ecx = EncodeContext {
opaque: encoder,
interpret_allocs_inverse: Default::default(),
required_source_files: Some(GrowableBitSet::with_capacity(source_map_files.len())),
is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro),
+ hygiene_ctxt: &hygiene_ctxt,
};
drop(source_map_files);
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, DefIndex};
use rustc_hir::lang_items;
-use rustc_index::vec::IndexVec;
+use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_middle::hir::exports::Export;
use rustc_middle::middle::cstore::{DepKind, ForeignModule, LinkagePreference, NativeLib};
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
use rustc_session::CrateDisambiguator;
use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::{self, Span};
+use rustc_span::{self, ExpnData, ExpnId, Span};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use std::marker::PhantomData;
pub use decoder::{provide, provide_extern};
crate use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
+use rustc_span::hygiene::SyntaxContextData;
mod decoder;
mod encoder;
($T:ty) => {Lazy<$T, ()>};
}
+type SyntaxContextTable = Lazy<Table<u32, Lazy<SyntaxContextData>>>;
+type ExpnDataTable = Lazy<Table<u32, Lazy<ExpnData>>>;
+
#[derive(RustcEncodable, RustcDecodable)]
crate struct CrateRoot<'tcx> {
name: Symbol,
proc_macro_data: Option<Lazy<[DefIndex]>>,
exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]),
+
+ syntax_contexts: SyntaxContextTable,
+ expn_data: ExpnDataTable,
+
source_map: Lazy<[rustc_span::SourceFile]>,
compiler_builtins: bool,
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
+ unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u64>>>,
}
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
#[derive(RustcEncodable, RustcDecodable)]
struct ModData {
reexports: Lazy<[Export<hir::HirId>]>,
+ expansion: ExpnId,
}
#[derive(RustcEncodable, RustcDecodable)]
where
Option<T>: FixedSizeEncoding,
{
- pub(super) fn set(&mut self, i: I, value: T) {
+ pub(crate) fn set(&mut self, i: I, value: T) {
// FIXME(eddyb) investigate more compact encodings for sparse tables.
// On the PR @michaelwoerister mentioned:
// > Space requirements could perhaps be optimized by using the HAMT `popcnt`
Some(value).write_to_bytes_at(&mut self.bytes, i);
}
- pub(super) fn encode(&self, buf: &mut Encoder) -> Lazy<Table<I, T>> {
+ pub(crate) fn encode(&self, buf: &mut Encoder) -> Lazy<Table<I, T>> {
let pos = buf.position();
buf.emit_raw_bytes(&self.bytes);
Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), self.bytes.len())
+++ /dev/null
-use std::env;
-
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_LIBDIR_RELATIVE");
- println!("cargo:rerun-if-env-changed=CFG_COMPILER_HOST_TRIPLE");
- println!("cargo:rerun-if-env-changed=RUSTC_VERIFY_LLVM_IR");
-
- if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() {
- println!("cargo:rustc-cfg=always_verify_llvm_ir");
- }
-}
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, CachingSourceMapView, SourceFile};
+use rustc_span::def_id::{CrateNum, CRATE_DEF_INDEX};
use smallvec::SmallVec;
use std::cmp::Ord;
self.hash_spans
}
+ #[inline]
+ fn hash_crate_num(&mut self, cnum: CrateNum, hasher: &mut StableHasher) {
+ let hcx = self;
+ hcx.def_path_hash(DefId { krate: cnum, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher);
+ }
+
#[inline]
fn hash_def_id(&mut self, def_id: DefId, hasher: &mut StableHasher) {
let hcx = self;
}
}
-impl<'a> HashStable<StableHashingContext<'a>> for CrateNum {
- #[inline]
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- hcx.def_path_hash(DefId { krate: *self, index: CRATE_DEF_INDEX }).hash_stable(hcx, hasher);
- }
-}
-
impl<'a> ToStableHashKey<StableHashingContext<'a>> for CrateNum {
type KeyType = DefPathHash;
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![feature(cmp_min_max_by)]
#![feature(const_fn)]
#![feature(const_panic)]
#![feature(const_fn_transmute)]
// Dummy span for the `def_site` means it's an external macro.
expn_data.def_site.is_dummy() || sess.source_map().is_imported(expn_data.def_site)
}
- ExpnKind::Macro(..) => true, // definitely a plugin
+ ExpnKind::Macro { .. } => true, // definitely a plugin
}
}
use crate::ty::{self, TyCtxt};
use rustc_ast::ast::CRATE_NODE_ID;
-use rustc_attr::{self as attr, ConstStability, Deprecation, RustcDeprecation, Stability};
+use rustc_attr::{self as attr, ConstStability, Deprecation, Stability};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_feature::GateIssue;
/// Checks whether an item marked with `deprecated(since="X")` is currently
/// deprecated (i.e., whether X is not greater than the current rustc version).
-pub fn deprecation_in_effect(since: &str) -> bool {
+pub fn deprecation_in_effect(is_since_rustc_version: bool, since: Option<&str>) -> bool {
+ let since = if let Some(since) = since {
+ if is_since_rustc_version {
+ since
+ } else {
+ // We assume that the deprecation is in effect if it's not a
+ // rustc version.
+ return true;
+ }
+ } else {
+ // If since attribute is not set, then we're definitely in effect.
+ return true;
+ };
fn parse_version(ver: &str) -> Vec<u32> {
// We ignore non-integer components of the version (e.g., "nightly").
ver.split(|c| c == '.' || c == '-').flat_map(|s| s.parse()).collect()
}
if let Some(rustc) = option_env!("CFG_RELEASE") {
- let since: Vec<u32> = parse_version(since);
+ let since: Vec<u32> = parse_version(&since);
let rustc: Vec<u32> = parse_version(rustc);
// We simply treat invalid `since` attributes as relating to a previous
// Rust version, thus always displaying the warning.
}
}
-fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
- match reason {
- Some(reason) => format!("{}: {}", message, reason),
- None => message,
- }
-}
-
pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
- let message = format!("use of deprecated item '{}'", path);
- (deprecation_message_common(message, depr.note), DEPRECATED)
-}
-
-pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
- let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
+ let (message, lint) = if deprecation_in_effect(
+ depr.is_since_rustc_version,
+ depr.since.map(Symbol::as_str).as_deref(),
+ ) {
(format!("use of deprecated item '{}'", path), DEPRECATED)
} else {
(
format!(
"use of item '{}' that will be deprecated in future version {}",
- path, depr.since
+ path,
+ depr.since.unwrap()
),
DEPRECATED_IN_FUTURE,
)
};
- (deprecation_message_common(message, Some(depr.reason)), lint)
+ let message = match depr.note {
+ Some(reason) => format!("{}: {}", message, reason),
+ None => message,
+ };
+ (message, lint)
}
pub fn early_report_deprecation(
.lookup_deprecation_entry(parent_def_id.to_def_id())
.map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
- if !skip {
+ // #[deprecated] doesn't emit a notice if we're not on the
+ // topmost deprecation. For example, if a struct is deprecated,
+ // the use of a field won't be linted.
+ //
+ // #[rustc_deprecated] however wants to emit down the whole
+ // hierarchy.
+ if !skip || depr_entry.attr.is_since_rustc_version {
let (message, lint) =
deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
- late_report_deprecation(self, &message, None, lint, span, id);
+ late_report_deprecation(
+ self,
+ &message,
+ depr_entry.attr.suggestion,
+ lint,
+ span,
+ id,
+ );
}
};
}
def_id, span, stability
);
- if let Some(id) = id {
- if let Some(stability) = stability {
- if let Some(depr) = &stability.rustc_depr {
- let (message, lint) =
- rustc_deprecation_message(depr, &self.def_path_str(def_id));
- late_report_deprecation(self, &message, depr.suggestion, lint, span, id);
- }
- }
- }
-
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !def_id.is_local();
if !cross_crate {
Allocation::from_bytes(slice, Align::from_bytes(1).unwrap())
}
- pub fn undef(size: Size, align: Align) -> Self {
+ pub fn uninit(size: Size, align: Align) -> Self {
Allocation {
bytes: vec![0; size.bytes_usize()],
relocations: Relocations::new(),
self.size.bytes_usize()
}
- /// Looks at a slice which may describe undefined bytes or describe a relocation. This differs
+ /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs
/// from `get_bytes_with_undef_and_ptr` in that it does no relocation checks (even on the
/// edges) at all. It further ignores `AllocationExtra` callbacks.
/// This must not be used for reads affecting the interpreter execution.
offset.bytes_usize()..end
}
- /// The last argument controls whether we error out when there are undefined
+ /// The last argument controls whether we error out when there are uninitialized
/// or pointer bytes. You should never call this, call `get_bytes` or
/// `get_bytes_with_undef_and_ptr` instead,
///
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
size: Size,
- check_defined_and_ptr: bool,
+ check_init_and_ptr: bool,
) -> InterpResult<'tcx, &[u8]> {
let range = self.check_bounds(ptr.offset, size);
- if check_defined_and_ptr {
- self.check_defined(ptr, size)?;
+ if check_init_and_ptr {
+ self.check_init(ptr, size)?;
self.check_relocations(cx, ptr, size)?;
} else {
// We still don't want relocations on the *edges*.
self.get_bytes_internal(cx, ptr, size, true)
}
- /// It is the caller's responsibility to handle undefined and pointer bytes.
+ /// It is the caller's responsibility to handle uninitialized and pointer bytes.
/// However, this still checks that there are no relocations on the *edges*.
///
/// It is the caller's responsibility to check bounds and alignment beforehand.
) -> InterpResult<'tcx, &mut [u8]> {
let range = self.check_bounds(ptr.offset, size);
- self.mark_definedness(ptr, size, true);
+ self.mark_init(ptr, size, true);
self.clear_relocations(cx, ptr, size)?;
AllocationExtra::memory_written(self, ptr, size)?;
/// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a
/// relocation. If `allow_ptr_and_undef` is `false`, also enforces that the memory in the
- /// given range contains neither relocations nor undef bytes.
+ /// given range contains neither relocations nor uninitialized bytes.
pub fn check_bytes(
&self,
cx: &impl HasDataLayout,
) -> InterpResult<'tcx> {
// Check bounds and relocations on the edges.
self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
- // Check undef and ptr.
+ // Check uninit and ptr.
if !allow_ptr_and_undef {
- self.check_defined(ptr, size)?;
+ self.check_init(ptr, size)?;
self.check_relocations(cx, ptr, size)?;
}
Ok(())
let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
// Uninit check happens *after* we established that the alignment is correct.
// We must not return `Ok()` for unaligned pointers!
- if self.is_defined(ptr, size).is_err() {
+ if self.is_init(ptr, size).is_err() {
// This inflates uninitialized bytes to the entire scalar, even if only a few
// bytes are uninitialized.
return Ok(ScalarMaybeUninit::Uninit);
let val = match val {
ScalarMaybeUninit::Scalar(scalar) => scalar,
ScalarMaybeUninit::Uninit => {
- self.mark_definedness(ptr, type_size, false);
+ self.mark_init(ptr, type_size, false);
return Ok(());
}
};
let start = ptr.offset;
let end = start + size; // `Size` addition
- // Mark parts of the outermost relocations as undefined if they partially fall outside the
+ // Mark parts of the outermost relocations as uninitialized if they partially fall outside the
// given range.
if first < start {
self.init_mask.set_range(first, start, false);
}
}
-/// Undefined bytes.
+/// Uninitialized bytes.
impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
- /// Checks whether the given range is entirely defined.
+ /// Checks whether the given range is entirely initialized.
///
- /// Returns `Ok(())` if it's defined. Otherwise returns the range of byte
- /// indexes of the first contiguous undefined access.
- fn is_defined(&self, ptr: Pointer<Tag>, size: Size) -> Result<(), Range<Size>> {
+ /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte
+ /// indexes of the first contiguous uninitialized access.
+ fn is_init(&self, ptr: Pointer<Tag>, size: Size) -> Result<(), Range<Size>> {
self.init_mask.is_range_initialized(ptr.offset, ptr.offset + size) // `Size` addition
}
- /// Checks that a range of bytes is defined. If not, returns the `InvalidUndefBytes`
- /// error which will report the first range of bytes which is undefined.
- fn check_defined(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> {
- self.is_defined(ptr, size).or_else(|idx_range| {
+ /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes`
+ /// error which will report the first range of bytes which is uninitialized.
+ fn check_init(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> {
+ self.is_init(ptr, size).or_else(|idx_range| {
throw_ub!(InvalidUninitBytes(Some(Box::new(UninitBytesAccess {
access_ptr: ptr.erase_tag(),
access_size: size,
})
}
- pub fn mark_definedness(&mut self, ptr: Pointer<Tag>, size: Size, new_state: bool) {
+ pub fn mark_init(&mut self, ptr: Pointer<Tag>, size: Size, is_init: bool) {
if size.bytes() == 0 {
return;
}
- self.init_mask.set_range(ptr.offset, ptr.offset + size, new_state);
+ self.init_mask.set_range(ptr.offset, ptr.offset + size, is_init);
}
}
-/// Run-length encoding of the undef mask.
+/// Run-length encoding of the uninit mask.
/// Used to copy parts of a mask multiple times to another allocation.
-pub struct AllocationDefinedness {
- /// The definedness of the first range.
+pub struct InitMaskCompressed {
+ /// Whether the first range is initialized.
initial: bool,
/// The lengths of ranges that are run-length encoded.
- /// The definedness of the ranges alternate starting with `initial`.
+ /// The initialization state of the ranges alternate starting with `initial`.
ranges: smallvec::SmallVec<[u64; 1]>,
}
-impl AllocationDefinedness {
- pub fn all_bytes_undef(&self) -> bool {
- // The `ranges` are run-length encoded and of alternating definedness.
- // So if `ranges.len() > 1` then the second block is a range of defined.
+impl InitMaskCompressed {
+ pub fn no_bytes_init(&self) -> bool {
+ // The `ranges` are run-length encoded and of alternating initialization state.
+ // So if `ranges.len() > 1` then the second block is an initialized range.
!self.initial && self.ranges.len() == 1
}
}
-/// Transferring the definedness mask to other allocations.
+/// Transferring the initialization mask to other allocations.
impl<Tag, Extra> Allocation<Tag, Extra> {
- /// Creates a run-length encoding of the undef mask.
- pub fn compress_undef_range(&self, src: Pointer<Tag>, size: Size) -> AllocationDefinedness {
+ /// Creates a run-length encoding of the initialization mask.
+ pub fn compress_undef_range(&self, src: Pointer<Tag>, size: Size) -> InitMaskCompressed {
// Since we are copying `size` bytes from `src` to `dest + i * size` (`for i in 0..repeat`),
- // a naive undef mask copying algorithm would repeatedly have to read the undef mask from
+ // a naive initialization mask copying algorithm would repeatedly have to read the initialization mask from
// the source and write it to the destination. Even if we optimized the memory accesses,
// we'd be doing all of this `repeat` times.
- // Therefore we precompute a compressed version of the undef mask of the source value and
+ // Therefore we precompute a compressed version of the initialization mask of the source value and
// then write it back `repeat` times without computing any more information from the source.
- // A precomputed cache for ranges of defined/undefined bits
+ // A precomputed cache for ranges of initialized / uninitialized bits
// 0000010010001110 will become
// `[5, 1, 2, 1, 3, 3, 1]`,
// where each element toggles the state.
let mut cur = initial;
for i in 1..size.bytes() {
- // FIXME: optimize to bitshift the current undef block's bits and read the top bit.
+ // FIXME: optimize to bitshift the current uninitialized block's bits and read the top bit.
if self.init_mask.get(src.offset + Size::from_bytes(i)) == cur {
cur_len += 1;
} else {
ranges.push(cur_len);
- AllocationDefinedness { ranges, initial }
+ InitMaskCompressed { ranges, initial }
}
- /// Applies multiple instances of the run-length encoding to the undef mask.
- pub fn mark_compressed_undef_range(
+ /// Applies multiple instances of the run-length encoding to the initialization mask.
+ pub fn mark_compressed_init_range(
&mut self,
- defined: &AllocationDefinedness,
+ defined: &InitMaskCompressed,
dest: Pointer<Tag>,
size: Size,
repeat: u64,
}
////////////////////////////////////////////////////////////////////////////////
-// Undefined byte tracking
+// Uninitialized byte tracking
////////////////////////////////////////////////////////////////////////////////
type Block = u64;
match idx {
Some(idx) => {
- let undef_end = (idx.bytes()..end.bytes())
+ let uninit_end = (idx.bytes()..end.bytes())
.map(Size::from_bytes)
.find(|&i| self.get(i))
.unwrap_or(end);
- Err(idx..undef_end)
+ Err(idx..uninit_end)
}
None => Ok(()),
}
}
#[inline]
- pub fn not_undef(self) -> InterpResult<'static, Scalar<Tag>> {
+ pub fn check_init(self) -> InterpResult<'static, Scalar<Tag>> {
match self {
ScalarMaybeUninit::Scalar(scalar) => Ok(scalar),
ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)),
#[inline(always)]
pub fn to_bool(self) -> InterpResult<'tcx, bool> {
- self.not_undef()?.to_bool()
+ self.check_init()?.to_bool()
}
#[inline(always)]
pub fn to_char(self) -> InterpResult<'tcx, char> {
- self.not_undef()?.to_char()
+ self.check_init()?.to_char()
}
#[inline(always)]
pub fn to_f32(self) -> InterpResult<'tcx, Single> {
- self.not_undef()?.to_f32()
+ self.check_init()?.to_f32()
}
#[inline(always)]
pub fn to_f64(self) -> InterpResult<'tcx, Double> {
- self.not_undef()?.to_f64()
+ self.check_init()?.to_f64()
}
#[inline(always)]
pub fn to_u8(self) -> InterpResult<'tcx, u8> {
- self.not_undef()?.to_u8()
+ self.check_init()?.to_u8()
}
#[inline(always)]
pub fn to_u16(self) -> InterpResult<'tcx, u16> {
- self.not_undef()?.to_u16()
+ self.check_init()?.to_u16()
}
#[inline(always)]
pub fn to_u32(self) -> InterpResult<'tcx, u32> {
- self.not_undef()?.to_u32()
+ self.check_init()?.to_u32()
}
#[inline(always)]
pub fn to_u64(self) -> InterpResult<'tcx, u64> {
- self.not_undef()?.to_u64()
+ self.check_init()?.to_u64()
}
#[inline(always)]
pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
- self.not_undef()?.to_machine_usize(cx)
+ self.check_init()?.to_machine_usize(cx)
}
#[inline(always)]
pub fn to_i8(self) -> InterpResult<'tcx, i8> {
- self.not_undef()?.to_i8()
+ self.check_init()?.to_i8()
}
#[inline(always)]
pub fn to_i16(self) -> InterpResult<'tcx, i16> {
- self.not_undef()?.to_i16()
+ self.check_init()?.to_i16()
}
#[inline(always)]
pub fn to_i32(self) -> InterpResult<'tcx, i32> {
- self.not_undef()?.to_i32()
+ self.check_init()?.to_i32()
}
#[inline(always)]
pub fn to_i64(self) -> InterpResult<'tcx, i64> {
- self.not_undef()?.to_i64()
+ self.check_init()?.to_i64()
}
#[inline(always)]
pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> {
- self.not_undef()?.to_machine_isize(cx)
+ self.check_init()?.to_machine_isize(cx)
}
}
MonoItem::GlobalAsm(..) => return true,
};
- tcx.substitute_normalize_and_test_predicates((def_id, &substs))
+ !tcx.subst_and_check_impossible_predicates((def_id, &substs))
}
pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String {
/// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
/// }
/// ```
+ // It looks like caching this query on disk actually slightly
+ // worsened performance in #74376.
+ //
+ // Once const generics are more prevalently used, we might want to
+ // consider only caching calls returning `Some`.
query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
- // FIXME(#74113): consider storing this query on disk.
}
/// Records the type of every item.
query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> {
desc { "codegen_unit" }
}
+ query unused_generic_params(key: DefId) -> FiniteBitSet<u64> {
+ cache_on_disk_if { key.is_local() }
+ desc {
+ |tcx| "determining which generic parameters are unused by `{}`",
+ tcx.def_path_str(key)
+ }
+ }
query backend_optimization_level(_: CrateNum) -> OptLevel {
desc { "optimization level used by backend" }
}
desc { "normalizing `{:?}`", goal }
}
- query substitute_normalize_and_test_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
+ query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
desc { |tcx|
- "testing substituted normalized predicates:`{}`",
+ "impossible substituted predicates:`{}`",
tcx.def_path_str(key.0)
}
}
}
}
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct UnifyReceiverContext<'tcx> {
+ pub assoc_item: ty::AssocItem,
+ pub param_env: ty::ParamEnv<'tcx>,
+ pub substs: SubstsRef<'tcx>,
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from the span.
/// Method receiver
MethodReceiver,
+ UnifyReceiver(Box<UnifyReceiverContext<'tcx>>),
+
/// `return` with no expression
ReturnNoExpression,
use crate::ich::{self, StableHashingContext};
use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::fold::TypeFoldable;
use crate::ty::{self, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
start_from_impl: DefId,
) -> Result<Ancestors<'tcx>, ErrorReported> {
let specialization_graph = tcx.specialization_graph_of(trait_def_id);
- if specialization_graph.has_errored {
+
+ if specialization_graph.has_errored || tcx.type_of(start_from_impl).references_error() {
Err(ErrorReported)
} else {
Ok(Ancestors {
super::StartFunctionType => Some(super::StartFunctionType),
super::IntrinsicType => Some(super::IntrinsicType),
super::MethodReceiver => Some(super::MethodReceiver),
+ super::UnifyReceiver(ref ctxt) => tcx.lift(ctxt).map(|ctxt| super::UnifyReceiver(ctxt)),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
}
}
}
+impl<'a, 'tcx> Lift<'tcx> for traits::UnifyReceiverContext<'a> {
+ type Lifted = traits::UnifyReceiverContext<'tcx>;
+ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+ tcx.lift(&self.param_env).and_then(|param_env| {
+ tcx.lift(&self.substs).map(|substs| traits::UnifyReceiverContext {
+ assoc_item: self.assoc_item,
+ param_env,
+ substs,
+ })
+ })
+ }
+}
+
impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
type Lifted = traits::DerivedObligationCause<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
}
&ty::Generator(_, ref substs, _) => {
- self.add_substs(substs);
+ let substs = substs.as_generator();
+ let should_remove_further_specializable =
+ !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ self.add_substs(substs.parent_substs());
+ if should_remove_further_specializable {
+ self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+ }
+
+ self.add_ty(substs.resume_ty());
+ self.add_ty(substs.return_ty());
+ self.add_ty(substs.witness());
+ self.add_ty(substs.yield_ty());
+ self.add_ty(substs.tupled_upvars_ty());
}
&ty::GeneratorWitness(ts) => {
}
&ty::Closure(_, substs) => {
- self.add_substs(substs);
+ let substs = substs.as_closure();
+ let should_remove_further_specializable =
+ !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
+ self.add_substs(substs.parent_substs());
+ if should_remove_further_specializable {
+ self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+ }
+
+ self.add_ty(substs.sig_as_fn_ptr_ty());
+ self.add_ty(substs.kind_ty());
+ self.add_ty(substs.tupled_upvars_ty());
}
&ty::Bound(debruijn, _) => {
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::ty::print::{FmtPrinter, Printer};
+use crate::ty::subst::InternalSubsts;
use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable};
use rustc_errors::ErrorReported;
use rustc_hir::def::Namespace;
}
impl<'tcx> Instance<'tcx> {
- /// Returns the `Ty` corresponding to this `Instance`,
- /// with generic substitutions applied and lifetimes erased.
- ///
- /// This method can only be called when the 'substs' for this Instance
- /// are fully monomorphic (no `ty::Param`'s are present).
- /// This is usually the case (e.g. during codegen).
- /// However, during constant evaluation, we may want
- /// to try to resolve a `Instance` using generic parameters
- /// (e.g. when we are attempting to to do const-propagation).
- /// In this case, `Instance.ty_env` should be used to provide
- /// the `ParamEnv` for our generic context.
- pub fn monomorphic_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
- let ty = tcx.type_of(self.def.def_id());
- // There shouldn't be any params - if there are, then
- // Instance.ty_env should have been used to provide the proper
- // ParamEnv
- if self.substs.has_param_types_or_consts() {
- bug!("Instance.ty called for type {:?} with params in substs: {:?}", ty, self.substs);
- }
- tcx.subst_and_normalize_erasing_regions(self.substs, ty::ParamEnv::reveal_all(), &ty)
- }
-
- /// Like `Instance.ty`, but allows a `ParamEnv` to be specified for use during
- /// normalization. This method is only really useful during constant evaluation,
- /// where we are dealing with potentially generic types.
- pub fn ty_env(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
+ /// Returns the `Ty` corresponding to this `Instance`, with generic substitutions applied and
+ /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
+ pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
let ty = tcx.type_of(self.def.def_id());
tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty)
}
| InstanceDef::VtableShim(..) => Some(self.substs),
}
}
+
+ /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by
+ /// identify parameters if they are determined to be unused in `instance.def`.
+ pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self {
+ debug!("polymorphize: running polymorphization analysis");
+ if !tcx.sess.opts.debugging_opts.polymorphize {
+ return self;
+ }
+
+ if let InstanceDef::Item(def) = self.def {
+ let unused = tcx.unused_generic_params(def.did);
+
+ if unused.is_empty() {
+ // Exit early if every parameter was used.
+ return self;
+ }
+
+ debug!("polymorphize: unused={:?}", unused);
+ let polymorphized_substs =
+ InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind {
+ // If parameter is a const or type parameter..
+ ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
+ // ..and is within range and unused..
+ unused.contains(param.index).unwrap_or(false) =>
+ // ..then use the identity for this parameter.
+ tcx.mk_param_from_def(param),
+ // Otherwise, use the parameter as before.
+ _ => self.substs[param.index as usize],
+ });
+
+ debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
+ Self { def: self.def, substs: polymorphized_substs }
+ } else {
+ self
+ }
+ }
}
fn needs_fn_once_adapter_shim(
.iter_enumerated()
.all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i.as_u32()));
- let mut niche_filling_layout = None;
-
// Niche-filling enum optimization.
if !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants {
let mut dataful_variant = None;
let largest_niche =
Niche::from_scalar(dl, offset, niche_scalar.clone());
- niche_filling_layout = Some(Layout {
+ return Ok(tcx.intern_layout(Layout {
variants: Variants::Multiple {
tag: niche_scalar,
tag_encoding: TagEncoding::Niche {
largest_niche,
size,
align,
- });
+ }));
}
}
}
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag.clone());
- let tagged_layout = Layout {
+ tcx.intern_layout(Layout {
variants: Variants::Multiple {
tag,
tag_encoding: TagEncoding::Direct,
abi,
align,
size,
- };
-
- let best_layout = match (tagged_layout, niche_filling_layout) {
- (tagged_layout, Some(niche_filling_layout)) => {
- // Pick the smaller layout; otherwise,
- // pick the layout with the larger niche; otherwise,
- // pick tagged as it has simpler codegen.
- cmp::min_by_key(tagged_layout, niche_filling_layout, |layout| {
- let niche_size =
- layout.largest_niche.as_ref().map_or(0, |n| n.available(dl));
- (layout.size, cmp::Reverse(niche_size))
- })
- }
- (tagged_layout, None) => tagged_layout,
- };
-
- tcx.intern_layout(best_layout)
+ })
}
// Types with no meaningful known layout.
}
fn pointee_info_at(this: TyAndLayout<'tcx>, cx: &C, offset: Size) -> Option<PointeeInfo> {
- match this.ty.kind {
+ let addr_space_of_ty = |ty: Ty<'tcx>| {
+ if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
+ };
+
+ let pointee_info = match this.ty.kind {
ty::RawPtr(mt) if offset.bytes() == 0 => {
cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: None,
+ address_space: addr_space_of_ty(mt.ty),
+ })
+ }
+ ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
+ cx.layout_of(cx.tcx().mk_fn_ptr(fn_sig)).to_result().ok().map(|layout| {
+ PointeeInfo {
+ size: layout.size,
+ align: layout.align.abi,
+ safe: None,
+ address_space: cx.data_layout().instruction_address_space,
+ }
})
}
-
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
+ let address_space = addr_space_of_ty(ty);
let tcx = cx.tcx();
let is_freeze = ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env());
let kind = match mt {
size: layout.size,
align: layout.align.abi,
safe: Some(kind),
+ address_space,
})
}
result = field.to_result().ok().and_then(|field| {
if ptr_end <= field_start + field.size {
// We found the right field, look inside it.
- field.pointee_info_at(cx, offset - field_start)
+ let field_info =
+ field.pointee_info_at(cx, offset - field_start);
+ field_info
} else {
None
}
result
}
- }
+ };
+
+ debug!(
+ "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
+ offset, this.ty.kind, pointee_info
+ );
+
+ pointee_info
}
}
// or should go through `FnAbi` instead, to avoid losing any
// adjustments `FnAbi::of_instance` might be performing.
fn fn_sig_for_fn_abi(&self, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
- let ty = self.monomorphic_ty(tcx);
+ // FIXME(davidtwco,eddyb): A `ParamEnv` should be passed through to this function.
+ let ty = self.ty(tcx, ty::ParamEnv::reveal_all());
match ty.kind {
- ty::FnDef(..) |
- // Shims currently have type FnPtr. Not sure this should remain.
- ty::FnPtr(_) => {
- let mut sig = ty.fn_sig(tcx);
+ ty::FnDef(..) => {
+ // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering
+ // parameters unused if they show up in the signature, but not in the `mir::Body`
+ // (i.e. due to being inside a projection that got normalized, see
+ // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping
+ // track of a polymorphization `ParamEnv` to allow normalizing later.
+ let mut sig = match ty.kind {
+ ty::FnDef(def_id, substs) => tcx
+ .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id))
+ .subst(tcx, substs),
+ _ => unreachable!(),
+ };
+
if let ty::InstanceDef::VtableShim(..) = self.def {
// Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`.
sig = sig.map_bound(|mut sig| {
let sig = substs.as_closure().sig();
let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
- sig.map_bound(|sig| tcx.mk_fn_sig(
- iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
- sig.output(),
- sig.c_variadic,
- sig.unsafety,
- sig.abi
- ))
+ sig.map_bound(|sig| {
+ tcx.mk_fn_sig(
+ iter::once(env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
+ sig.output(),
+ sig.c_variadic,
+ sig.unsafety,
+ sig.abi,
+ )
+ })
}
ty::Generator(_, substs, _) => {
let sig = substs.as_generator().poly_sig();
sig.map_bound(|sig| {
let state_did = tcx.require_lang_item(GeneratorStateLangItem, None);
let state_adt_ref = tcx.adt_def(state_did);
- let state_substs = tcx.intern_substs(&[
- sig.yield_ty.into(),
- sig.return_ty.into(),
- ]);
+ let state_substs =
+ tcx.intern_substs(&[sig.yield_ty.into(), sig.return_ty.into()]);
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
tcx.mk_fn_sig(
&ret_ty,
false,
hir::Unsafety::Normal,
- rustc_target::spec::abi::Abi::Rust
+ rustc_target::spec::abi::Abi::Rust,
)
})
}
- _ => bug!("unexpected type {:?} in Instance::fn_sig", ty)
+ _ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
}
}
}
pub extern_prelude: FxHashMap<Symbol, bool>,
}
-#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable, Hash)]
pub enum AssocItemContainer {
TraitContainer(DefId),
ImplContainer(DefId),
Reservation,
}
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
+#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
pub struct AssocItem {
pub def_id: DefId,
#[stable_hasher(project(name))]
pub fn_has_self_parameter: bool,
}
-#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash)]
pub enum AssocKind {
Const,
Fn,
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable)]
+#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable, HashStable, Hash)]
pub enum Visibility {
/// Visible everywhere (including in other crates).
Public,
false
}
+ /// Returns the `GenericParamDef` with the given index.
pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
if let Some(index) = param_index.checked_sub(self.parent_count) {
&self.params[index]
}
}
+ /// Returns the `GenericParamDef` associated with this `EarlyBoundRegion`.
pub fn region_param(
&'tcx self,
param: &EarlyBoundRegion,
}
}
- /// Returns the `ConstParameterDef` associated with this `ParamConst`.
+ /// Returns the `GenericParamDef` associated with this `ParamConst`.
pub fn const_param(&'tcx self, param: &ParamConst, tcx: TyCtxt<'tcx>) -> &GenericParamDef {
let param = self.param_at(param.index as usize, tcx);
match param.kind {
impl<T> WithOptConstParam<T> {
/// Creates a new `WithOptConstParam` setting `const_param_did` to `None`.
+ #[inline(always)]
pub fn unknown(did: T) -> WithOptConstParam<T> {
WithOptConstParam { did, const_param_did: None }
}
}
impl WithOptConstParam<LocalDefId> {
+ /// Returns `Some((did, param_did))` if `def_id` is a const argument,
+ /// `None` otherwise.
+ #[inline(always)]
+ pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> {
+ tcx.opt_const_param_of(did).map(|param_did| (did, param_did))
+ }
+
+ /// In case `self` is unknown but `self.did` is a const argument, this returns
+ /// a `WithOptConstParam` with the correct `const_param_did`.
+ #[inline(always)]
+ pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> {
+ if self.const_param_did.is_none() {
+ if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) {
+ return Some(WithOptConstParam { did: self.did, const_param_did });
+ }
+ }
+
+ None
+ }
+
pub fn to_global(self) -> WithOptConstParam<DefId> {
WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did }
}
where
T: TypeFoldable<'tcx>,
{
- assert!(!value.needs_subst());
let value = self.erase_late_bound_regions(value);
self.normalize_erasing_regions(param_env, value)
}
let substs = substs.truncate_to(self.tcx, generics);
self.push_generic_params(substs, iter::empty(), output, debug);
}
+ ty::Param(_) => {
+ output.push_str(&t.to_string());
+ }
ty::Error(_)
| ty::Bound(..)
| ty::Infer(_)
| ty::Placeholder(..)
| ty::Projection(..)
- | ty::Param(_)
| ty::GeneratorWitness(_)
| ty::Opaque(..) => {
if debug {
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId};
use rustc_hir::lang_items::{LangItem, LanguageItems};
use rustc_hir::{Crate, HirIdSet, ItemLocalId, TraitCandidate};
-use rustc_index::vec::IndexVec;
+use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use rustc_session::utils::NativeLibKind;
use rustc_session::CrateDisambiguator;
UseSpecializedDecodable, UseSpecializedEncodable,
};
use rustc_session::{CrateDisambiguator, Session};
-use rustc_span::hygiene::{ExpnId, SyntaxContext};
+use rustc_span::hygiene::{
+ ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext,
+ SyntaxContext, SyntaxContextData,
+};
use rustc_span::source_map::{SourceMap, StableSourceFileId};
use rustc_span::symbol::Ident;
use rustc_span::CachingSourceMapView;
-use rustc_span::{BytePos, SourceFile, Span, DUMMY_SP};
+use rustc_span::{BytePos, ExpnData, SourceFile, Span, DUMMY_SP};
use std::mem;
const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE;
-const TAG_NO_EXPN_DATA: u8 = 0;
-const TAG_EXPN_DATA_SHORTHAND: u8 = 1;
-const TAG_EXPN_DATA_INLINE: u8 = 2;
-
const TAG_VALID_SPAN: u8 = 0;
const TAG_INVALID_SPAN: u8 = 1;
+const TAG_SYNTAX_CONTEXT: u8 = 0;
+const TAG_EXPN_DATA: u8 = 1;
+
/// Provides an interface to incremental compilation data cached from the
/// previous compilation session. This data will eventually include the results
/// of a few selected queries (like `typeck` and `mir_optimized`) and
// Caches that are populated lazily during decoding.
file_index_to_file: Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
- synthetic_syntax_contexts: Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
// A map from dep-node to the position of the cached query result in
// `serialized_data`.
prev_diagnostics_index: FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
alloc_decoding_state: AllocDecodingState,
+
+ // A map from syntax context ids to the position of their associated
+ // `SyntaxContextData`. We use a `u32` instead of a `SyntaxContext`
+ // to represent the fact that we are storing *encoded* ids. When we decode
+ // a `SyntaxContext`, a new id will be allocated from the global `HygieneData`,
+ // which will almost certainly be different than the serialized id.
+ syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
+ // A map from the `DefPathHash` of an `ExpnId` to the position
+ // of their associated `ExpnData`. Ideally, we would store a `DefId`,
+ // but we need to decode this before we've constructed a `TyCtxt` (which
+ // makes it difficult to decode a `DefId`).
+
+ // Note that these `DefPathHashes` correspond to both local and foreign
+ // `ExpnData` (e.g `ExpnData.krate` may not be `LOCAL_CRATE`). Alternatively,
+ // we could look up the `ExpnData` from the metadata of foreign crates,
+ // but it seemed easier to have `OnDiskCache` be independent of the `CStore`.
+ expn_data: FxHashMap<u32, AbsoluteBytePos>,
+ // Additional information used when decoding hygiene data.
+ hygiene_context: HygieneDecodeContext,
}
-// This type is used only for (de-)serialization.
+// This type is used only for serialization and deserialization.
#[derive(RustcEncodable, RustcDecodable)]
struct Footer {
file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>,
diagnostics_index: EncodedQueryResultIndex,
// The location of all allocations.
interpret_alloc_index: Vec<u32>,
+ // See `OnDiskCache.syntax_contexts`
+ syntax_contexts: FxHashMap<u32, AbsoluteBytePos>,
+ // See `OnDiskCache.expn_data`
+ expn_data: FxHashMap<u32, AbsoluteBytePos>,
}
type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>;
// Decode the file footer, which contains all the lookup tables, etc.
decoder.set_position(footer_pos);
+
decode_tagged(&mut decoder, TAG_FILE_FOOTER)
.expect("error while trying to decode footer position")
};
current_diagnostics: Default::default(),
query_result_index: footer.query_result_index.into_iter().collect(),
prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(),
- synthetic_syntax_contexts: Default::default(),
alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index),
+ syntax_contexts: footer.syntax_contexts,
+ expn_data: footer.expn_data,
+ hygiene_context: Default::default(),
}
}
current_diagnostics: Default::default(),
query_result_index: Default::default(),
prev_diagnostics_index: Default::default(),
- synthetic_syntax_contexts: Default::default(),
alloc_decoding_state: AllocDecodingState::new(Vec::new()),
+ syntax_contexts: FxHashMap::default(),
+ expn_data: FxHashMap::default(),
+ hygiene_context: Default::default(),
}
}
(file_to_file_index, file_index_to_stable_id)
};
+ let hygiene_encode_context = HygieneEncodeContext::default();
+
let mut encoder = CacheEncoder {
tcx,
encoder,
type_shorthands: Default::default(),
predicate_shorthands: Default::default(),
- expn_data_shorthands: Default::default(),
interpret_allocs: Default::default(),
interpret_allocs_inverse: Vec::new(),
source_map: CachingSourceMapView::new(tcx.sess.source_map()),
file_to_file_index,
+ hygiene_context: &hygiene_encode_context,
};
// Load everything into memory so we can write it out to the on-disk
})
.collect();
- // Encode the file footer.
+ let mut syntax_contexts = FxHashMap::default();
+ let mut expn_ids = FxHashMap::default();
+
+ // Encode all hygiene data (`SyntaxContextData` and `ExpnData`) from the current
+ // session.
+
+ hygiene_encode_context.encode(
+ &mut encoder,
+ |encoder, index, ctxt_data| {
+ let pos = AbsoluteBytePos::new(encoder.position());
+ encoder.encode_tagged(TAG_SYNTAX_CONTEXT, ctxt_data)?;
+ syntax_contexts.insert(index, pos);
+ Ok(())
+ },
+ |encoder, index, expn_data| {
+ let pos = AbsoluteBytePos::new(encoder.position());
+ encoder.encode_tagged(TAG_EXPN_DATA, expn_data)?;
+ expn_ids.insert(index, pos);
+ Ok(())
+ },
+ )?;
+
+ // `Encode the file footer.
let footer_pos = encoder.position() as u64;
encoder.encode_tagged(
TAG_FILE_FOOTER,
query_result_index,
diagnostics_index,
interpret_alloc_index,
+ syntax_contexts,
+ expn_data: expn_ids,
},
)?;
{
let pos = index.get(&dep_node_index).cloned()?;
+ self.with_decoder(tcx, pos, |decoder| match decode_tagged(decoder, dep_node_index) {
+ Ok(v) => Some(v),
+ Err(e) => bug!("could not decode cached {}: {}", debug_tag, e),
+ })
+ }
+
+ fn with_decoder<'tcx, T, F: FnOnce(&mut CacheDecoder<'sess, 'tcx>) -> T>(
+ &'sess self,
+ tcx: TyCtxt<'tcx>,
+ pos: AbsoluteBytePos,
+ f: F,
+ ) -> T
+ where
+ T: Decodable,
+ {
let cnum_map =
self.cnum_map.get_or_init(|| Self::compute_cnum_map(tcx, &self.prev_cnums[..]));
opaque: opaque::Decoder::new(&self.serialized_data[..], pos.to_usize()),
source_map: self.source_map,
cnum_map,
- synthetic_syntax_contexts: &self.synthetic_syntax_contexts,
file_index_to_file: &self.file_index_to_file,
file_index_to_stable_id: &self.file_index_to_stable_id,
alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(),
+ syntax_contexts: &self.syntax_contexts,
+ expn_data: &self.expn_data,
+ hygiene_context: &self.hygiene_context,
};
-
- match decode_tagged(&mut decoder, dep_node_index) {
- Ok(v) => Some(v),
- Err(e) => bug!("could not decode cached {}: {}", debug_tag, e),
- }
+ f(&mut decoder)
}
// This function builds mapping from previous-session-`CrateNum` to
opaque: opaque::Decoder<'a>,
source_map: &'a SourceMap,
cnum_map: &'a IndexVec<CrateNum, Option<CrateNum>>,
- synthetic_syntax_contexts: &'a Lock<FxHashMap<AbsoluteBytePos, SyntaxContext>>,
file_index_to_file: &'a Lock<FxHashMap<SourceFileIndex, Lrc<SourceFile>>>,
file_index_to_stable_id: &'a FxHashMap<SourceFileIndex, StableSourceFileId>,
alloc_decoding_session: AllocDecodingSession<'a>,
+ syntax_contexts: &'a FxHashMap<u32, AbsoluteBytePos>,
+ expn_data: &'a FxHashMap<u32, AbsoluteBytePos>,
+ hygiene_context: &'a HygieneDecodeContext,
}
impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
+impl<'a, 'tcx> SpecializedDecoder<SyntaxContext> for CacheDecoder<'a, 'tcx> {
+ fn specialized_decode(&mut self) -> Result<SyntaxContext, Self::Error> {
+ let syntax_contexts = self.syntax_contexts;
+ rustc_span::hygiene::decode_syntax_context(self, self.hygiene_context, |this, id| {
+ // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing.
+ // We look up the position of the associated `SyntaxData` and decode it.
+ let pos = syntax_contexts.get(&id).unwrap();
+ this.with_position(pos.to_usize(), |decoder| {
+ let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT)?;
+ Ok(data)
+ })
+ })
+ }
+}
+
+impl<'a, 'tcx> SpecializedDecoder<ExpnId> for CacheDecoder<'a, 'tcx> {
+ fn specialized_decode(&mut self) -> Result<ExpnId, Self::Error> {
+ let expn_data = self.expn_data;
+ rustc_span::hygiene::decode_expn_id(
+ self,
+ ExpnDataDecodeMode::incr_comp(self.hygiene_context),
+ |this, index| {
+ // This closure is invoked if we haven't already decoded the data for the `ExpnId` we are deserializing.
+ // We look up the position of the associated `ExpnData` and decode it.
+ let pos = expn_data
+ .get(&index)
+ .unwrap_or_else(|| panic!("Bad index {:?} (map {:?})", index, expn_data));
+
+ this.with_position(pos.to_usize(), |decoder| {
+ let data: ExpnData = decode_tagged(decoder, TAG_EXPN_DATA)?;
+ Ok(data)
+ })
+ },
+ )
+ }
+}
+
impl<'a, 'tcx> SpecializedDecoder<interpret::AllocId> for CacheDecoder<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<interpret::AllocId, Self::Error> {
let alloc_decoding_session = self.alloc_decoding_session;
let line_lo = usize::decode(self)?;
let col_lo = BytePos::decode(self)?;
let len = BytePos::decode(self)?;
+ let ctxt = SyntaxContext::decode(self)?;
let file_lo = self.file_index_to_file(file_lo_index);
let lo = file_lo.lines[line_lo - 1] + col_lo;
let hi = lo + len;
- let expn_data_tag = u8::decode(self)?;
-
- // FIXME(mw): This method does not restore `ExpnData::parent` or
- // `SyntaxContextData::prev_ctxt` or `SyntaxContextData::opaque`. These things
- // don't seem to be used after HIR lowering, so everything should be fine
- // until we want incremental compilation to serialize Spans that we need
- // full hygiene information for.
- let location = || Span::with_root_ctxt(lo, hi);
- let recover_from_expn_data = |this: &Self, expn_data, transparency, pos| {
- let span = location().fresh_expansion_with_transparency(expn_data, transparency);
- this.synthetic_syntax_contexts.borrow_mut().insert(pos, span.ctxt());
- span
- };
- Ok(match expn_data_tag {
- TAG_NO_EXPN_DATA => location(),
- TAG_EXPN_DATA_INLINE => {
- let (expn_data, transparency) = Decodable::decode(self)?;
- recover_from_expn_data(
- self,
- expn_data,
- transparency,
- AbsoluteBytePos::new(self.opaque.position()),
- )
- }
- TAG_EXPN_DATA_SHORTHAND => {
- let pos = AbsoluteBytePos::decode(self)?;
- let cached_ctxt = self.synthetic_syntax_contexts.borrow().get(&pos).cloned();
- if let Some(ctxt) = cached_ctxt {
- Span::new(lo, hi, ctxt)
- } else {
- let (expn_data, transparency) =
- self.with_position(pos.to_usize(), |this| Decodable::decode(this))?;
- recover_from_expn_data(self, expn_data, transparency, pos)
- }
- }
- _ => unreachable!(),
- })
+ Ok(Span::new(lo, hi, ctxt))
}
}
encoder: &'a mut E,
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
- expn_data_shorthands: FxHashMap<ExpnId, AbsoluteBytePos>,
interpret_allocs: FxHashMap<interpret::AllocId, usize>,
interpret_allocs_inverse: Vec<interpret::AllocId>,
source_map: CachingSourceMapView<'tcx>,
file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
+ hygiene_context: &'a HygieneEncodeContext,
}
impl<'a, 'tcx, E> CacheEncoder<'a, 'tcx, E>
}
}
+impl<'a, 'tcx, E> SpecializedEncoder<SyntaxContext> for CacheEncoder<'a, 'tcx, E>
+where
+ E: 'a + TyEncoder,
+{
+ fn specialized_encode(&mut self, ctxt: &SyntaxContext) -> Result<(), Self::Error> {
+ rustc_span::hygiene::raw_encode_syntax_context(*ctxt, self.hygiene_context, self)
+ }
+}
+
+impl<'a, 'tcx, E> SpecializedEncoder<ExpnId> for CacheEncoder<'a, 'tcx, E>
+where
+ E: 'a + TyEncoder,
+{
+ fn specialized_encode(&mut self, expn: &ExpnId) -> Result<(), Self::Error> {
+ rustc_span::hygiene::raw_encode_expn_id(
+ *expn,
+ self.hygiene_context,
+ ExpnDataEncodeMode::IncrComp,
+ self,
+ )
+ }
+}
+
impl<'a, 'tcx, E> SpecializedEncoder<Span> for CacheEncoder<'a, 'tcx, E>
where
E: 'a + TyEncoder,
line_lo.encode(self)?;
col_lo.encode(self)?;
len.encode(self)?;
-
- if span_data.ctxt == SyntaxContext::root() {
- TAG_NO_EXPN_DATA.encode(self)
- } else {
- let (expn_id, transparency, expn_data) = span_data.ctxt.outer_mark_with_data();
- if let Some(pos) = self.expn_data_shorthands.get(&expn_id).cloned() {
- TAG_EXPN_DATA_SHORTHAND.encode(self)?;
- pos.encode(self)
- } else {
- TAG_EXPN_DATA_INLINE.encode(self)?;
- let pos = AbsoluteBytePos::new(self.position());
- self.expn_data_shorthands.insert(expn_id, pos);
- (expn_data, transparency).encode(self)
- }
- }
+ span_data.ctxt.encode(self)?;
+ Ok(())
}
}
/// Struct returned by `split()`. Note that these are subslices of the
/// parent slice and not canonical substs themselves.
struct SplitClosureSubsts<'tcx> {
+ parent: &'tcx [GenericArg<'tcx>],
closure_kind_ty: GenericArg<'tcx>,
closure_sig_as_fn_ptr_ty: GenericArg<'tcx>,
tupled_upvars_ty: GenericArg<'tcx>,
/// ordering.
fn split(self) -> SplitClosureSubsts<'tcx> {
match self.substs[..] {
- [.., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
- SplitClosureSubsts { closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty }
+ [ref parent @ .., closure_kind_ty, closure_sig_as_fn_ptr_ty, tupled_upvars_ty] => {
+ SplitClosureSubsts {
+ parent,
+ closure_kind_ty,
+ closure_sig_as_fn_ptr_ty,
+ tupled_upvars_ty,
+ }
}
_ => bug!("closure substs missing synthetics"),
}
self.substs.len() >= 3 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_))
}
+ /// Returns the substitutions of the closure's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent
+ }
+
#[inline]
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
- self.split().tupled_upvars_ty.expect_ty().tuple_fields()
+ self.tupled_upvars_ty().tuple_fields()
+ }
+
+ /// Returns the tuple type representing the upvars for this closure.
+ #[inline]
+ pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+ self.split().tupled_upvars_ty.expect_ty()
}
/// Returns the closure kind for this closure; may return a type
}
struct SplitGeneratorSubsts<'tcx> {
+ parent: &'tcx [GenericArg<'tcx>],
resume_ty: GenericArg<'tcx>,
yield_ty: GenericArg<'tcx>,
return_ty: GenericArg<'tcx>,
impl<'tcx> GeneratorSubsts<'tcx> {
fn split(self) -> SplitGeneratorSubsts<'tcx> {
match self.substs[..] {
- [.., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
- SplitGeneratorSubsts { resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty }
+ [ref parent @ .., resume_ty, yield_ty, return_ty, witness, tupled_upvars_ty] => {
+ SplitGeneratorSubsts {
+ parent,
+ resume_ty,
+ yield_ty,
+ return_ty,
+ witness,
+ tupled_upvars_ty,
+ }
}
_ => bug!("generator substs missing synthetics"),
}
self.substs.len() >= 5 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_))
}
+ /// Returns the substitutions of the generator's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent
+ }
+
/// This describes the types that can be contained in a generator.
/// It will be a type variable initially and unified in the last stages of typeck of a body.
/// It contains a tuple of all the types that could end up on a generator frame.
#[inline]
pub fn upvar_tys(self) -> impl Iterator<Item = Ty<'tcx>> + 'tcx {
- self.split().tupled_upvars_ty.expect_ty().tuple_fields()
+ self.tupled_upvars_ty().tuple_fields()
+ }
+
+ /// Returns the tuple type representing the upvars for this generator.
+ #[inline]
+ pub fn tupled_upvars_ty(self) -> Ty<'tcx> {
+ self.split().tupled_upvars_ty.expect_ty()
}
/// Returns the type representing the resume type of the generator.
// Don't give suggestions for upvars, closure return types, or other unnamable
// regions.
RegionNameSource::SynthesizedFreeEnvRegion(..)
- | RegionNameSource::CannotMatchHirTy(..)
- | RegionNameSource::MatchedHirTy(..)
- | RegionNameSource::MatchedAdtAndSegment(..)
+ | RegionNameSource::AnonRegionFromArgument(..)
| RegionNameSource::AnonRegionFromUpvar(..)
| RegionNameSource::AnonRegionFromOutput(..)
| RegionNameSource::AnonRegionFromYieldTy(..)
MirBorrowckCtxt,
};
-use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
+use super::{OutlivesSuggestionBuilder, RegionName};
impl ConstraintDescription for ConstraintCategory {
fn description(&self) -> &'static str {
diag.span_label(upvar_span, "variable captured here");
}
- match self.give_region_a_name(*outlived_fr).unwrap().source {
- RegionNameSource::NamedEarlyBoundRegion(fr_span)
- | RegionNameSource::NamedFreeRegion(fr_span)
- | RegionNameSource::SynthesizedFreeEnvRegion(fr_span, _)
- | RegionNameSource::CannotMatchHirTy(fr_span, _)
- | RegionNameSource::MatchedHirTy(fr_span)
- | RegionNameSource::MatchedAdtAndSegment(fr_span)
- | RegionNameSource::AnonRegionFromUpvar(fr_span, _)
- | RegionNameSource::AnonRegionFromOutput(fr_span, _, _) => {
- diag.span_label(fr_span, "inferred to be a `FnMut` closure");
- }
- _ => {}
+ if let Some(fr_span) = self.give_region_a_name(*outlived_fr).unwrap().span() {
+ diag.span_label(fr_span, "inferred to be a `FnMut` closure");
}
diag.note(
Static,
/// The free region corresponding to the environment of a closure.
SynthesizedFreeEnvRegion(Span, String),
- /// The region name corresponds to a region where the type annotation is completely missing
- /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
- CannotMatchHirTy(Span, String),
- /// The region name corresponds a reference that was found by traversing the type in the HIR.
- MatchedHirTy(Span),
- /// A region name from the generics list of a struct/enum/union.
- MatchedAdtAndSegment(Span),
+ /// The region corresponding to an argument.
+ AnonRegionFromArgument(RegionNameHighlight),
/// The region corresponding to a closure upvar.
AnonRegionFromUpvar(Span, String),
/// The region corresponding to the return type of a closure.
AnonRegionFromAsyncFn(Span),
}
+/// Describes what to highlight to explain to the user that we're giving an anonymous region a
+/// synthesized name, and how to highlight it.
+#[derive(Debug, Clone)]
+crate enum RegionNameHighlight {
+ /// The anonymous region corresponds to a reference that was found by traversing the type in the HIR.
+ MatchedHirTy(Span),
+ /// The anonymous region corresponds to a `'_` in the generics list of a struct/enum/union.
+ MatchedAdtAndSegment(Span),
+ /// The anonymous region corresponds to a region where the type annotation is completely missing
+ /// from the code, e.g. in a closure arguments `|x| { ... }`, where `x` is a reference.
+ CannotMatchHirTy(Span, String),
+}
+
impl RegionName {
crate fn was_named(&self) -> bool {
match self.source {
| RegionNameSource::NamedFreeRegion(..)
| RegionNameSource::Static => true,
RegionNameSource::SynthesizedFreeEnvRegion(..)
- | RegionNameSource::CannotMatchHirTy(..)
- | RegionNameSource::MatchedHirTy(..)
- | RegionNameSource::MatchedAdtAndSegment(..)
+ | RegionNameSource::AnonRegionFromArgument(..)
| RegionNameSource::AnonRegionFromUpvar(..)
| RegionNameSource::AnonRegionFromOutput(..)
| RegionNameSource::AnonRegionFromYieldTy(..)
}
}
+ crate fn span(&self) -> Option<Span> {
+ match self.source {
+ RegionNameSource::Static => None,
+ RegionNameSource::NamedEarlyBoundRegion(span)
+ | RegionNameSource::NamedFreeRegion(span)
+ | RegionNameSource::SynthesizedFreeEnvRegion(span, _)
+ | RegionNameSource::AnonRegionFromUpvar(span, _)
+ | RegionNameSource::AnonRegionFromOutput(span, _, _)
+ | RegionNameSource::AnonRegionFromYieldTy(span, _)
+ | RegionNameSource::AnonRegionFromAsyncFn(span) => Some(span),
+ RegionNameSource::AnonRegionFromArgument(ref highlight) => match *highlight {
+ RegionNameHighlight::MatchedHirTy(span)
+ | RegionNameHighlight::MatchedAdtAndSegment(span)
+ | RegionNameHighlight::CannotMatchHirTy(span, _) => Some(span),
+ },
+ }
+ }
+
crate fn highlight_region_name(&self, diag: &mut DiagnosticBuilder<'_>) {
match &self.source {
RegionNameSource::NamedFreeRegion(span)
);
diag.note(¬e);
}
- RegionNameSource::CannotMatchHirTy(span, type_name) => {
+ RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::CannotMatchHirTy(
+ span,
+ type_name,
+ )) => {
diag.span_label(*span, format!("has type `{}`", type_name));
}
- RegionNameSource::MatchedHirTy(span)
+ RegionNameSource::AnonRegionFromArgument(RegionNameHighlight::MatchedHirTy(span))
| RegionNameSource::AnonRegionFromAsyncFn(span) => {
diag.span_label(
*span,
format!("let's call the lifetime of this reference `{}`", self),
);
}
- RegionNameSource::MatchedAdtAndSegment(span) => {
+ RegionNameSource::AnonRegionFromArgument(
+ RegionNameHighlight::MatchedAdtAndSegment(span),
+ ) => {
diag.span_label(*span, format!("let's call this `{}`", self));
}
RegionNameSource::AnonRegionFromUpvar(span, upvar_name) => {
let arg_ty = self.regioncx.universal_regions().unnormalized_input_tys
[implicit_inputs + argument_index];
- if let Some(region_name) =
- self.give_name_if_we_can_match_hir_ty_from_argument(fr, arg_ty, argument_index)
- {
- return Some(region_name);
- }
+ let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
+ &self.body,
+ &self.local_names,
+ argument_index,
+ );
- self.give_name_if_we_cannot_match_hir_ty(fr, arg_ty)
+ self.get_argument_hir_ty_for_highlighting(argument_index)
+ .and_then(|arg_hir_ty| self.highlight_if_we_can_match_hir_ty(fr, arg_ty, arg_hir_ty))
+ .or_else(|| {
+ // `highlight_if_we_cannot_match_hir_ty` needs to know the number we will give to
+ // the anonymous region. If it succeeds, the `synthesize_region_name` call below
+ // will increment the counter, "reserving" the number we just used.
+ let counter = *self.next_region_name.try_borrow().unwrap();
+ self.highlight_if_we_cannot_match_hir_ty(fr, arg_ty, span, counter)
+ })
+ .map(|highlight| RegionName {
+ name: self.synthesize_region_name(),
+ source: RegionNameSource::AnonRegionFromArgument(highlight),
+ })
}
- fn give_name_if_we_can_match_hir_ty_from_argument(
+ fn get_argument_hir_ty_for_highlighting(
&self,
- needle_fr: RegionVid,
- argument_ty: Ty<'tcx>,
argument_index: usize,
- ) -> Option<RegionName> {
+ ) -> Option<&hir::Ty<'tcx>> {
let mir_hir_id = self.infcx.tcx.hir().as_local_hir_id(self.mir_def_id);
let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(mir_hir_id)?;
let argument_hir_ty: &hir::Ty<'_> = fn_decl.inputs.get(argument_index)?;
// (`give_name_if_anonymous_region_appears_in_arguments`).
hir::TyKind::Infer => None,
- _ => self.give_name_if_we_can_match_hir_ty(needle_fr, argument_ty, argument_hir_ty),
+ _ => Some(argument_hir_ty),
}
}
/// | | has type `&'1 u32`
/// | has type `&'2 u32`
/// ```
- fn give_name_if_we_cannot_match_hir_ty(
+ fn highlight_if_we_cannot_match_hir_ty(
&self,
needle_fr: RegionVid,
- argument_ty: Ty<'tcx>,
- ) -> Option<RegionName> {
- let counter = *self.next_region_name.try_borrow().unwrap();
+ ty: Ty<'tcx>,
+ span: Span,
+ counter: usize,
+ ) -> Option<RegionNameHighlight> {
let mut highlight = RegionHighlightMode::default();
highlight.highlighting_region_vid(needle_fr, counter);
- let type_name = self.infcx.extract_type_name(&argument_ty, Some(highlight)).0;
+ let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0;
debug!(
- "give_name_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
+ "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}",
type_name, needle_fr
);
- let assigned_region_name = if type_name.find(&format!("'{}", counter)).is_some() {
+ if type_name.find(&format!("'{}", counter)).is_some() {
// Only add a label if we can confirm that a region was labelled.
- let argument_index =
- self.regioncx.get_argument_index_for_region(self.infcx.tcx, needle_fr)?;
- let (_, span) = self.regioncx.get_argument_name_and_span_for_region(
- &self.body,
- &self.local_names,
- argument_index,
- );
-
- Some(RegionName {
- // This counter value will already have been used, so this function will increment
- // it so the next value will be used next and return the region name that would
- // have been used.
- name: self.synthesize_region_name(),
- source: RegionNameSource::CannotMatchHirTy(span, type_name),
- })
+
+ Some(RegionNameHighlight::CannotMatchHirTy(span, type_name))
} else {
None
- };
-
- assigned_region_name
+ }
}
/// Attempts to highlight the specific part of a type annotation
/// | - let's call the lifetime of this reference `'1`
/// ```
///
- /// the way this works is that we match up `argument_ty`, which is
+ /// the way this works is that we match up `ty`, which is
/// a `Ty<'tcx>` (the internal form of the type) with
- /// `argument_hir_ty`, a `hir::Ty` (the syntax of the type
+ /// `hir_ty`, a `hir::Ty` (the syntax of the type
/// annotation). We are descending through the types stepwise,
/// looking in to find the region `needle_fr` in the internal
/// type. Once we find that, we can use the span of the `hir::Ty`
/// keep track of the **closest** type we've found. If we fail to
/// find the exact `&` or `'_` to highlight, then we may fall back
/// to highlighting that closest type instead.
- fn give_name_if_we_can_match_hir_ty(
+ fn highlight_if_we_can_match_hir_ty(
&self,
needle_fr: RegionVid,
- argument_ty: Ty<'tcx>,
- argument_hir_ty: &hir::Ty<'_>,
- ) -> Option<RegionName> {
- let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> =
- &mut vec![(argument_ty, argument_hir_ty)];
+ ty: Ty<'tcx>,
+ hir_ty: &hir::Ty<'_>,
+ ) -> Option<RegionNameHighlight> {
+ let search_stack: &mut Vec<(Ty<'tcx>, &hir::Ty<'_>)> = &mut vec![(ty, hir_ty)];
while let Some((ty, hir_ty)) = search_stack.pop() {
match (&ty.kind, &hir_ty.kind) {
- // Check if the `argument_ty` is `&'X ..` where `'X`
+ // Check if the `ty` is `&'X ..` where `'X`
// is the region we are looking for -- if so, and we have a `&T`
// on the RHS, then we want to highlight the `&` like so:
//
hir::TyKind::Rptr(_lifetime, referent_hir_ty),
) => {
if region.to_region_vid() == needle_fr {
- let region_name = self.synthesize_region_name();
-
// Just grab the first character, the `&`.
let source_map = self.infcx.tcx.sess.source_map();
let ampersand_span = source_map.start_point(hir_ty.span);
- return Some(RegionName {
- name: region_name,
- source: RegionNameSource::MatchedHirTy(ampersand_span),
- });
+ return Some(RegionNameHighlight::MatchedHirTy(ampersand_span));
}
// Otherwise, let's descend into the referent types.
Res::Def(DefKind::TyAlias, _) => (),
_ => {
if let Some(last_segment) = path.segments.last() {
- if let Some(name) = self.match_adt_and_segment(
+ if let Some(highlight) = self.match_adt_and_segment(
substs,
needle_fr,
last_segment,
search_stack,
) {
- return Some(name);
+ return Some(highlight);
}
}
}
needle_fr: RegionVid,
last_segment: &'hir hir::PathSegment<'hir>,
search_stack: &mut Vec<(Ty<'tcx>, &'hir hir::Ty<'hir>)>,
- ) -> Option<RegionName> {
+ ) -> Option<RegionNameHighlight> {
// Did the user give explicit arguments? (e.g., `Foo<..>`)
let args = last_segment.args.as_ref()?;
let lifetime =
| hir::LifetimeName::Error
| hir::LifetimeName::Static
| hir::LifetimeName::Underscore => {
- let region_name = self.synthesize_region_name();
- let ampersand_span = lifetime.span;
- Some(RegionName {
- name: region_name,
- source: RegionNameSource::MatchedAdtAndSegment(ampersand_span),
- })
+ let lifetime_span = lifetime.span;
+ Some(RegionNameHighlight::MatchedAdtAndSegment(lifetime_span))
}
hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Implicit => {
pub fn provide(providers: &mut Providers) {
*providers = Providers {
- mir_borrowck: |tcx, did| mir_borrowck(tcx, ty::WithOptConstParam::unknown(did)),
+ mir_borrowck: |tcx, did| {
+ if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+ tcx.mir_borrowck_const_arg(def)
+ } else {
+ mir_borrowck(tcx, ty::WithOptConstParam::unknown(did))
+ }
+ },
mir_borrowck_const_arg: |tcx, (did, param_did)| {
mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
},
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx BorrowCheckResult<'tcx> {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_borrowck_const_arg((def.did, param_did));
- }
- }
-
let (input_body, promoted) = tcx.mir_validated(def);
debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
ScalarMaybeUninit::Uninit => to_const_value(op.assert_mem_place(ecx)),
},
Immediate::ScalarPair(a, b) => {
- let (data, start) = match a.not_undef().unwrap() {
+ let (data, start) = match a.check_init().unwrap() {
Scalar::Ptr(ptr) => {
(ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes())
}
// We call `const_eval` for zero arg intrinsics, too, in order to cache their value.
// Catch such calls and evaluate them instead of trying to load a constant's MIR.
if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def {
- let ty = key.value.instance.ty_env(tcx, key.param_env);
+ let ty = key.value.instance.ty(tcx, key.param_env);
let substs = match ty.kind {
ty::FnDef(_, substs) => substs,
_ => bug!("intrinsic with type {:?}", ty),
};
use rustc_middle::ty;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable};
use rustc_span::symbol::{sym, Symbol};
use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size};
let name = tcx.item_name(def_id);
Ok(match name {
sym::type_name => {
+ if tp_ty.needs_subst() {
+ throw_inval!(TooGeneric);
+ }
let alloc = type_name::alloc_type_name(tcx, tp_ty);
ConstValue::Slice { data: alloc, start: 0, end: alloc.len() }
}
};
ConstValue::from_machine_usize(n, &tcx)
}
- sym::type_id => ConstValue::from_u64(tcx.type_id_hash(tp_ty)),
+ sym::type_id => {
+ if tp_ty.needs_subst() {
+ throw_inval!(TooGeneric);
+ }
+ ConstValue::from_u64(tcx.type_id_hash(tp_ty))
+ }
sym::variant_count => {
if let ty::Adt(ref adt, _) = tp_ty.kind {
ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx)
| sym::bitreverse => {
let ty = substs.type_at(0);
let layout_of = self.layout_of(ty)?;
- let val = self.read_scalar(args[0])?.not_undef()?;
+ let val = self.read_scalar(args[0])?.check_init()?;
let bits = self.force_bits(val, layout_of.size)?;
let kind = match layout_of.abi {
Abi::Scalar(ref scalar) => scalar.value,
// rotate_left: (X << (S % BW)) | (X >> ((BW - S) % BW))
// rotate_right: (X << ((BW - S) % BW)) | (X >> (S % BW))
let layout = self.layout_of(substs.type_at(0))?;
- let val = self.read_scalar(args[0])?.not_undef()?;
+ let val = self.read_scalar(args[0])?.check_init()?;
let val_bits = self.force_bits(val, layout.size)?;
- let raw_shift = self.read_scalar(args[1])?.not_undef()?;
+ let raw_shift = self.read_scalar(args[1])?.check_init()?;
let raw_shift_bits = self.force_bits(raw_shift, layout.size)?;
let width_bits = u128::from(layout.size.bits());
let shift_bits = raw_shift_bits % width_bits;
self.write_scalar(result, dest)?;
}
sym::offset => {
- let ptr = self.read_scalar(args[0])?.not_undef()?;
+ let ptr = self.read_scalar(args[0])?.check_init()?;
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
let pointee_ty = substs.type_at(0);
self.write_scalar(offset_ptr, dest)?;
}
sym::arith_offset => {
- let ptr = self.read_scalar(args[0])?.not_undef()?;
+ let ptr = self.read_scalar(args[0])?.check_init()?;
let offset_count = self.read_scalar(args[1])?.to_machine_isize(self)?;
let pointee_ty = substs.type_at(0);
align: Align,
kind: MemoryKind<M::MemoryKind>,
) -> Pointer<M::PointerTag> {
- let alloc = Allocation::undef(size, align);
+ let alloc = Allocation::uninit(size, align);
self.allocate_with(alloc, kind)
}
}
}
- pub fn leak_report(&self) -> usize {
+ /// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation
+ /// are not considered leaked. Leaks whose kind `may_leak()` returns true are not reported.
+ pub fn leak_report(&self, static_roots: &[AllocId]) -> usize {
// Collect the set of allocations that are *reachable* from `Global` allocations.
let reachable = {
let mut reachable = FxHashSet::default();
let mut todo: Vec<_> = self.alloc_map.filter_map_collect(move |&id, &(kind, _)| {
if Some(kind) == global_kind { Some(id) } else { None }
});
+ todo.extend(static_roots);
while let Some(id) = todo.pop() {
if reachable.insert(id) {
// This is a new allocation, add its relocations to `todo`.
let dest_bytes = dest_bytes.as_mut_ptr();
- // Prepare a copy of the undef mask.
+ // Prepare a copy of the initialization mask.
let compressed = self.get_raw(src.alloc_id)?.compress_undef_range(src, size);
- if compressed.all_bytes_undef() {
- // Fast path: If all bytes are `undef` then there is nothing to copy. The target range
- // is marked as undef but we otherwise omit changing the byte representation which may
- // be arbitrary for undef bytes.
+ if compressed.no_bytes_init() {
+ // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range
+ // is marked as unititialized but we otherwise omit changing the byte representation which may
+ // be arbitrary for uninitialized bytes.
// This also avoids writing to the target bytes so that the backing allocation is never
- // touched if the bytes stay undef for the whole interpreter execution. On contemporary
+ // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
// operating system this can avoid physically allocating the page.
let dest_alloc = self.get_raw_mut(dest.alloc_id)?;
- dest_alloc.mark_definedness(dest, size * length, false); // `Size` multiplication
+ dest_alloc.mark_init(dest, size * length, false); // `Size` multiplication
dest_alloc.mark_relocation_range(relocations);
return Ok(());
}
}
// now fill in all the data
- self.get_raw_mut(dest.alloc_id)?.mark_compressed_undef_range(
+ self.get_raw_mut(dest.alloc_id)?.mark_compressed_init_range(
&compressed,
dest,
size,
}
#[inline]
- pub fn to_scalar_or_undef(self) -> ScalarMaybeUninit<Tag> {
+ pub fn to_scalar_or_uninit(self) -> ScalarMaybeUninit<Tag> {
match self {
Immediate::Scalar(val) => val,
Immediate::ScalarPair(..) => bug!("Got a wide pointer where a scalar was expected"),
#[inline]
pub fn to_scalar(self) -> InterpResult<'tcx, Scalar<Tag>> {
- self.to_scalar_or_undef().not_undef()
+ self.to_scalar_or_uninit().check_init()
}
#[inline]
pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
match self {
Immediate::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"),
- Immediate::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?)),
+ Immediate::ScalarPair(a, b) => Ok((a.check_init()?, b.check_init()?)),
}
}
}
&self,
op: OpTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ScalarMaybeUninit<M::PointerTag>> {
- Ok(self.read_immediate(op)?.to_scalar_or_undef())
+ Ok(self.read_immediate(op)?.to_scalar_or_uninit())
}
// Turn the wide MPlace into a string (must already be dereferenced!)
val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
let layout = self.layout_of(pointee_type)?;
let (ptr, meta) = match *val {
- Immediate::Scalar(ptr) => (ptr.not_undef()?, MemPlaceMeta::None),
+ Immediate::Scalar(ptr) => (ptr.check_init()?, MemPlaceMeta::None),
Immediate::ScalarPair(ptr, meta) => {
- (ptr.not_undef()?, MemPlaceMeta::Meta(meta.not_undef()?))
+ (ptr.check_init()?, MemPlaceMeta::Meta(meta.check_init()?))
}
};
let n = self.access_local(self.frame(), local, Some(layout))?;
let n = self.read_scalar(n)?;
let n = u64::try_from(
- self.force_bits(n.not_undef()?, self.tcx.data_layout.pointer_size)?,
+ self.force_bits(n.check_init()?, self.tcx.data_layout.pointer_size)?,
)
.unwrap();
self.mplace_index(base, n)?
let (fn_val, abi) = match func.layout.ty.kind {
ty::FnPtr(sig) => {
let caller_abi = sig.abi();
- let fn_ptr = self.read_scalar(func)?.not_undef()?;
+ let fn_ptr = self.read_scalar(func)?.check_init()?;
let fn_val = self.memory.get_fn(fn_ptr)?;
(fn_val, caller_abi)
}
// ABI check
{
let callee_abi = {
- let instance_ty = instance.ty_env(*self.tcx, self.param_env);
+ let instance_ty = instance.ty(*self.tcx, self.param_env);
match instance_ty.kind {
ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(),
ty::Closure(..) => Abi::RustCall,
.memory
.get_raw(vtable_slot.alloc_id)?
.read_ptr_sized(self, vtable_slot)?
- .not_undef()?;
+ .check_init()?;
Ok(self.memory.get_fn(fn_ptr)?)
}
)?
.expect("cannot be a ZST");
let drop_fn =
- self.memory.get_raw(vtable.alloc_id)?.read_ptr_sized(self, vtable)?.not_undef()?;
+ self.memory.get_raw(vtable.alloc_id)?.read_ptr_sized(self, vtable)?.check_init()?;
// We *need* an instance here, no other kind of function value, to be able
// to determine the type.
let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
trace!("Found drop fn: {:?}", drop_instance);
- let fn_sig = drop_instance.ty_env(*self.tcx, self.param_env).fn_sig(*self.tcx);
+ let fn_sig = drop_instance.ty(*self.tcx, self.param_env).fn_sig(*self.tcx);
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
// The drop function takes `*mut T` where `T` is the type being dropped, so get that.
let args = fn_sig.inputs();
.check_ptr_access(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)?
.expect("cannot be a ZST");
let alloc = self.memory.get_raw(vtable.alloc_id)?;
- let size = alloc.read_ptr_sized(self, vtable.offset(pointer_size, self)?)?.not_undef()?;
+ let size = alloc.read_ptr_sized(self, vtable.offset(pointer_size, self)?)?.check_init()?;
let size = u64::try_from(self.force_bits(size, pointer_size)?).unwrap();
let align =
- alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.not_undef()?;
+ alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.check_init()?;
let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap();
if size >= self.tcx.data_layout.obj_size_bound() {
// types below!
if self.ref_tracking_for_consts.is_some() {
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
- let is_bits = value.not_undef().map_or(false, |v| v.is_bits());
+ let is_bits = value.check_init().map_or(false, |v| v.is_bits());
if !is_bits {
throw_validation_failure!(self.path,
{ "{}", value } expected { "initialized plain (non-pointer) bytes" }
ty::FnPtr(_sig) => {
let value = self.ecx.read_scalar(value)?;
let _fn = try_validation!(
- value.not_undef().and_then(|ptr| self.ecx.memory.get_fn(ptr)),
+ value.check_init().and_then(|ptr| self.ecx.memory.get_fn(ptr)),
self.path,
err_ub!(DanglingIntPointer(..)) |
err_ub!(InvalidFunctionPointer(..)) |
}
// At least one value is excluded. Get the bits.
let value = try_validation!(
- value.not_undef(),
+ value.check_init(),
self.path,
err_ub!(InvalidUninitBytes(None)) => { "{}", value }
expected { "something {}", wrapping_range_format(valid_range, max_hi) },
shim::provide(providers);
transform::provide(providers);
monomorphize::partitioning::provide(providers);
+ monomorphize::polymorphize::provide(providers);
providers.const_eval_validated = const_eval::const_eval_validated_provider;
providers.const_eval_raw = const_eval::const_eval_raw_provider;
providers.const_caller_location = const_eval::const_caller_location;
let instance = Instance::mono(tcx, def_id);
// Sanity check whether this ended up being collected accidentally
- debug_assert!(should_monomorphize_locally(tcx, &instance));
+ debug_assert!(should_codegen_locally(tcx, &instance));
- let ty = instance.monomorphic_ty(tcx);
+ let ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
visit_drop_use(tcx, ty, true, starting_point.span, &mut neighbors);
recursion_depth_reset = None;
}
MonoItem::Fn(instance) => {
// Sanity check whether this ended up being collected accidentally
- debug_assert!(should_monomorphize_locally(tcx, &instance));
+ debug_assert!(should_codegen_locally(tcx, &instance));
// Keep track of the monomorphization recursion depth
recursion_depth_reset =
substs,
ty::ClosureKind::FnOnce,
);
- if should_monomorphize_locally(self.tcx, &instance) {
- self.output.push(create_fn_mono_item(instance, span));
+ if should_codegen_locally(self.tcx, &instance) {
+ self.output.push(create_fn_mono_item(self.tcx, instance, span));
}
}
_ => bug!(),
let exchange_malloc_fn_def_id =
tcx.require_lang_item(ExchangeMallocFnLangItem, None);
let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
- if should_monomorphize_locally(tcx, &instance) {
- self.output.push(create_fn_mono_item(instance, span));
+ if should_codegen_locally(tcx, &instance) {
+ self.output.push(create_fn_mono_item(self.tcx, instance, span));
}
}
mir::Rvalue::ThreadLocalRef(def_id) => {
assert!(self.tcx.is_thread_local_static(def_id));
let instance = Instance::mono(self.tcx, def_id);
- if should_monomorphize_locally(self.tcx, &instance) {
+ if should_codegen_locally(self.tcx, &instance) {
trace!("collecting thread-local static {:?}", def_id);
self.output.push(respan(span, MonoItem::Static(def_id)));
}
Ok(val) => collect_const_value(self.tcx, val, self.output),
Err(ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted) => {}
Err(ErrorHandled::TooGeneric) => span_bug!(
- self.tcx.def_span(def.did),
- "collection encountered polymorphic constant",
+ self.body.source_info(location).span,
+ "collection encountered polymorphic constant: {}",
+ substituted_constant
),
}
}
}
mir::InlineAsmOperand::SymStatic { def_id } => {
let instance = Instance::mono(self.tcx, def_id);
- if should_monomorphize_locally(self.tcx, &instance) {
+ if should_codegen_locally(self.tcx, &instance) {
trace!("collecting asm sym static {:?}", def_id);
self.output.push(respan(source, MonoItem::Static(def_id)));
}
output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
- if !should_monomorphize_locally(tcx, &instance) {
+ if !should_codegen_locally(tcx, &instance) {
return;
}
ty::InstanceDef::DropGlue(_, None) => {
// Don't need to emit noop drop glue if we are calling directly.
if !is_direct_call {
- output.push(create_fn_mono_item(instance, source));
+ output.push(create_fn_mono_item(tcx, instance, source));
}
}
ty::InstanceDef::DropGlue(_, Some(_))
| ty::InstanceDef::Item(..)
| ty::InstanceDef::FnPtrShim(..)
| ty::InstanceDef::CloneShim(..) => {
- output.push(create_fn_mono_item(instance, source));
+ output.push(create_fn_mono_item(tcx, instance, source));
}
}
}
// Returns `true` if we should codegen an instance in the local crate.
// Returns `false` if we can just link to the upstream crate and therefore don't
// need a mono item.
-fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
+fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
let def_id = match instance.def {
ty::InstanceDef::Item(def) => def.did,
ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id,
};
if tcx.is_foreign_item(def_id) {
- // Foreign items are always linked against, there's no way of
- // instantiating them.
+ // Foreign items are always linked against, there's no way of instantiating them.
return false;
}
if def_id.is_local() {
- // Local items cannot be referred to locally without
- // monomorphizing them locally.
+ // Local items cannot be referred to locally without monomorphizing them locally.
return true;
}
- if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() {
- // We can link to the item in question, no instance needed
- // in this crate.
+ if tcx.is_reachable_non_generic(def_id)
+ || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some()
+ {
+ // We can link to the item in question, no instance needed in this crate.
return false;
}
}
}
-fn create_fn_mono_item(instance: Instance<'_>, source: Span) -> Spanned<MonoItem<'_>> {
+fn create_fn_mono_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: Instance<'tcx>,
+ source: Span,
+) -> Spanned<MonoItem<'tcx>> {
debug!("create_fn_mono_item(instance={})", instance);
- respan(source, MonoItem::Fn(instance))
+ respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
}
/// Creates a `MonoItem` for each method that is referenced by the vtable for
source: Span,
output: &mut Vec<Spanned<MonoItem<'tcx>>>,
) {
- assert!(
- !trait_ty.needs_subst()
- && !trait_ty.has_escaping_bound_vars()
- && !impl_ty.needs_subst()
- && !impl_ty.has_escaping_bound_vars()
- );
+ assert!(!trait_ty.has_escaping_bound_vars() && !impl_ty.has_escaping_bound_vars());
if let ty::Dynamic(ref trait_ty, ..) = trait_ty.kind {
if let Some(principal) = trait_ty.principal() {
)
.unwrap()
})
- .filter(|&instance| should_monomorphize_locally(tcx, &instance))
- .map(|item| create_fn_mono_item(item, source));
+ .filter(|&instance| should_codegen_locally(tcx, &instance))
+ .map(|item| create_fn_mono_item(tcx, item, source));
output.extend(methods);
}
);
let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty())
- .monomorphic_ty(self.tcx);
+ .ty(self.tcx, ty::ParamEnv::reveal_all());
visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
}
}
debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
let instance = Instance::mono(self.tcx, def_id.to_def_id());
- self.output.push(create_fn_mono_item(instance, DUMMY_SP));
+ self.output.push(create_fn_mono_item(self.tcx, instance, DUMMY_SP));
}
}
.unwrap()
.unwrap();
- self.output.push(create_fn_mono_item(start_instance, DUMMY_SP));
+ self.output.push(create_fn_mono_item(self.tcx, start_instance, DUMMY_SP));
}
}
.unwrap()
.unwrap();
- let mono_item = create_fn_mono_item(instance, DUMMY_SP);
- if mono_item.node.is_instantiable(tcx)
- && should_monomorphize_locally(tcx, &instance)
+ let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP);
+ if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, &instance)
{
output.push(mono_item);
}
GlobalAlloc::Static(def_id) => {
assert!(!tcx.is_thread_local_static(def_id));
let instance = Instance::mono(tcx, def_id);
- if should_monomorphize_locally(tcx, &instance) {
+ if should_codegen_locally(tcx, &instance) {
trace!("collecting static {:?}", def_id);
output.push(dummy_spanned(MonoItem::Static(def_id)));
}
}
}
GlobalAlloc::Function(fn_instance) => {
- if should_monomorphize_locally(tcx, &fn_instance) {
+ if should_codegen_locally(tcx, &fn_instance) {
trace!("collecting {:?} with {:#?}", alloc_id, fn_instance);
- output.push(create_fn_mono_item(fn_instance, DUMMY_SP));
+ output.push(create_fn_mono_item(tcx, fn_instance, DUMMY_SP));
}
}
}
pub mod collector;
pub mod partitioning;
+pub mod polymorphize;
pub fn custom_coerce_unsize_info<'tcx>(
tcx: TyCtxt<'tcx>,
--- /dev/null
+//! Polymorphization Analysis
+//! =========================
+//!
+//! This module implements an analysis of functions, methods and closures to determine which
+//! generic parameters are unused (and eventually, in what ways generic parameters are used - only
+//! for their size, offset of a field, etc.).
+
+use rustc_hir::{def::DefKind, def_id::DefId};
+use rustc_index::bit_set::FiniteBitSet;
+use rustc_middle::mir::{
+ visit::{TyContext, Visitor},
+ Local, LocalDecl, Location,
+};
+use rustc_middle::ty::{
+ self,
+ fold::{TypeFoldable, TypeVisitor},
+ query::Providers,
+ Const, Ty, TyCtxt,
+};
+use rustc_span::symbol::sym;
+use std::convert::TryInto;
+
+/// Provide implementations of queries relating to polymorphization analysis.
+pub fn provide(providers: &mut Providers) {
+ providers.unused_generic_params = unused_generic_params;
+}
+
+/// Determine which generic parameters are used by the function/method/closure represented by
+/// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty`
+/// indicates all parameters are used).
+fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u64> {
+ debug!("unused_generic_params({:?})", def_id);
+
+ if !tcx.sess.opts.debugging_opts.polymorphize {
+ // If polymorphization disabled, then all parameters are used.
+ return FiniteBitSet::new_empty();
+ }
+
+ let generics = tcx.generics_of(def_id);
+ debug!("unused_generic_params: generics={:?}", generics);
+
+ // Exit early when there are no parameters to be unused.
+ if generics.count() == 0 {
+ return FiniteBitSet::new_empty();
+ }
+
+ // Exit early when there is no MIR available.
+ if !tcx.is_mir_available(def_id) {
+ debug!("unused_generic_params: (no mir available) def_id={:?}", def_id);
+ return FiniteBitSet::new_empty();
+ }
+
+ // Create a bitset with N rightmost ones for each parameter.
+ let generics_count: u32 =
+ generics.count().try_into().expect("more generic parameters than can fit into a `u32`");
+ let mut unused_parameters = FiniteBitSet::<u64>::new_empty();
+ unused_parameters.set_range(0..generics_count);
+ debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters);
+ mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters);
+ debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters);
+
+ // Visit MIR and accumululate used generic parameters.
+ let body = tcx.optimized_mir(def_id);
+ let mut vis =
+ UsedGenericParametersVisitor { tcx, def_id, unused_parameters: &mut unused_parameters };
+ vis.visit_body(body);
+ debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters);
+
+ mark_used_by_predicates(tcx, def_id, &mut unused_parameters);
+ debug!("unused_generic_params: (end) unused_parameters={:?}", unused_parameters);
+
+ // Emit errors for debugging and testing if enabled.
+ if !unused_parameters.is_empty() {
+ emit_unused_generic_params_error(tcx, def_id, generics, &unused_parameters);
+ }
+
+ unused_parameters
+}
+
+/// Some parameters are considered used-by-default, such as non-generic parameters and the dummy
+/// generic parameters from closures, this function marks them as used. `leaf_is_closure` should
+/// be `true` if the item that `unused_generic_params` was invoked on is a closure.
+fn mark_used_by_default_parameters<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ generics: &'tcx ty::Generics,
+ unused_parameters: &mut FiniteBitSet<u64>,
+) {
+ if !tcx.is_trait(def_id) && (tcx.is_closure(def_id) || tcx.type_of(def_id).is_generator()) {
+ for param in &generics.params {
+ debug!("mark_used_by_default_parameters: (closure/gen) param={:?}", param);
+ unused_parameters.clear(param.index);
+ }
+ } else {
+ for param in &generics.params {
+ debug!("mark_used_by_default_parameters: (other) param={:?}", param);
+ if let ty::GenericParamDefKind::Lifetime = param.kind {
+ unused_parameters.clear(param.index);
+ }
+ }
+ }
+
+ if let Some(parent) = generics.parent {
+ mark_used_by_default_parameters(tcx, parent, tcx.generics_of(parent), unused_parameters);
+ }
+}
+
+/// Search the predicates on used generic parameters for any unused generic parameters, and mark
+/// those as used.
+fn mark_used_by_predicates<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ unused_parameters: &mut FiniteBitSet<u64>,
+) {
+ let def_id = tcx.closure_base_def_id(def_id);
+
+ let is_self_ty_used = |unused_parameters: &mut FiniteBitSet<u64>, self_ty: Ty<'tcx>| {
+ debug!("unused_generic_params: self_ty={:?}", self_ty);
+ if let ty::Param(param) = self_ty.kind {
+ !unused_parameters.contains(param.index).unwrap_or(false)
+ } else {
+ false
+ }
+ };
+
+ let mark_ty = |unused_parameters: &mut FiniteBitSet<u64>, ty: Ty<'tcx>| {
+ let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters };
+ ty.visit_with(&mut vis);
+ };
+
+ let predicates = tcx.explicit_predicates_of(def_id);
+ debug!("mark_parameters_used_in_predicates: predicates_of={:?}", predicates);
+ for (predicate, _) in predicates.predicates {
+ match predicate.kind() {
+ ty::PredicateKind::Trait(predicate, ..) => {
+ let trait_ref = predicate.skip_binder().trait_ref;
+ if is_self_ty_used(unused_parameters, trait_ref.self_ty()) {
+ for ty in trait_ref.substs.types() {
+ debug!("unused_generic_params: (trait) ty={:?}", ty);
+ mark_ty(unused_parameters, ty);
+ }
+ }
+ }
+ ty::PredicateKind::Projection(predicate, ..) => {
+ let self_ty = predicate.skip_binder().projection_ty.self_ty();
+ if is_self_ty_used(unused_parameters, self_ty) {
+ let ty = predicate.ty();
+ debug!("unused_generic_params: (projection) ty={:?}", ty);
+ mark_ty(unused_parameters, ty.skip_binder());
+ }
+ }
+ _ => (),
+ }
+ }
+}
+
+/// Emit errors for the function annotated by `#[rustc_polymorphize_error]`, labelling each generic
+/// parameter which was unused.
+fn emit_unused_generic_params_error<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ generics: &'tcx ty::Generics,
+ unused_parameters: &FiniteBitSet<u64>,
+) {
+ debug!("emit_unused_generic_params_error: def_id={:?}", def_id);
+ let base_def_id = tcx.closure_base_def_id(def_id);
+ if !tcx.get_attrs(base_def_id).iter().any(|a| a.check_name(sym::rustc_polymorphize_error)) {
+ return;
+ }
+
+ debug!("emit_unused_generic_params_error: unused_parameters={:?}", unused_parameters);
+ let fn_span = match tcx.opt_item_name(def_id) {
+ Some(ident) => ident.span,
+ _ => tcx.def_span(def_id),
+ };
+
+ let mut err = tcx.sess.struct_span_err(fn_span, "item has unused generic parameters");
+
+ let mut next_generics = Some(generics);
+ while let Some(generics) = next_generics {
+ for param in &generics.params {
+ if unused_parameters.contains(param.index).unwrap_or(false) {
+ debug!("emit_unused_generic_params_error: param={:?}", param);
+ let def_span = tcx.def_span(param.def_id);
+ err.span_label(def_span, &format!("generic parameter `{}` is unused", param.name));
+ }
+ }
+
+ next_generics = generics.parent.map(|did| tcx.generics_of(did));
+ }
+
+ err.emit();
+}
+
+/// Visitor used to aggregate generic parameter uses.
+struct UsedGenericParametersVisitor<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ unused_parameters: &'a mut FiniteBitSet<u64>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
+ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
+ debug!("visit_local_decl: local_decl={:?}", local_decl);
+ if local == Local::from_usize(1) {
+ let def_kind = self.tcx.def_kind(self.def_id);
+ if matches!(def_kind, DefKind::Closure | DefKind::Generator) {
+ // Skip visiting the closure/generator that is currently being processed. This only
+ // happens because the first argument to the closure is a reference to itself and
+ // that will call `visit_substs`, resulting in each generic parameter captured being
+ // considered used by default.
+ debug!("visit_local_decl: skipping closure substs");
+ return;
+ }
+ }
+
+ self.super_local_decl(local, local_decl);
+ }
+
+ fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) {
+ c.visit_with(self);
+ }
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) {
+ ty.visit_with(self);
+ }
+}
+
+impl<'a, 'tcx> TypeVisitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
+ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool {
+ debug!("visit_const: c={:?}", c);
+ if !c.has_param_types_or_consts() {
+ return false;
+ }
+
+ match c.val {
+ ty::ConstKind::Param(param) => {
+ debug!("visit_const: param={:?}", param);
+ self.unused_parameters.clear(param.index);
+ false
+ }
+ _ => c.super_visit_with(self),
+ }
+ }
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
+ debug!("visit_ty: ty={:?}", ty);
+ if !ty.has_param_types_or_consts() {
+ return false;
+ }
+
+ match ty.kind {
+ ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
+ debug!("visit_ty: def_id={:?}", def_id);
+ // Avoid cycle errors with generators.
+ if def_id == self.def_id {
+ return false;
+ }
+
+ // Consider any generic parameters used by any closures/generators as used in the
+ // parent.
+ let unused = self.tcx.unused_generic_params(def_id);
+ debug!(
+ "visit_ty: unused_parameters={:?} unused={:?}",
+ self.unused_parameters, unused
+ );
+ for (i, arg) in substs.iter().enumerate() {
+ let i = i.try_into().unwrap();
+ if !unused.contains(i).unwrap_or(false) {
+ arg.visit_with(self);
+ }
+ }
+ debug!("visit_ty: unused_parameters={:?}", self.unused_parameters);
+
+ false
+ }
+ ty::Param(param) => {
+ debug!("visit_ty: param={:?}", param);
+ self.unused_parameters.clear(param.index);
+ false
+ }
+ _ => ty.super_visit_with(self),
+ }
+ }
+}
use rustc_middle::mir::*;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_target::abi::VariantIdx;
use rustc_index::vec::{Idx, IndexVec};
build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id), None)
}
ty::InstanceDef::FnPtrShim(def_id, ty) => {
- // FIXME(eddyb) support generating shims for a "shallow type",
- // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
- // `Foo<Bar>` or `[String]` etc.
- assert!(!ty.needs_subst());
-
let trait_ = tcx.trait_of_item(def_id).unwrap();
let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) {
Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
None,
)
}
- ty::InstanceDef::DropGlue(def_id, ty) => {
- // FIXME(eddyb) support generating shims for a "shallow type",
- // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
- // `Foo<Bar>` or `[String]` etc.
- assert!(!ty.needs_subst());
-
- build_drop_shim(tcx, def_id, ty)
- }
- ty::InstanceDef::CloneShim(def_id, ty) => {
- // FIXME(eddyb) support generating shims for a "shallow type",
- // e.g. `Foo<_>` or `[_]` instead of requiring a fully monomorphic
- // `Foo<Bar>` or `[String]` etc.
- assert!(!ty.needs_subst());
-
- build_clone_shim(tcx, def_id, ty)
- }
+ ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
+ ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
ty::InstanceDef::Virtual(..) => {
bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
}
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
unsafety_check_result: |tcx, def_id| {
- unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
+ if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+ tcx.unsafety_check_result_for_const_arg(def)
+ } else {
+ unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
},
unsafety_check_result_for_const_arg: |tcx, (did, param_did)| {
unsafety_check_result(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx UnsafetyCheckResult {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.unsafety_check_result_for_const_arg((def.did, param_did));
- }
- }
-
debug!("unsafety_violations({:?})", def);
// N.B., this borrow is valid because all the consumers of
use crate::const_eval::error_to_const_error;
use crate::interpret::{
- self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx, LocalState,
- LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer,
- ScalarMaybeUninit, StackPopCleanup,
+ self, compile_time_machine, truncate, AllocId, Allocation, Frame, ImmTy, Immediate, InterpCx,
+ LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy,
+ Pointer, ScalarMaybeUninit, StackPopCleanup,
};
use crate::transform::{MirPass, MirSource};
.predicates
.iter()
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
- if !traits::normalize_and_test_predicates(
+ if traits::impossible_predicates(
tcx,
traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
) {
right: &Operand<'tcx>,
source_info: SourceInfo,
) -> Option<()> {
- let r =
- self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?))?;
+ let r = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(right, None)?));
let l = self.use_ecx(|this| this.ecx.read_immediate(this.ecx.eval_operand(left, None)?));
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
if op == BinOp::Shr || op == BinOp::Shl {
+ let r = r?;
// We need the type of the LHS. We cannot use `place_layout` as that is the type
// of the result, which for checked binops is not the same!
let left_ty = left.ty(&self.local_decls, self.tcx);
}
}
- let l = l?;
-
- // The remaining operators are handled through `overflowing_binary_op`.
- if self.use_ecx(|this| {
- let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
- Ok(overflow)
- })? {
- self.report_assert_as_lint(
- lint::builtin::ARITHMETIC_OVERFLOW,
- source_info,
- "this arithmetic operation will overflow",
- AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
- )?;
+ if let (Some(l), Some(r)) = (l, r) {
+ // The remaining operators are handled through `overflowing_binary_op`.
+ if self.use_ecx(|this| {
+ let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
+ Ok(overflow)
+ })? {
+ self.report_assert_as_lint(
+ lint::builtin::ARITHMETIC_OVERFLOW,
+ source_info,
+ "this arithmetic operation will overflow",
+ AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
+ )?;
+ }
}
-
Some(())
}
+ fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
+ match *operand {
+ Operand::Copy(l) | Operand::Move(l) => {
+ if let Some(value) = self.get_const(l) {
+ if self.should_const_prop(value) {
+ // FIXME(felix91gr): this code only handles `Scalar` cases.
+ // For now, we're not handling `ScalarPair` cases because
+ // doing so here would require a lot of code duplication.
+ // We should hopefully generalize `Operand` handling into a fn,
+ // and use it to do const-prop here and everywhere else
+ // where it makes sense.
+ if let interpret::Operand::Immediate(interpret::Immediate::Scalar(
+ ScalarMaybeUninit::Scalar(scalar),
+ )) = *value
+ {
+ *operand = self.operand_from_scalar(
+ scalar,
+ value.layout.ty,
+ self.source_info.unwrap().span,
+ );
+ }
+ }
+ }
+ }
+ Operand::Constant(_) => (),
+ }
+ }
+
fn const_prop(
&mut self,
rvalue: &Rvalue<'tcx>,
return None;
}
+ if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 {
+ self.eval_rvalue_with_identities(rvalue, place)
+ } else {
+ self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
+ }
+ }
+
+ // Attempt to use albegraic identities to eliminate constant expressions
+ fn eval_rvalue_with_identities(
+ &mut self,
+ rvalue: &Rvalue<'tcx>,
+ place: Place<'tcx>,
+ ) -> Option<()> {
self.use_ecx(|this| {
- trace!("calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})", rvalue, place);
- this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ match rvalue {
+ Rvalue::BinaryOp(op, left, right) | Rvalue::CheckedBinaryOp(op, left, right) => {
+ let l = this.ecx.eval_operand(left, None);
+ let r = this.ecx.eval_operand(right, None);
+
+ let const_arg = match (l, r) {
+ (Ok(x), Err(_)) | (Err(_), Ok(x)) => this.ecx.read_immediate(x)?,
+ (Err(e), Err(_)) => return Err(e),
+ (Ok(_), Ok(_)) => {
+ this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ return Ok(());
+ }
+ };
+
+ let arg_value =
+ this.ecx.force_bits(const_arg.to_scalar()?, const_arg.layout.size)?;
+ let dest = this.ecx.eval_place(place)?;
+
+ match op {
+ BinOp::BitAnd => {
+ if arg_value == 0 {
+ this.ecx.write_immediate(*const_arg, dest)?;
+ }
+ }
+ BinOp::BitOr => {
+ if arg_value == truncate(u128::MAX, const_arg.layout.size)
+ || (const_arg.layout.ty.is_bool() && arg_value == 1)
+ {
+ this.ecx.write_immediate(*const_arg, dest)?;
+ }
+ }
+ BinOp::Mul => {
+ if const_arg.layout.ty.is_integral() && arg_value == 0 {
+ if let Rvalue::CheckedBinaryOp(_, _, _) = rvalue {
+ let val = Immediate::ScalarPair(
+ const_arg.to_scalar()?.into(),
+ Scalar::from_bool(false).into(),
+ );
+ this.ecx.write_immediate(val, dest)?;
+ } else {
+ this.ecx.write_immediate(*const_arg, dest)?;
+ }
+ }
+ }
+ _ => {
+ this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ }
+ }
+ }
+ _ => {
+ this.ecx.eval_rvalue_into_place(rvalue, place)?;
+ }
+ }
+
Ok(())
})
}
}
}
+ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
+ self.super_operand(operand, location);
+
+ // Only const prop copies and moves on `mir_opt_level=3` as doing so
+ // currently increases compile time.
+ if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 {
+ self.propagate_operand(operand)
+ }
+ }
+
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
trace!("visit_constant: {:?}", constant);
self.super_constant(constant, location);
}
}
}
- TerminatorKind::SwitchInt { ref mut discr, switch_ty, .. } => {
- if let Some(value) = self.eval_operand(&discr, source_info) {
- if self.should_const_prop(value) {
- if let ScalarMaybeUninit::Scalar(scalar) =
- self.ecx.read_scalar(value).unwrap()
- {
- *discr = self.operand_from_scalar(scalar, switch_ty, source_info.span);
- }
- }
- }
+ TerminatorKind::SwitchInt { ref mut discr, .. } => {
+ // FIXME: This is currently redundant with `visit_operand`, but sadly
+ // always visiting operands currently causes a perf regression in LLVM codegen, so
+ // `visit_operand` currently only runs for propagates places for `mir_opt_level=3`.
+ self.propagate_operand(discr)
}
- // None of these have Operands to const-propagate
+ // None of these have Operands to const-propagate.
TerminatorKind::Goto { .. }
| TerminatorKind::Resume
| TerminatorKind::Abort
| TerminatorKind::FalseEdge { .. }
| TerminatorKind::FalseUnwind { .. }
| TerminatorKind::InlineAsm { .. } => {}
- // Every argument in our function calls can be const propagated.
- TerminatorKind::Call { ref mut args, .. } => {
- let mir_opt_level = self.tcx.sess.opts.debugging_opts.mir_opt_level;
- // Constant Propagation into function call arguments is gated
- // under mir-opt-level 2, because LLVM codegen gives performance
- // regressions with it.
- if mir_opt_level >= 2 {
- for opr in args {
- /*
- The following code would appear to be incomplete, because
- the function `Operand::place()` returns `None` if the
- `Operand` is of the variant `Operand::Constant`. In this
- context however, that variant will never appear. This is why:
-
- When constructing the MIR, all function call arguments are
- copied into `Locals` of `LocalKind::Temp`. At least, all arguments
- that are not unsized (Less than 0.1% are unsized. See #71170
- to learn more about those).
-
- This means that, conversely, all `Operands` found as function call
- arguments are of the variant `Operand::Copy`. This allows us to
- simplify our handling of `Operands` in this case.
- */
- if let Some(l) = opr.place() {
- if let Some(value) = self.get_const(l) {
- if self.should_const_prop(value) {
- // FIXME(felix91gr): this code only handles `Scalar` cases.
- // For now, we're not handling `ScalarPair` cases because
- // doing so here would require a lot of code duplication.
- // We should hopefully generalize `Operand` handling into a fn,
- // and use it to do const-prop here and everywhere else
- // where it makes sense.
- if let interpret::Operand::Immediate(
- interpret::Immediate::Scalar(ScalarMaybeUninit::Scalar(
- scalar,
- )),
- ) = *value
- {
- *opr = self.operand_from_scalar(
- scalar,
- value.layout.ty,
- source_info.span,
- );
- }
- }
- }
- }
- }
- }
- }
+ // Every argument in our function calls have already been propagated in `visit_operand`.
+ //
+ // NOTE: because LLVM codegen gives performance regressions with it, so this is gated
+ // on `mir_opt_level=3`.
+ TerminatorKind::Call { .. } => {}
}
// We remove all Locals which are restricted in propagation to their containing blocks and
// which were modified in the current block.
- // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`
+ // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
for &local in locals.iter() {
Self::remove_const(&mut self.ecx, local);
*providers = Providers {
mir_keys,
mir_const,
- mir_const_qualif: |tcx, did| {
- mir_const_qualif(tcx, ty::WithOptConstParam::unknown(did.expect_local()))
+ mir_const_qualif: |tcx, def_id| {
+ let def_id = def_id.expect_local();
+ if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+ tcx.mir_const_qualif_const_arg(def)
+ } else {
+ mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
},
mir_const_qualif_const_arg: |tcx, (did, param_did)| {
mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
optimized_mir_of_const_arg,
is_mir_available,
promoted_mir: |tcx, def_id| {
- promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id.expect_local()))
+ let def_id = def_id.expect_local();
+ if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
+ tcx.promoted_mir_of_const_arg(def)
+ } else {
+ promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id))
+ }
},
promoted_mir_of_const_arg: |tcx, (did, param_did)| {
promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
}
fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_const_qualif_const_arg((def.did, param_did));
- }
- }
-
let const_kind = tcx.hir().body_const_context(def.did);
// No need to const-check a non-const `fn`.
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx Steal<Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_const(ty::WithOptConstParam { const_param_did, ..def });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_const(def);
}
// Unsafety check uses the raw mir, so make sure it is run.
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_validated(ty::WithOptConstParam { const_param_did, ..def });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_validated(def);
}
// Ensure that we compute the `mir_const_qualif` for constants at
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx Steal<Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam {
- const_param_did,
- ..def
- });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_drops_elaborated_and_const_checked(def);
}
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
let did = did.expect_local();
- if let Some(param_did) = tcx.opt_const_param_of(did) {
- tcx.optimized_mir_of_const_arg((did, param_did))
+ if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
+ tcx.optimized_mir_of_const_arg(def)
} else {
tcx.arena.alloc(inner_optimized_mir(tcx, ty::WithOptConstParam::unknown(did)))
}
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let Some(param_did) = tcx.opt_const_param_of(def.did) {
- return tcx.promoted_mir_of_const_arg((def.did, param_did));
- }
- }
-
if tcx.is_constructor(def.did.to_def_id()) {
return tcx.arena.alloc(IndexVec::new());
}
use crate::hair::*;
use rustc_ast::ast::InlineAsmOptions;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
let block_and = match expr.kind {
ExprKind::Scope { region_scope, lint_level, value } => {
let region_scope = (region_scope, source_info);
- this.in_scope(region_scope, lint_level, |this| this.into(destination, block, value))
+ ensure_sufficient_stack(|| {
+ this.in_scope(region_scope, lint_level, |this| {
+ this.into(destination, block, value)
+ })
+ })
}
ExprKind::Block { body: ast_block } => {
this.ast_block(destination, block, ast_block, source_info)
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx ty::steal::Steal<Body<'tcx>> {
- if def.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(def.did) {
- return tcx.mir_built(ty::WithOptConstParam { const_param_did, ..def });
- }
+ if let Some(def) = def.try_upgrade(tcx) {
+ return tcx.mir_built(def);
}
tcx.alloc_steal_mir(mir_build(tcx, def))
let pats = cx.pattern_arena.alloc_from_iter((0..n).filter_map(|i| {
let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
- let scalar = scalar.not_undef().ok()?;
+ let scalar = scalar.check_init().ok()?;
let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
let pattern = Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
Some(pattern)
fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
let mut ty = self.typeck_results.node_type(pat.hir_id);
- if let ty::Error(_) = ty.kind {
- // Avoid ICEs (e.g., #50577 and #50585).
- return Pat { span: pat.span, ty, kind: Box::new(PatKind::Wild) };
- }
-
let kind = match pat.kind {
hir::PatKind::Wild => PatKind::Wild,
use super::ty::AllowPlus;
use super::{BlockMode, Parser, PathStyle, SemiColonMode, SeqSep, TokenExpectType, TokenType};
-use rustc_ast::ast::{self, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind, Item, Param};
-use rustc_ast::ast::{AttrVec, ItemKind, Mutability, Pat, PatKind, PathSegment, QSelf, Ty, TyKind};
+use rustc_ast::ast::{
+ self, AngleBracketedArgs, AttrVec, BinOpKind, BindingMode, BlockCheckMode, Expr, ExprKind,
+ Item, ItemKind, Mutability, Param, Pat, PatKind, PathSegment, QSelf, Ty, TyKind,
+};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Lit, LitKind, TokenKind};
use rustc_ast::util::parser::AssocOp;
false
}
+ /// Check if a method call with an intended turbofish has been written without surrounding
+ /// angle brackets.
+ pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
+ if token::ModSep == self.token.kind && segment.args.is_none() {
+ let snapshot = self.clone();
+ self.bump();
+ let lo = self.token.span;
+ match self.parse_angle_args() {
+ Ok(args) => {
+ let span = lo.to(self.prev_token.span);
+ // Detect trailing `>` like in `x.collect::Vec<_>>()`.
+ let mut trailing_span = self.prev_token.span.shrink_to_hi();
+ while self.token.kind == token::BinOp(token::Shr)
+ || self.token.kind == token::Gt
+ {
+ trailing_span = trailing_span.to(self.token.span);
+ self.bump();
+ }
+ if self.token.kind == token::OpenDelim(token::Paren) {
+ // Recover from bad turbofish: `foo.collect::Vec<_>()`.
+ let args = AngleBracketedArgs { args, span }.into();
+ segment.args = args;
+
+ self.struct_span_err(
+ span,
+ "generic parameters without surrounding angle brackets",
+ )
+ .multipart_suggestion(
+ "surround the type parameters with angle brackets",
+ vec![
+ (span.shrink_to_lo(), "<".to_string()),
+ (trailing_span, ">".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ )
+ .emit();
+ } else {
+ // This doesn't look like an invalid turbofish, can't recover parse state.
+ *self = snapshot;
+ }
+ }
+ Err(mut err) => {
+ // We could't parse generic parameters, unlikely to be a turbofish. Rely on
+ // generic parse error instead.
+ err.cancel();
+ *self = snapshot;
+ }
+ }
+ }
+ }
+
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
/// parenthesising the leftmost comparison.
}
let fn_span_lo = self.token.span;
- let segment = self.parse_path_segment(PathStyle::Expr)?;
+ let mut segment = self.parse_path_segment(PathStyle::Expr)?;
self.check_trailing_angle_brackets(&segment, &[&token::OpenDelim(token::Paren)]);
+ self.check_turbofish_missing_angle_brackets(&mut segment);
if self.check(&token::OpenDelim(token::Paren)) {
// Method call `expr.f()`
/// Parses (possibly empty) list of generic arguments / associated item constraints,
/// possibly including trailing comma.
- fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
+ pub(super) fn parse_angle_args(&mut self) -> PResult<'a, Vec<AngleBracketedArg>> {
let mut args = Vec::new();
while let Some(arg) = self.parse_angle_arg()? {
args.push(arg);
) where
F: FnOnce(&mut Self),
{
+ debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
+ let mut did_error = false;
if !self.tcx.features().staged_api {
- self.forbid_staged_api_attrs(hir_id, attrs, item_sp, kind, visit_children);
- return;
+ did_error = self.forbid_staged_api_attrs(hir_id, attrs);
}
- // This crate explicitly wants staged API.
+ let depr = if did_error {
+ None
+ } else {
+ attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp)
+ };
+ let mut is_deprecated = false;
+ if let Some(depr) = &depr {
+ is_deprecated = true;
- debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs);
- if let Some(..) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
- self.tcx.sess.span_err(
- item_sp,
- "`#[deprecated]` cannot be used in staged API; \
- use `#[rustc_deprecated]` instead",
+ if kind == AnnotationKind::Prohibited {
+ self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
+ }
+
+ // `Deprecation` is just two pointers, no need to intern it
+ let depr_entry = DeprecationEntry::local(depr.clone(), hir_id);
+ self.index.depr_map.insert(hir_id, depr_entry);
+ } else if let Some(parent_depr) = self.parent_depr.clone() {
+ is_deprecated = true;
+ info!("tagging child {:?} as deprecated from parent", hir_id);
+ self.index.depr_map.insert(hir_id, parent_depr);
+ }
+
+ if self.tcx.features().staged_api {
+ if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) {
+ self.tcx.sess.span_err(
+ item_sp,
+ "`#[deprecated]` cannot be used in staged API; \
+ use `#[rustc_deprecated]` instead",
+ );
+ }
+ } else {
+ self.recurse_with_stability_attrs(
+ depr.map(|d| DeprecationEntry::local(d, hir_id)),
+ None,
+ None,
+ visit_children,
);
+ return;
}
let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
}
}
- let stab = stab.map(|mut stab| {
+ if depr.as_ref().map_or(false, |d| d.is_since_rustc_version) {
+ if stab.is_none() {
+ struct_span_err!(
+ self.tcx.sess,
+ item_sp,
+ E0549,
+ "rustc_deprecated attribute must be paired with \
+ either stable or unstable attribute"
+ )
+ .emit();
+ }
+ }
+
+ let stab = stab.map(|stab| {
// Error if prohibited, or can't inherit anything from a container.
if kind == AnnotationKind::Prohibited
- || (kind == AnnotationKind::Container
- && stab.level.is_stable()
- && stab.rustc_depr.is_none())
+ || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
{
self.tcx.sess.span_err(item_sp, "This stability annotation is useless");
}
debug!("annotate: found {:?}", stab);
- // If parent is deprecated and we're not, inherit this by merging
- // deprecated_since and its reason.
- if let Some(parent_stab) = self.parent_stab {
- if parent_stab.rustc_depr.is_some() && stab.rustc_depr.is_none() {
- stab.rustc_depr = parent_stab.rustc_depr
- }
- }
-
let stab = self.tcx.intern_stability(stab);
// Check if deprecated_since < stable_since. If it is,
// this is *almost surely* an accident.
- if let (
- &Some(attr::RustcDeprecation { since: dep_since, .. }),
- &attr::Stable { since: stab_since },
- ) = (&stab.rustc_depr, &stab.level)
+ if let (&Some(dep_since), &attr::Stable { since: stab_since }) =
+ (&depr.as_ref().and_then(|d| d.since), &stab.level)
{
// Explicit version of iter::order::lt to handle parse errors properly
for (dep_v, stab_v) in
}
}
- self.recurse_with_stability_attrs(stab, const_stab, visit_children);
+ self.recurse_with_stability_attrs(
+ depr.map(|d| DeprecationEntry::local(d, hir_id)),
+ stab,
+ const_stab,
+ visit_children,
+ );
}
fn recurse_with_stability_attrs(
&mut self,
+ depr: Option<DeprecationEntry>,
stab: Option<&'tcx Stability>,
const_stab: Option<&'tcx ConstStability>,
f: impl FnOnce(&mut Self),
) {
// These will be `Some` if this item changes the corresponding stability attribute.
+ let mut replaced_parent_depr = None;
let mut replaced_parent_stab = None;
let mut replaced_parent_const_stab = None;
+ if let Some(depr) = depr {
+ replaced_parent_depr = Some(replace(&mut self.parent_depr, Some(depr)));
+ }
if let Some(stab) = stab {
replaced_parent_stab = Some(replace(&mut self.parent_stab, Some(stab)));
}
f(self);
+ if let Some(orig_parent_depr) = replaced_parent_depr {
+ self.parent_depr = orig_parent_depr;
+ }
if let Some(orig_parent_stab) = replaced_parent_stab {
self.parent_stab = orig_parent_stab;
}
}
}
- fn forbid_staged_api_attrs(
- &mut self,
- hir_id: HirId,
- attrs: &[Attribute],
- item_sp: Span,
- kind: AnnotationKind,
- visit_children: impl FnOnce(&mut Self),
- ) {
+ // returns true if an error occurred, used to suppress some spurious errors
+ fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool {
// Emit errors for non-staged-api crates.
let unstable_attrs = [
sym::unstable,
sym::rustc_const_unstable,
sym::rustc_const_stable,
];
+ let mut has_error = false;
for attr in attrs {
let name = attr.name_or_empty();
if unstable_attrs.contains(&name) {
"stability attributes may not be used outside of the standard library",
)
.emit();
+ has_error = true;
}
}
}
}
- if let Some(depr) = attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp) {
- if kind == AnnotationKind::Prohibited {
- self.tcx.sess.span_err(item_sp, "This deprecation annotation is useless");
- }
-
- // `Deprecation` is just two pointers, no need to intern it
- let depr_entry = DeprecationEntry::local(depr, hir_id);
- self.index.depr_map.insert(hir_id, depr_entry.clone());
-
- let orig_parent_depr = replace(&mut self.parent_depr, Some(depr_entry));
- visit_children(self);
- self.parent_depr = orig_parent_depr;
- } else if let Some(parent_depr) = self.parent_depr.clone() {
- self.index.depr_map.insert(hir_id, parent_depr);
- visit_children(self);
- } else {
- visit_children(self);
- }
+ has_error
}
}
is_soft: false,
},
feature: sym::rustc_private,
- rustc_depr: None,
});
annotator.parent_stab = Some(stability);
}
use rustc_span::hygiene::{ExpnId, MacroKind};
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
use log::debug;
use std::cell::Cell;
parent,
kind,
def_id,
- ExpnId::root(),
- DUMMY_SP,
+ self.cstore().module_expansion_untracked(def_id, &self.session),
+ self.cstore().get_span_untracked(def_id, &self.session),
));
self.extern_module_map.insert(def_id, module);
module
fn build_reduced_graph_for_external_crate_res(&mut self, child: Export<NodeId>) {
let parent = self.parent_scope.module;
let Export { ident, res, vis, span } = child;
- let expansion = ExpnId::root(); // FIXME(jseyfried) intercrate hygiene
+ let expansion = self.parent_scope.expansion;
// Record primary definitions.
match res {
Res::Def(kind @ (DefKind::Mod | DefKind::Enum | DefKind::Trait), def_id) => {
pat_src: PatternSource,
bindings: &mut SmallVec<[(PatBoundCtx, FxHashSet<Ident>); 1]>,
) {
+ let is_tuple_struct_pat = matches!(pat.kind, PatKind::TupleStruct(_, _));
+
// Visit all direct subpatterns of this pattern.
pat.walk(&mut |pat| {
debug!("resolve_pattern pat={:?} node={:?}", pat, pat.kind);
match pat.kind {
PatKind::Ident(bmode, ident, ref sub) => {
- // First try to resolve the identifier as some existing entity,
- // then fall back to a fresh binding.
- let has_sub = sub.is_some();
- let res = self
- .try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
- .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings));
- self.r.record_partial_res(pat.id, PartialRes::new(res));
+ if is_tuple_struct_pat && sub.as_ref().filter(|p| p.is_rest()).is_some() {
+ // In tuple struct patterns ignore the invalid `ident @ ...`.
+ // It will be handled as an error by the AST lowering.
+ self.r
+ .session
+ .delay_span_bug(ident.span, "ident in tuple pattern is invalid");
+ } else {
+ // First try to resolve the identifier as some existing entity,
+ // then fall back to a fresh binding.
+ let has_sub = sub.is_some();
+ let res = self
+ .try_resolve_as_non_binding(pat_src, pat, bmode, ident, has_sub)
+ .unwrap_or_else(|| {
+ self.fresh_binding(ident, pat.id, pat_src, bindings)
+ });
+ self.r.record_partial_res(pat.id, PartialRes::new(res));
+ }
}
PatKind::TupleStruct(ref path, ..) => {
self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span));
err.emit();
}
+ // FIXME(const_generics): This patches over a ICE caused by non-'static lifetimes in const
+ // generics. We are disallowing this until we can decide on how we want to handle non-'static
+ // lifetimes in const generics. See issue #74052 for discussion.
+ crate fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &hir::Lifetime) {
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ lifetime_ref.span,
+ E0771,
+ "use of non-static lifetime `{}` in const generic",
+ lifetime_ref
+ );
+ err.note(
+ "for more information, see issue #74052 \
+ <https://github.com/rust-lang/rust/issues/74052>",
+ );
+ err.emit();
+ }
+
crate fn is_trait_ref_fn_scope(&mut self, trait_ref: &'tcx hir::PolyTraitRef<'tcx>) -> bool {
if let def::Res::Def(_, did) = trait_ref.trait_ref.path.res {
if [
/// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax.
is_in_fn_syntax: bool,
+ is_in_const_generic: bool,
+
/// List of labels in the function/method currently under analysis.
labels_in_fn: Vec<Ident>,
scope: ROOT_SCOPE,
trait_ref_hack: false,
is_in_fn_syntax: false,
+ is_in_const_generic: false,
labels_in_fn: vec![],
xcrate_object_lifetime_defaults: Default::default(),
lifetime_uses: &mut Default::default(),
self.insert_lifetime(lifetime_ref, Region::Static);
return;
}
+ if self.is_in_const_generic && lifetime_ref.name != LifetimeName::Error {
+ self.emit_non_static_lt_in_const_generic_error(lifetime_ref);
+ return;
+ }
self.resolve_lifetime_ref(lifetime_ref);
}
}
}
GenericParamKind::Const { ref ty, .. } => {
+ let was_in_const_generic = self.is_in_const_generic;
+ self.is_in_const_generic = true;
walk_list!(self, visit_param_bound, param.bounds);
self.visit_ty(&ty);
+ self.is_in_const_generic = was_in_const_generic;
}
}
}
}
GenericParamKind::Const { .. } => {
// Generic consts don't impose any constraints.
- None
+ //
+ // We still store a dummy value here to allow generic parameters
+ // in an arbitrary order.
+ Some(Set1::Empty)
}
})
.collect()
scope: &wrap_scope,
trait_ref_hack: self.trait_ref_hack,
is_in_fn_syntax: self.is_in_fn_syntax,
+ is_in_const_generic: self.is_in_const_generic,
labels_in_fn,
xcrate_object_lifetime_defaults,
lifetime_uses,
///
/// Multiple bindings in the same module can have the same key (in a valid
/// program) if all but one of them come from glob imports.
-#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
struct BindingKey {
/// The identifier for the binding, aways the `normalize_to_macros_2_0` version of the
/// identifier.
}
fn resolve_crate_root(&mut self, ident: Ident) -> Module<'a> {
+ debug!("resolve_crate_root({:?})", ident);
let mut ctxt = ident.span.ctxt();
let mark = if ident.name == kw::DollarCrate {
// When resolving `$crate` from a `macro_rules!` invoked in a `macro`,
// definitions actually produced by `macro` and `macro` definitions produced by
// `macro_rules!`, but at least such configurations are not stable yet.
ctxt = ctxt.normalize_to_macro_rules();
+ debug!(
+ "resolve_crate_root: marks={:?}",
+ ctxt.marks().into_iter().map(|(i, t)| (i.expn_data(), t)).collect::<Vec<_>>()
+ );
let mut iter = ctxt.marks().into_iter().rev().peekable();
let mut result = None;
// Find the last opaque mark from the end if it exists.
break;
}
}
+ debug!(
+ "resolve_crate_root: found opaque mark {:?} {:?}",
+ result,
+ result.map(|r| r.expn_data())
+ );
// Then find the last semi-transparent mark from the end if it exists.
for (mark, transparency) in iter {
if transparency == Transparency::SemiTransparent {
break;
}
}
+ debug!(
+ "resolve_crate_root: found semi-transparent mark {:?} {:?}",
+ result,
+ result.map(|r| r.expn_data())
+ );
result
} else {
+ debug!("resolve_crate_root: not DollarCrate");
ctxt = ctxt.normalize_to_macros_2_0();
ctxt.adjust(ExpnId::root())
};
let module = match mark {
Some(def) => self.macro_def_scope(def),
- None => return self.graph_root,
+ None => {
+ debug!(
+ "resolve_crate_root({:?}): found no mark (ident.span = {:?})",
+ ident, ident.span
+ );
+ return self.graph_root;
+ }
};
- self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.normal_ancestor_id })
+ let module = self.get_module(DefId { index: CRATE_DEF_INDEX, ..module.normal_ancestor_id });
+ debug!(
+ "resolve_crate_root({:?}): got module {:?} ({:?}) (ident.span = {:?})",
+ ident,
+ module,
+ module.kind.name(),
+ ident.span
+ );
+ module
}
fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Module<'a> {
);
}
}
- if let Some(depr) = &stability.rustc_depr {
- let path = pprust::path_to_string(path);
- let (message, lint) = stability::rustc_deprecation_message(depr, &path);
- stability::early_report_deprecation(
- &mut self.lint_buffer,
- &message,
- depr.suggestion,
- lint,
- span,
- );
- }
}
if let Some(depr) = &ext.deprecation {
let path = pprust::path_to_string(&path);
let (message, lint) = stability::deprecation_message(depr, &path);
- stability::early_report_deprecation(&mut self.lint_buffer, &message, None, lint, span);
+ stability::early_report_deprecation(
+ &mut self.lint_buffer,
+ &message,
+ depr.suggestion,
+ lint,
+ span,
+ );
}
}
let callee = span.source_callee()?;
let mac_name = match callee.kind {
- ExpnKind::Macro(mac_kind, name) => match mac_kind {
+ ExpnKind::Macro(kind, name) => match kind {
MacroKind::Bang => name,
// Ignore attribute macros, their spans are usually mangled
Symbols,
}
-/// The different settings that the `-Z control-flow-guard` flag can have.
+/// The different settings that the `-C control-flow-guard` flag can have.
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub enum CFGuard {
/// Do not emit Control Flow Guard metadata or checks.
"choose the code model to use (`rustc --print code-models` for details)"),
codegen_units: Option<usize> = (None, parse_opt_uint, [UNTRACKED],
"divide crate into N units to optimize in parallel"),
+ control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
+ "use Windows Control Flow Guard (default: no)"),
debug_assertions: Option<bool> = (None, parse_opt_bool, [TRACKED],
"explicitly enable the `cfg(debug_assertions)` directive"),
debuginfo: usize = (0, parse_uint, [TRACKED],
"enable the experimental Chalk-based trait solving engine"),
codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
"the backend to use"),
- control_flow_guard: CFGuard = (CFGuard::Disabled, parse_cfguard, [TRACKED],
- "use Windows Control Flow Guard (default: no)"),
crate_attr: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
"inject the given attribute in the crate"),
debug_macros: bool = (false, parse_bool, [TRACKED],
(default: PLT is disabled if full relro is enabled)"),
polonius: bool = (false, parse_bool, [UNTRACKED],
"enable polonius-based borrow-checker (default: no)"),
+ polymorphize: bool = (false, parse_bool, [TRACKED],
+ "perform polymorphization analysis"),
pre_link_arg: (/* redirected to pre_link_args */) = ((), parse_string_push, [UNTRACKED],
"a single extra argument to prepend the linker invocation (can be used several times)"),
pre_link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
self.opts.debugging_opts.asm_comments
}
pub fn verify_llvm_ir(&self) -> bool {
- self.opts.debugging_opts.verify_llvm_ir || cfg!(always_verify_llvm_ir)
+ self.opts.debugging_opts.verify_llvm_ir || option_env!("RUSTC_VERIFY_LLVM_IR").is_some()
}
pub fn borrowck_stats(&self) -> bool {
self.opts.debugging_opts.borrowck_stats
hcx.hash_def_id(*self, hasher)
}
}
+
+impl<CTX: HashStableContext> HashStable<CTX> for CrateNum {
+ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+ hcx.hash_crate_num(*self, hasher)
+ }
+}
// because getting it wrong can lead to nested `HygieneData::with` calls that
// trigger runtime aborts. (Fortunately these are obvious and easy to fix.)
-use crate::def_id::{DefId, CRATE_DEF_INDEX};
use crate::edition::Edition;
use crate::symbol::{kw, sym, Symbol};
use crate::SESSION_GLOBALS;
use crate::{Span, DUMMY_SP};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
+use crate::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use log::*;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::sync::{Lock, Lrc};
use rustc_macros::HashStable_Generic;
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use rustc_serialize::{
+ Decodable, Decoder, Encodable, Encoder, UseSpecializedDecodable, UseSpecializedEncodable,
+};
use std::fmt;
/// A `SyntaxContext` represents a chain of pairs `(ExpnId, Transparency)` named "marks".
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SyntaxContext(u32);
-#[derive(Debug)]
-struct SyntaxContextData {
+#[derive(Debug, RustcEncodable, RustcDecodable, Clone)]
+pub struct SyntaxContextData {
outer_expn: ExpnId,
outer_transparency: Transparency,
parent: SyntaxContext,
Opaque,
}
+pub(crate) const NUM_TRANSPARENCIES: usize = 3;
+
impl ExpnId {
pub fn fresh(expn_data: Option<ExpnData>) -> Self {
HygieneData::with(|data| data.fresh_expn(expn_data))
}
#[inline]
- pub fn set_expn_data(self, expn_data: ExpnData) {
+ pub fn set_expn_data(self, mut expn_data: ExpnData) {
HygieneData::with(|data| {
let old_expn_data = &mut data.expn_data[self.0 as usize];
assert!(old_expn_data.is_none(), "expansion data is reset for an expansion ID");
+ expn_data.orig_id.replace(self.as_u32()).expect_none("orig_id should be None");
*old_expn_data = Some(expn_data);
})
}
}
#[derive(Debug)]
-crate struct HygieneData {
+pub struct HygieneData {
/// Each expansion should have an associated expansion data, but sometimes there's a delay
/// between creation of an expansion ID and obtaining its data (e.g. macros are collected
/// first and then resolved later), so we use an `Option` here.
impl HygieneData {
crate fn new(edition: Edition) -> Self {
+ let mut root_data = ExpnData::default(
+ ExpnKind::Root,
+ DUMMY_SP,
+ edition,
+ Some(DefId::local(CRATE_DEF_INDEX)),
+ );
+ root_data.orig_id = Some(0);
+
HygieneData {
- expn_data: vec![Some(ExpnData::default(
- ExpnKind::Root,
- DUMMY_SP,
- edition,
- Some(DefId::local(CRATE_DEF_INDEX)),
- ))],
+ expn_data: vec![Some(root_data)],
syntax_context_data: vec![SyntaxContextData {
outer_expn: ExpnId::root(),
outer_transparency: Transparency::Opaque,
}
}
- fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
+ pub fn with<T, F: FnOnce(&mut HygieneData) -> T>(f: F) -> T {
SESSION_GLOBALS.with(|session_globals| f(&mut *session_globals.hygiene_data.borrow_mut()))
}
- fn fresh_expn(&mut self, expn_data: Option<ExpnData>) -> ExpnId {
+ fn fresh_expn(&mut self, mut expn_data: Option<ExpnData>) -> ExpnId {
+ let raw_id = self.expn_data.len() as u32;
+ if let Some(data) = expn_data.as_mut() {
+ data.orig_id.replace(raw_id).expect_none("orig_id should be None");
+ }
self.expn_data.push(expn_data);
- ExpnId(self.expn_data.len() as u32 - 1)
+ ExpnId(raw_id)
}
fn expn_data(&self, expn_id: ExpnId) -> &ExpnData {
fn marks(&self, mut ctxt: SyntaxContext) -> Vec<(ExpnId, Transparency)> {
let mut marks = Vec::new();
while ctxt != SyntaxContext::root() {
+ debug!("marks: getting parent of {:?}", ctxt);
marks.push(self.outer_mark(ctxt));
ctxt = self.parent_ctxt(ctxt);
}
}
fn walk_chain(&self, mut span: Span, to: SyntaxContext) -> Span {
+ debug!("walk_chain({:?}, {:?})", span, to);
+ debug!("walk_chain: span ctxt = {:?}", span.ctxt());
while span.from_expansion() && span.ctxt() != to {
- span = self.expn_data(self.outer_expn(span.ctxt())).call_site;
+ let outer_expn = self.outer_expn(span.ctxt());
+ debug!("walk_chain({:?}): outer_expn={:?}", span, outer_expn);
+ let expn_data = self.expn_data(outer_expn);
+ debug!("walk_chain({:?}): expn_data={:?}", span, expn_data);
+ span = expn_data.call_site;
}
span
}
/// The `DefId` of the macro being invoked,
/// if this `ExpnData` corresponds to a macro invocation
pub macro_def_id: Option<DefId>,
+ /// The crate that originally created this `ExpnData. During
+ /// metadata serialization, we only encode `ExpnData`s that were
+ /// created locally - when our serialized metadata is decoded,
+ /// foreign `ExpnId`s will have their `ExpnData` looked up
+ /// from the crate specified by `Crate
+ pub krate: CrateNum,
+ /// The raw that this `ExpnData` had in its original crate.
+ /// An `ExpnData` can be created before being assigned an `ExpnId`,
+ /// so this might be `None` until `set_expn_data` is called
+ // This is used only for serialization/deserialization purposes:
+ // two `ExpnData`s that differ only in their `orig_id` should
+ // be considered equivalent.
+ #[stable_hasher(ignore)]
+ pub orig_id: Option<u32>,
}
+// This would require special handling of `orig_id` and `parent`
+impl !PartialEq for ExpnData {}
+
impl ExpnData {
/// Constructs expansion data with default properties.
pub fn default(
local_inner_macros: false,
edition,
macro_def_id,
+ krate: LOCAL_CRATE,
+ orig_id: None,
}
}
}
/// The kind of AST transform.
-#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable, HashStable_Generic)]
+#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable, HashStable_Generic)]
pub enum AstPass {
StdImports,
TestHarness,
}
}
-impl Encodable for ExpnId {
- fn encode<E: Encoder>(&self, _: &mut E) -> Result<(), E::Error> {
- Ok(()) // FIXME(jseyfried) intercrate hygiene
+impl UseSpecializedEncodable for ExpnId {}
+impl UseSpecializedDecodable for ExpnId {}
+
+#[derive(Default)]
+pub struct HygieneEncodeContext {
+ /// All `SyntaxContexts` for which we have writen `SyntaxContextData` into crate metadata.
+ /// This is `None` after we finish encoding `SyntaxContexts`, to ensure
+ /// that we don't accidentally try to encode any more `SyntaxContexts`
+ serialized_ctxts: Lock<FxHashSet<SyntaxContext>>,
+ /// The `SyntaxContexts` that we have serialized (e.g. as a result of encoding `Spans`)
+ /// in the most recent 'round' of serializnig. Serializing `SyntaxContextData`
+ /// may cause us to serialize more `SyntaxContext`s, so serialize in a loop
+ /// until we reach a fixed point.
+ latest_ctxts: Lock<FxHashSet<SyntaxContext>>,
+
+ serialized_expns: Lock<FxHashSet<ExpnId>>,
+
+ latest_expns: Lock<FxHashSet<ExpnId>>,
+}
+
+impl HygieneEncodeContext {
+ pub fn encode<
+ T,
+ R,
+ F: FnMut(&mut T, u32, &SyntaxContextData) -> Result<(), R>,
+ G: FnMut(&mut T, u32, &ExpnData) -> Result<(), R>,
+ >(
+ &self,
+ encoder: &mut T,
+ mut encode_ctxt: F,
+ mut encode_expn: G,
+ ) -> Result<(), R> {
+ // When we serialize a `SyntaxContextData`, we may end up serializing
+ // a `SyntaxContext` that we haven't seen before
+ while !self.latest_ctxts.lock().is_empty() || !self.latest_expns.lock().is_empty() {
+ debug!(
+ "encode_hygiene: Serializing a round of {:?} SyntaxContextDatas: {:?}",
+ self.latest_ctxts.lock().len(),
+ self.latest_ctxts
+ );
+
+ // Consume the current round of SyntaxContexts.
+ // Drop the lock() temporary early
+ let latest_ctxts = { std::mem::take(&mut *self.latest_ctxts.lock()) };
+
+ // It's fine to iterate over a HashMap, because the serialization
+ // of the table that we insert data into doesn't depend on insertion
+ // order
+ for_all_ctxts_in(latest_ctxts.into_iter(), |(index, ctxt, data)| {
+ if self.serialized_ctxts.lock().insert(ctxt) {
+ encode_ctxt(encoder, index, data)?;
+ }
+ Ok(())
+ })?;
+
+ let latest_expns = { std::mem::take(&mut *self.latest_expns.lock()) };
+
+ for_all_expns_in(latest_expns.into_iter(), |index, expn, data| {
+ if self.serialized_expns.lock().insert(expn) {
+ encode_expn(encoder, index, data)?;
+ }
+ Ok(())
+ })?;
+ }
+ debug!("encode_hygiene: Done serializing SyntaxContextData");
+ Ok(())
+ }
+}
+
+#[derive(Default)]
+/// Additional information used to assist in decoding hygiene data
+pub struct HygieneDecodeContext {
+ // Maps serialized `SyntaxContext` ids to a `SyntaxContext` in the current
+ // global `HygieneData`. When we deserialize a `SyntaxContext`, we need to create
+ // a new id in the global `HygieneData`. This map tracks the ID we end up picking,
+ // so that multiple occurences of the same serialized id are decoded to the same
+ // `SyntaxContext`
+ remapped_ctxts: Lock<Vec<Option<SyntaxContext>>>,
+ // The same as `remapepd_ctxts`, but for `ExpnId`s
+ remapped_expns: Lock<Vec<Option<ExpnId>>>,
+}
+
+pub fn decode_expn_id<
+ 'a,
+ D: Decoder,
+ F: FnOnce(&mut D, u32) -> Result<ExpnData, D::Error>,
+ G: FnOnce(CrateNum) -> &'a HygieneDecodeContext,
+>(
+ d: &mut D,
+ mode: ExpnDataDecodeMode<'a, G>,
+ decode_data: F,
+) -> Result<ExpnId, D::Error> {
+ let index = u32::decode(d)?;
+ let context = match mode {
+ ExpnDataDecodeMode::IncrComp(context) => context,
+ ExpnDataDecodeMode::Metadata(get_context) => {
+ let krate = CrateNum::decode(d)?;
+ get_context(krate)
+ }
+ };
+
+ // Do this after decoding, so that we decode a `CrateNum`
+ // if necessary
+ if index == ExpnId::root().as_u32() {
+ debug!("decode_expn_id: deserialized root");
+ return Ok(ExpnId::root());
+ }
+
+ let outer_expns = &context.remapped_expns;
+
+ // Ensure that the lock() temporary is dropped early
+ {
+ if let Some(expn_id) = outer_expns.lock().get(index as usize).copied().flatten() {
+ return Ok(expn_id);
+ }
+ }
+
+ // Don't decode the data inside `HygieneData::with`, since we need to recursively decode
+ // other ExpnIds
+ let mut expn_data = decode_data(d, index)?;
+
+ let expn_id = HygieneData::with(|hygiene_data| {
+ let expn_id = ExpnId(hygiene_data.expn_data.len() as u32);
+
+ // If we just deserialized an `ExpnData` owned by
+ // the local crate, its `orig_id` will be stale,
+ // so we need to update it to its own value.
+ // This only happens when we deserialize the incremental cache,
+ // since a crate will never decode its own metadata.
+ if expn_data.krate == LOCAL_CRATE {
+ expn_data.orig_id = Some(expn_id.0);
+ }
+
+ hygiene_data.expn_data.push(Some(expn_data));
+
+ let mut expns = outer_expns.lock();
+ let new_len = index as usize + 1;
+ if expns.len() < new_len {
+ expns.resize(new_len, None);
+ }
+ expns[index as usize] = Some(expn_id);
+ drop(expns);
+ expn_id
+ });
+ return Ok(expn_id);
+}
+
+// Decodes `SyntaxContext`, using the provided `HygieneDecodeContext`
+// to track which `SyntaxContext`s we have already decoded.
+// The provided closure will be invoked to deserialize a `SyntaxContextData`
+// if we haven't already seen the id of the `SyntaxContext` we are deserializing.
+pub fn decode_syntax_context<
+ D: Decoder,
+ F: FnOnce(&mut D, u32) -> Result<SyntaxContextData, D::Error>,
+>(
+ d: &mut D,
+ context: &HygieneDecodeContext,
+ decode_data: F,
+) -> Result<SyntaxContext, D::Error> {
+ let raw_id: u32 = Decodable::decode(d)?;
+ if raw_id == 0 {
+ debug!("decode_syntax_context: deserialized root");
+ // The root is special
+ return Ok(SyntaxContext::root());
+ }
+
+ let outer_ctxts = &context.remapped_ctxts;
+
+ // Ensure that the lock() temporary is dropped early
+ {
+ if let Some(ctxt) = outer_ctxts.lock().get(raw_id as usize).copied().flatten() {
+ return Ok(ctxt);
+ }
+ }
+
+ // Allocate and store SyntaxContext id *before* calling the decoder function,
+ // as the SyntaxContextData may reference itself.
+ let new_ctxt = HygieneData::with(|hygiene_data| {
+ let new_ctxt = SyntaxContext(hygiene_data.syntax_context_data.len() as u32);
+ // Push a dummy SyntaxContextData to ensure that nobody else can get the
+ // same ID as us. This will be overwritten after call `decode_Data`
+ hygiene_data.syntax_context_data.push(SyntaxContextData {
+ outer_expn: ExpnId::root(),
+ outer_transparency: Transparency::Transparent,
+ parent: SyntaxContext::root(),
+ opaque: SyntaxContext::root(),
+ opaque_and_semitransparent: SyntaxContext::root(),
+ dollar_crate_name: kw::Invalid,
+ });
+ let mut ctxts = outer_ctxts.lock();
+ let new_len = raw_id as usize + 1;
+ if ctxts.len() < new_len {
+ ctxts.resize(new_len, None);
+ }
+ ctxts[raw_id as usize] = Some(new_ctxt);
+ drop(ctxts);
+ new_ctxt
+ });
+
+ // Don't try to decode data while holding the lock, since we need to
+ // be able to recursively decode a SyntaxContext
+ let mut ctxt_data = decode_data(d, raw_id)?;
+ // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`
+ // We don't care what the encoding crate set this to - we want to resolve it
+ // from the perspective of the current compilation session
+ ctxt_data.dollar_crate_name = kw::DollarCrate;
+
+ // Overwrite the dummy data with our decoded SyntaxContextData
+ HygieneData::with(|hygiene_data| {
+ let dummy = std::mem::replace(
+ &mut hygiene_data.syntax_context_data[new_ctxt.as_u32() as usize],
+ ctxt_data,
+ );
+ // Make sure nothing weird happening while `decode_data` was running
+ assert_eq!(dummy.dollar_crate_name, kw::Invalid);
+ });
+
+ return Ok(new_ctxt);
+}
+
+pub fn num_syntax_ctxts() -> usize {
+ HygieneData::with(|data| data.syntax_context_data.len())
+}
+
+pub fn for_all_ctxts_in<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Result<(), E>>(
+ ctxts: impl Iterator<Item = SyntaxContext>,
+ mut f: F,
+) -> Result<(), E> {
+ let all_data: Vec<_> = HygieneData::with(|data| {
+ ctxts.map(|ctxt| (ctxt, data.syntax_context_data[ctxt.0 as usize].clone())).collect()
+ });
+ for (ctxt, data) in all_data.into_iter() {
+ f((ctxt.0, ctxt, &data))?;
}
+ Ok(())
}
-impl Decodable for ExpnId {
- fn decode<D: Decoder>(_: &mut D) -> Result<Self, D::Error> {
- Ok(ExpnId::root()) // FIXME(jseyfried) intercrate hygiene
+pub fn for_all_expns_in<E, F: FnMut(u32, ExpnId, &ExpnData) -> Result<(), E>>(
+ expns: impl Iterator<Item = ExpnId>,
+ mut f: F,
+) -> Result<(), E> {
+ let all_data: Vec<_> = HygieneData::with(|data| {
+ expns.map(|expn| (expn, data.expn_data[expn.0 as usize].clone())).collect()
+ });
+ for (expn, data) in all_data.into_iter() {
+ f(expn.0, expn, &data.unwrap_or_else(|| panic!("Missing data for {:?}", expn)))?;
+ }
+ Ok(())
+}
+pub fn for_all_data<E, F: FnMut((u32, SyntaxContext, &SyntaxContextData)) -> Result<(), E>>(
+ mut f: F,
+) -> Result<(), E> {
+ let all_data = HygieneData::with(|data| data.syntax_context_data.clone());
+ for (i, data) in all_data.into_iter().enumerate() {
+ f((i as u32, SyntaxContext(i as u32), &data))?;
}
+ Ok(())
}
+
+pub fn for_all_expn_data<E, F: FnMut(u32, &ExpnData) -> Result<(), E>>(mut f: F) -> Result<(), E> {
+ let all_data = HygieneData::with(|data| data.expn_data.clone());
+ for (i, data) in all_data.into_iter().enumerate() {
+ f(i as u32, &data.unwrap_or_else(|| panic!("Missing ExpnData!")))?;
+ }
+ Ok(())
+}
+
+pub fn raw_encode_syntax_context<E: Encoder>(
+ ctxt: SyntaxContext,
+ context: &HygieneEncodeContext,
+ e: &mut E,
+) -> Result<(), E::Error> {
+ if !context.serialized_ctxts.lock().contains(&ctxt) {
+ context.latest_ctxts.lock().insert(ctxt);
+ }
+ ctxt.0.encode(e)
+}
+
+pub fn raw_encode_expn_id<E: Encoder>(
+ expn: ExpnId,
+ context: &HygieneEncodeContext,
+ mode: ExpnDataEncodeMode,
+ e: &mut E,
+) -> Result<(), E::Error> {
+ if !context.serialized_expns.lock().contains(&expn) {
+ context.latest_expns.lock().insert(expn);
+ }
+ match mode {
+ ExpnDataEncodeMode::IncrComp => expn.0.encode(e),
+ ExpnDataEncodeMode::Metadata => {
+ let data = expn.expn_data();
+ data.orig_id.expect("Missing orig_id").encode(e)?;
+ data.krate.encode(e)
+ }
+ }
+}
+
+pub enum ExpnDataEncodeMode {
+ IncrComp,
+ Metadata,
+}
+
+pub enum ExpnDataDecodeMode<'a, F: FnOnce(CrateNum) -> &'a HygieneDecodeContext> {
+ IncrComp(&'a HygieneDecodeContext),
+ Metadata(F),
+}
+
+impl<'a> ExpnDataDecodeMode<'a, Box<dyn FnOnce(CrateNum) -> &'a HygieneDecodeContext>> {
+ pub fn incr_comp(ctxt: &'a HygieneDecodeContext) -> Self {
+ ExpnDataDecodeMode::IncrComp(ctxt)
+ }
+}
+
+impl UseSpecializedEncodable for SyntaxContext {}
+impl UseSpecializedDecodable for SyntaxContext {}
#![feature(nll)]
#![feature(optin_builtin_traits)]
#![feature(min_specialization)]
+#![feature(option_expect_none)]
+#![feature(refcell_take)]
// FIXME(#56935): Work around ICEs during cross-compilation.
#[allow(unused)]
use edition::Edition;
pub mod hygiene;
pub use hygiene::SyntaxContext;
-use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
+use hygiene::{Transparency, NUM_TRANSPARENCIES};
pub mod def_id;
use def_id::{CrateNum, DefId, LOCAL_CRATE};
mod span_encoding;
pub mod fatal_error;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{Lock, Lrc};
}
}
+// If this ever becomes non thread-local, `decode_syntax_context`
+// and `decode_expn_id` will need to be updated to handle concurrent
+// deserialization.
scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
// FIXME: Perhaps this should not implement Rustc{Decodable, Encodable}
/// This is a hack to allow using the `HashStable_Generic` derive macro
/// instead of implementing everything in librustc_middle.
pub trait HashStableContext {
- fn hash_spans(&self) -> bool;
fn hash_def_id(&mut self, _: DefId, hasher: &mut StableHasher);
+ fn hash_crate_num(&mut self, _: CrateNum, hasher: &mut StableHasher);
+ fn hash_spans(&self) -> bool;
fn byte_pos_to_line_and_col(
&mut self,
byte: BytePos,
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
const TAG_VALID_SPAN: u8 = 0;
const TAG_INVALID_SPAN: u8 = 1;
- const TAG_EXPANSION: u8 = 0;
- const TAG_NO_EXPANSION: u8 = 1;
if !ctx.hash_spans() {
return;
}
if *self == DUMMY_SP {
- return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+ std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+ return;
}
// If this is not an empty or invalid span, we want to hash the last
let (file_lo, line_lo, col_lo) = match ctx.byte_pos_to_line_and_col(span.lo) {
Some(pos) => pos,
None => {
- return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+ std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+ span.ctxt.hash_stable(ctx, hasher);
+ return;
}
};
if !file_lo.contains(span.hi) {
- return std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+ std::hash::Hash::hash(&TAG_INVALID_SPAN, hasher);
+ span.ctxt.hash_stable(ctx, hasher);
+ return;
}
std::hash::Hash::hash(&TAG_VALID_SPAN, hasher);
let len = ((span.hi - span.lo).0 as u64) << 32;
let line_col_len = col | line | len;
std::hash::Hash::hash(&line_col_len, hasher);
+ span.ctxt.hash_stable(ctx, hasher);
+ }
+}
- if span.ctxt == SyntaxContext::root() {
+impl<CTX: HashStableContext> HashStable<CTX> for SyntaxContext {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ const TAG_EXPANSION: u8 = 0;
+ const TAG_NO_EXPANSION: u8 = 1;
+
+ if *self == SyntaxContext::root() {
TAG_NO_EXPANSION.hash_stable(ctx, hasher);
} else {
TAG_EXPANSION.hash_stable(ctx, hasher);
// times, we cache a stable hash of it and hash that instead of
// recursing every time.
thread_local! {
- static CACHE: RefCell<FxHashMap<hygiene::ExpnId, u64>> = Default::default();
+ static CACHE: RefCell<Vec<Option<[Option<u64>; NUM_TRANSPARENCIES]>>> = Default::default();
}
let sub_hash: u64 = CACHE.with(|cache| {
- let expn_id = span.ctxt.outer_expn();
+ let (expn_id, transparency, _) = self.outer_mark_with_data();
+ let index = expn_id.as_u32() as usize;
- if let Some(&sub_hash) = cache.borrow().get(&expn_id) {
- return sub_hash;
+ if let Some(sub_hash_cache) = cache.borrow().get(index).copied().flatten() {
+ if let Some(sub_hash) = sub_hash_cache[transparency as usize] {
+ return sub_hash;
+ }
}
+ let new_len = index + 1;
+
let mut hasher = StableHasher::new();
expn_id.expn_data().hash_stable(ctx, &mut hasher);
+ transparency.hash_stable(ctx, &mut hasher);
+
let sub_hash: Fingerprint = hasher.finish();
let sub_hash = sub_hash.to_smaller_hash();
- cache.borrow_mut().insert(expn_id, sub_hash);
+
+ let mut cache = cache.borrow_mut();
+ if cache.len() < new_len {
+ cache.resize(new_len, None);
+ }
+ if let Some(mut sub_hash_cache) = cache[index] {
+ sub_hash_cache[transparency as usize] = Some(sub_hash);
+ } else {
+ let mut sub_hash_cache = [None; NUM_TRANSPARENCIES];
+ sub_hash_cache[transparency as usize] = Some(sub_hash);
+ cache[index] = Some(sub_hash_cache);
+ }
sub_hash
});
minnumf32,
minnumf64,
mips_target_feature,
- miri_start_panic,
mmx_target_feature,
module,
module_path,
rustc_peek_liveness,
rustc_peek_maybe_init,
rustc_peek_maybe_uninit,
+ rustc_polymorphize_error,
rustc_private,
rustc_proc_macro_decls,
rustc_promotable,
// also include any type parameters (for generic items)
assert!(!substs.has_erasable_regions());
- assert!(!substs.needs_subst());
substs.hash_stable(&mut hcx, &mut hasher);
if let Some(instantiating_crate) = instantiating_crate {
/// Alignments for vector types.
pub vector_align: Vec<(Size, AbiAndPrefAlign)>,
- pub instruction_address_space: u32,
+ pub instruction_address_space: AddressSpace,
}
impl Default for TargetDataLayout {
(Size::from_bits(64), AbiAndPrefAlign::new(align(64))),
(Size::from_bits(128), AbiAndPrefAlign::new(align(128))),
],
- instruction_address_space: 0,
+ instruction_address_space: AddressSpace::DATA,
}
}
}
pub fn parse(target: &Target) -> Result<TargetDataLayout, String> {
// Parse an address space index from a string.
let parse_address_space = |s: &str, cause: &str| {
- s.parse::<u32>().map_err(|err| {
+ s.parse::<u32>().map(AddressSpace).map_err(|err| {
format!("invalid address space `{}` for `{}` in \"data-layout\": {}", s, cause, err)
})
};
}
}
+/// An identifier that specifies the address space that some operation
+/// should operate on. Special address spaces have an effect on code generation,
+/// depending on the target and the address spaces it implements.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct AddressSpace(pub u32);
+
+impl AddressSpace {
+ /// The default address space, corresponding to data space.
+ pub const DATA: Self = AddressSpace(0);
+}
+
/// Describes how values of the type are passed by target ABIs,
/// in terms of categories of C types there are ABI rules for.
#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
}
}
-#[derive(Copy, Clone, PartialEq, Eq)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum PointerKind {
/// Most general case, we know no restrictions to tell LLVM.
Shared,
UniqueOwned,
}
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
pub struct PointeeInfo {
pub size: Size,
pub align: Align,
pub safe: Option<PointerKind>,
+ pub address_space: AddressSpace,
}
pub trait TyAndLayoutMethods<'a, C: LayoutOf<Ty = Self>>: Sized {
+++ /dev/null
-fn main() {
- println!("cargo:rerun-if-changed=build.rs");
- println!("cargo:rerun-if-env-changed=CFG_DEFAULT_LINKER");
-}
--- /dev/null
+use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::apple_base::opts();
+ base.cpu = "apple-a12".to_string();
+ base.max_atomic_width = Some(128);
+ base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
+
+ base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
+
+ // Clang automatically chooses a more specific target based on
+ // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
+ // correctly, we do too.
+ let arch = "aarch64";
+ let llvm_target = super::apple_base::macos_llvm_target(&arch);
+
+ Ok(Target {
+ llvm_target,
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ target_c_int_width: "32".to_string(),
+ data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(),
+ arch: arch.to_string(),
+ target_os: "macos".to_string(),
+ target_env: String::new(),
+ target_vendor: "apple".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: TargetOptions { target_mcount: "\u{1}mcount".to_string(), ..base },
+ })
+}
has_elf_tls: version >= (10, 7),
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
+ eh_frame_header: false,
// This environment variable is pretty magical but is intended for
// producing deterministic builds. This was first discovered to be used
has_rpath: false,
pre_link_args: args,
position_independent_executables: false,
+ eh_frame_header: false,
..Default::default()
}
}
is_like_solaris: true,
limit_rdylib_exports: false, // Linker doesn't support this
eliminate_frame_pointer: false,
+ eh_frame_header: false,
late_link_args,
// While we support ELF TLS, rust requires a way to register
("i686-unknown-haiku", i686_unknown_haiku),
("x86_64-unknown-haiku", x86_64_unknown_haiku),
+ ("aarch64-apple-darwin", aarch64_apple_darwin),
("x86_64-apple-darwin", x86_64_apple_darwin),
("i686-apple-darwin", i686_apple_darwin),
/// Whether to use legacy .ctors initialization hooks rather than .init_array. Defaults
/// to false (uses .init_array).
pub use_ctors_section: bool,
+
+ /// Whether the linker is instructed to add a `GNU_EH_FRAME` ELF header
+ /// used to locate unwinding information is passed
+ /// (only has effect if the linker is `ld`-like).
+ pub eh_frame_header: bool,
}
impl Default for TargetOptions {
relax_elf_relocations: false,
llvm_args: vec![],
use_ctors_section: false,
+ eh_frame_header: true,
}
}
}
key!(relax_elf_relocations, bool);
key!(llvm_args, list);
key!(use_ctors_section, bool);
+ key!(eh_frame_header, bool);
// NB: The old name is deprecated, but support for it is retained for
// compatibility.
target_option_val!(relax_elf_relocations);
target_option_val!(llvm_args);
target_option_val!(use_ctors_section);
+ target_option_val!(eh_frame_header);
if default.unsupported_abis != self.options.unsupported_abis {
d.insert(
// See the thumb_base.rs file for an explanation of this value
emit_debug_gdb_scripts: false,
+ eh_frame_header: false,
+
..Default::default()
},
})
relocation_model: RelocModel::Static,
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
relocation_model: RelocModel::Static,
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
relocation_model: RelocModel::Static,
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
code_model: Some(CodeModel::Medium),
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
code_model: Some(CodeModel::Medium),
emit_debug_gdb_scripts: false,
unsupported_abis: super::riscv_base::unsupported_abis(),
+ eh_frame_header: false,
..Default::default()
},
})
target_family: Some("unix".to_string()),
is_like_solaris: true,
limit_rdylib_exports: false, // Linker doesn't support this
+ eh_frame_header: false,
..Default::default()
}
abi_return_struct_as_int: true,
emit_debug_gdb_scripts: false,
requires_uwtable: true,
+ eh_frame_header: false,
..Default::default()
}
base.cpu = "core2".to_string();
base.max_atomic_width = Some(128); // core2 support cmpxchg16b
base.eliminate_frame_pointer = false;
- base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string()]);
+ base.pre_link_args.insert(
+ LinkerFlavor::Gcc,
+ vec!["-m64".to_string(), "-arch".to_string(), "x86_64".to_string()],
+ );
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
base.stack_probes = true;
use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::{
FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngine,
+ Unimplemented,
};
use rustc_errors::ErrorReported;
use rustc_middle::ty::fold::TypeFoldable;
);
return Err(ErrorReported);
}
+ Err(Unimplemented) => {
+ // This can trigger when we probe for the source of a `'static` lifetime requirement
+ // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+ infcx.tcx.sess.delay_span_bug(
+ rustc_span::DUMMY_SP,
+ &format!(
+ "Encountered error `Unimplemented` selecting `{:?}` during codegen",
+ trait_ref
+ ),
+ );
+ return Err(ErrorReported);
+ }
Err(e) => {
bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref)
}
/// - but (knowing that `Vec<T>` is non-fundamental, and assuming it's
/// not local), `Vec<LocalType>` is bad, because `Vec<->` is between
/// the local type and the type parameter.
-/// 3. Every type parameter before the local key parameter is fully known in C.
-/// - e.g., `impl<T> T: Trait<LocalType>` is bad, because `T` might be
-/// an unknown type.
-/// - but `impl<T> LocalType: Trait<T>` is OK, because `LocalType`
-/// occurs before `T`.
+/// 3. Before this local type, no generic type parameter of the impl must
+/// be reachable through fundamental types.
+/// - e.g. `impl<T> Trait<LocalType> for Vec<T>` is fine, as `Vec` is not fundamental.
+/// - while `impl<T> Trait<LocalType for Box<T>` results in an error, as `T` is
+/// reachable through the fundamental type `Box`.
/// 4. Every type in the local key parameter not known in C, going
/// through the parameter's type tree, must appear only as a subtree of
/// a type local to C, with only fundamental types between the type
ty: Ty<'tcx>,
in_crate: InCrate,
) -> Vec<Ty<'tcx>> {
- // FIXME(eddyb) figure out if this is redundant with `ty_is_non_local`,
- // or maybe if this should be calling `ty_is_non_local_constructor`.
- if ty_is_non_local(tcx, ty, in_crate).is_some() {
+ // FIXME: this is currently somewhat overly complicated,
+ // but fixing this requires a more complicated refactor.
+ if !contained_non_local_types(tcx, ty, in_crate).is_empty() {
if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
return inner_tys
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
.enumerate()
{
debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty);
- let non_local_tys = ty_is_non_local(tcx, input_ty, in_crate);
- if non_local_tys.is_none() {
+ let non_local_tys = contained_non_local_types(tcx, input_ty, in_crate);
+ if non_local_tys.is_empty() {
debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty);
return Ok(());
} else if let ty::Param(_) = input_ty.kind {
.substs
.types()
.flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
- .find(|ty| ty_is_non_local_constructor(ty, in_crate).is_none());
+ .find(|ty| ty_is_local_constructor(ty, in_crate));
debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type));
}
- if let Some(non_local_tys) = non_local_tys {
- for input_ty in non_local_tys {
- non_local_spans.push((input_ty, i == 0));
- }
+
+ for input_ty in non_local_tys {
+ non_local_spans.push((input_ty, i == 0));
}
}
// If we exit above loop, never found a local type.
Err(OrphanCheckErr::NonLocalInputType(non_local_spans))
}
-fn ty_is_non_local(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Option<Vec<Ty<'tcx>>> {
- match ty_is_non_local_constructor(ty, in_crate) {
- Some(ty) => {
- if let Some(inner_tys) = fundamental_ty_inner_tys(tcx, ty) {
- let tys: Vec<_> = inner_tys
- .filter_map(|ty| ty_is_non_local(tcx, ty, in_crate))
- .flatten()
- .collect();
- if tys.is_empty() { None } else { Some(tys) }
- } else {
- Some(vec![ty])
+/// Returns a list of relevant non-local types for `ty`.
+///
+/// This is just `ty` itself unless `ty` is `#[fundamental]`,
+/// in which case we recursively look into this type.
+///
+/// If `ty` is local itself, this method returns an empty `Vec`.
+///
+/// # Examples
+///
+/// - `u32` is not local, so this returns `[u32]`.
+/// - for `Foo<u32>`, where `Foo` is a local type, this returns `[]`.
+/// - `&mut u32` returns `[u32]`, as `&mut` is a fundamental type, similar to `Box`.
+/// - `Box<Foo<u32>>` returns `[]`, as `Box` is a fundamental type and `Foo` is local.
+fn contained_non_local_types(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, in_crate: InCrate) -> Vec<Ty<'tcx>> {
+ if ty_is_local_constructor(ty, in_crate) {
+ Vec::new()
+ } else {
+ match fundamental_ty_inner_tys(tcx, ty) {
+ Some(inner_tys) => {
+ inner_tys.flat_map(|ty| contained_non_local_types(tcx, ty, in_crate)).collect()
}
+ None => vec![ty],
}
- None => None,
}
}
}
}
-// FIXME(eddyb) this can just return `bool` as it always returns `Some(ty)` or `None`.
-fn ty_is_non_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> Option<Ty<'_>> {
- debug!("ty_is_non_local_constructor({:?})", ty);
+fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool {
+ debug!("ty_is_local_constructor({:?})", ty);
match ty.kind {
ty::Bool
| ty::Never
| ty::Tuple(..)
| ty::Param(..)
- | ty::Projection(..) => Some(ty),
+ | ty::Projection(..) => false,
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate {
- InCrate::Local => Some(ty),
+ InCrate::Local => false,
// The inference variable might be unified with a local
// type in that remote crate.
- InCrate::Remote => None,
+ InCrate::Remote => true,
},
- ty::Adt(def, _) => {
- if def_id_is_local(def.did, in_crate) {
- None
- } else {
- Some(ty)
- }
- }
- ty::Foreign(did) => {
- if def_id_is_local(did, in_crate) {
- None
- } else {
- Some(ty)
- }
- }
+ ty::Adt(def, _) => def_id_is_local(def.did, in_crate),
+ ty::Foreign(did) => def_id_is_local(did, in_crate),
ty::Opaque(..) => {
// This merits some explanation.
// Normally, opaque types are not involed when performing
// the underlying type *within the same crate*. When an
// opaque type is used from outside the module
// where it is declared, it should be impossible to observe
- // anyything about it other than the traits that it implements.
+ // anything about it other than the traits that it implements.
//
// The alternative would be to look at the underlying type
// to determine whether or not the opaque type itself should
// to a remote type. This would violate the rule that opaque
// types should be completely opaque apart from the traits
// that they implement, so we don't use this behavior.
- Some(ty)
+ false
}
ty::Dynamic(ref tt, ..) => {
if let Some(principal) = tt.principal() {
- if def_id_is_local(principal.def_id(), in_crate) { None } else { Some(ty) }
+ def_id_is_local(principal.def_id(), in_crate)
} else {
- Some(ty)
+ false
}
}
- ty::Error(_) => None,
+ ty::Error(_) => true,
ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
| ObligationCauseCode::IntrinsicType
| ObligationCauseCode::MethodReceiver
| ObligationCauseCode::ReturnNoExpression
+ | ObligationCauseCode::UnifyReceiver(..)
| ObligationCauseCode::MiscObligation => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
Ok(resolved_value)
}
-/// Normalizes the predicates and checks whether they hold in an empty
-/// environment. If this returns false, then either normalize
-/// encountered an error or one of the predicates did not hold. Used
-/// when creating vtables to check for unsatisfiable methods.
-pub fn normalize_and_test_predicates<'tcx>(
+/// Normalizes the predicates and checks whether they hold in an empty environment. If this
+/// returns true, then either normalize encountered an error or one of the predicates did not
+/// hold. Used when creating vtables to check for unsatisfiable methods.
+pub fn impossible_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>,
) -> bool {
- debug!("normalize_and_test_predicates(predicates={:?})", predicates);
+ debug!("impossible_predicates(predicates={:?})", predicates);
let result = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::reveal_all();
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
- fulfill_cx.select_all_or_error(&infcx).is_ok()
+ fulfill_cx.select_all_or_error(&infcx).is_err()
});
- debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result);
+ debug!("impossible_predicates(predicates={:?}) = {:?}", predicates, result);
result
}
-fn substitute_normalize_and_test_predicates<'tcx>(
+fn subst_and_check_impossible_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
key: (DefId, SubstsRef<'tcx>),
) -> bool {
- debug!("substitute_normalize_and_test_predicates(key={:?})", key);
+ debug!("subst_and_check_impossible_predicates(key={:?})", key);
- let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
- let result = normalize_and_test_predicates(tcx, predicates);
+ let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
+ predicates.retain(|predicate| !predicate.needs_subst());
+ let result = impossible_predicates(tcx, predicates);
- debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result);
+ debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
result
}
// Note that this method could then never be called, so we
// do not want to try and codegen it, in that case (see #23435).
let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs);
- if !normalize_and_test_predicates(tcx, predicates.predicates) {
+ if impossible_predicates(tcx, predicates.predicates) {
debug!("vtable_methods: predicates do not hold");
return None;
}
specializes: specialize::specializes,
codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
vtable_methods,
- substitute_normalize_and_test_predicates,
type_implements_trait,
+ subst_and_check_impossible_predicates,
..*providers
};
}
trait_ref
.substs
.iter()
- .filter(|arg| {
+ .enumerate()
+ .filter(|(_, arg)| {
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
})
- .filter(|arg| !arg.has_escaping_bound_vars())
- .map(|arg| {
+ .filter(|(_, arg)| !arg.has_escaping_bound_vars())
+ .map(|(i, arg)| {
+ let mut new_cause = cause.clone();
+ // The first subst is the self ty - use the correct span for it.
+ if i == 0 {
+ if let Some(hir::ItemKind::Impl { self_ty, .. }) = item.map(|i| &i.kind) {
+ new_cause.make_mut().span = self_ty.span;
+ }
+ }
traits::Obligation::new(
- cause.clone(),
+ new_cause,
param_env,
ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
)
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeFoldable};
-use rustc_span::sym;
+use rustc_span::{sym, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use traits::{translate_substs, Reveal};
let ty = substs.type_at(0);
if ty.needs_drop(tcx, param_env) {
- // `DropGlue` requires a monomorphic aka concrete type.
- if ty.needs_subst() {
- return Ok(None);
+ debug!(" => nontrivial drop glue");
+ match ty.kind {
+ ty::Closure(..)
+ | ty::Generator(..)
+ | ty::Tuple(..)
+ | ty::Adt(..)
+ | ty::Dynamic(..)
+ | ty::Array(..)
+ | ty::Slice(..) => {}
+ // Drop shims can only be built from ADTs.
+ _ => return Ok(None),
}
- debug!(" => nontrivial drop glue");
ty::InstanceDef::DropGlue(def_id, Some(ty))
} else {
debug!(" => trivial drop glue");
trait_closure_kind,
))
}
- traits::ImplSourceFnPointer(ref data) => {
- // `FnPtrShim` requires a monomorphic aka concrete type.
- if data.fn_ty.needs_subst() {
- return Ok(None);
- }
-
- Some(Instance {
+ traits::ImplSourceFnPointer(ref data) => match data.fn_ty.kind {
+ ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
substs: rcvr_substs,
- })
- }
+ }),
+ _ => None,
+ },
traits::ImplSourceObject(ref data) => {
let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
if name == sym::clone {
let self_ty = trait_ref.self_ty();
- // `CloneShim` requires a monomorphic aka concrete type.
- if self_ty.needs_subst() {
- return Ok(None);
- }
+ let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
+ match self_ty.kind {
+ _ if is_copy => (),
+ ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {}
+ _ => return Ok(None),
+ };
Some(Instance {
def: ty::InstanceDef::CloneShim(def_id, self_ty),
debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
let br_name = match *br {
- ty::BrNamed(_, name) => name,
- _ => {
- span_bug!(
- binding.span,
- "anonymous bound region {:?} in binding but not trait ref",
- br
- );
- }
+ ty::BrNamed(_, name) => format!("lifetime `{}`", name),
+ _ => "an anonymous lifetime".to_string(),
};
// FIXME: point at the type params that don't have appropriate lifetimes:
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
// ---- ---- ^^^^^^^
- struct_span_err!(
+ let mut err = struct_span_err!(
tcx.sess,
binding.span,
E0582,
- "binding for associated type `{}` references lifetime `{}`, \
+ "binding for associated type `{}` references {}, \
which does not appear in the trait input types",
binding.item_name,
br_name
- )
- .emit();
+ );
+
+ if let ty::BrAnon(_) = *br {
+ // The only way for an anonymous lifetime to wind up
+ // in the return type but **also** be unconstrained is
+ // if it only appears in "associated types" in the
+ // input. See #62200 for an example. In this case,
+ // though we can easily give a hint that ought to be
+ // relevant.
+ err.note("lifetimes appearing in an associated type are not considered constrained");
+ }
+
+ err.emit();
}
}
}
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::ty;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
+use rustc_middle::ty::subst::{InternalSubsts, Subst};
use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt, WithConstness};
+use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use super::{potentially_plural_count, FnCtxt, Inherited};
-use std::iter;
/// Checks that a method from an impl conforms to the signature of
/// the same method as declared in the trait.
return Ok(());
}
- let param_env = tcx.param_env(impl_ty.def_id);
-
// Given
//
// impl<A, B> Foo<u32> for (A, B) {
impl_ty_substs.rebase_onto(tcx, impl_ty.container.id(), impl_trait_ref.substs);
let impl_ty_value = tcx.type_of(impl_ty.def_id);
- // Map the predicate from the trait to the corresponding one for the impl.
- // For example:
+ let param_env = tcx.param_env(impl_ty.def_id);
+
+ // When checking something like
//
- // trait X<A> { type Y<'a>: PartialEq<A> } impl X for T { type Y<'a> = &'a S; }
- // impl<'x> X<&'x u32> for () { type Y<'c> = &'c u32; }
+ // trait X { type Y: PartialEq<<Self as X>::Y> }
+ // impl X for T { default type Y = S; }
//
- // For the `for<'a> <<Self as X<A>>::Y<'a>: PartialEq<A>` bound, this
- // function would translate and partially normalize
- // `[<Self as X<A>>::Y<'a>, A]` to `[&'a u32, &'x u32]`.
- let translate_predicate_substs = move |predicate_substs: SubstsRef<'tcx>| {
- tcx.mk_substs(
- iter::once(impl_ty_value.into())
- .chain(predicate_substs[1..].iter().map(|s| s.subst(tcx, rebased_substs))),
- )
+ // We will have to prove the bound S: PartialEq<<T as X>::Y>. In this case
+ // we want <T as X>::Y to normalize to S. This is valid because we are
+ // checking the default value specifically here. Add this equality to the
+ // ParamEnv for normalization specifically.
+ let normalize_param_env = {
+ let mut predicates = param_env.caller_bounds().iter().collect::<Vec<_>>();
+ predicates.push(
+ ty::Binder::dummy(ty::ProjectionPredicate {
+ projection_ty: ty::ProjectionTy {
+ item_def_id: trait_ty.def_id,
+ substs: rebased_substs,
+ },
+ ty: impl_ty_value,
+ })
+ .to_predicate(tcx),
+ );
+ ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None)
};
tcx.infer_ctxt().enter(move |infcx| {
);
let predicates = tcx.projection_predicates(trait_ty.def_id);
-
debug!("compare_projection_bounds: projection_predicates={:?}", predicates);
for predicate in predicates {
- let concrete_ty_predicate = match predicate.kind() {
- ty::PredicateKind::Trait(poly_tr, c) => poly_tr
- .map_bound(|tr| {
- let trait_substs = translate_predicate_substs(tr.trait_ref.substs);
- ty::TraitRef { def_id: tr.def_id(), substs: trait_substs }
- })
- .with_constness(*c)
- .to_predicate(tcx),
- ty::PredicateKind::Projection(poly_projection) => poly_projection
- .map_bound(|projection| {
- let projection_substs =
- translate_predicate_substs(projection.projection_ty.substs);
- ty::ProjectionPredicate {
- projection_ty: ty::ProjectionTy {
- substs: projection_substs,
- item_def_id: projection.projection_ty.item_def_id,
- },
- ty: projection.ty.subst(tcx, rebased_substs),
- }
- })
- .to_predicate(tcx),
- ty::PredicateKind::TypeOutlives(poly_outlives) => poly_outlives
- .map_bound(|outlives| {
- ty::OutlivesPredicate(impl_ty_value, outlives.1.subst(tcx, rebased_substs))
- })
- .to_predicate(tcx),
- _ => bug!("unexepected projection predicate kind: `{:?}`", predicate),
- };
+ let concrete_ty_predicate = predicate.subst(tcx, rebased_substs);
+ debug!("compare_projection_bounds: concrete predicate = {:?}", concrete_ty_predicate);
let traits::Normalized { value: normalized_predicate, obligations } = traits::normalize(
&mut selcx,
- param_env,
+ normalize_param_env,
normalize_cause.clone(),
&concrete_ty_predicate,
);
-
debug!("compare_projection_bounds: normalized predicate = {:?}", normalized_predicate);
inh.register_predicates(obligations);
use rustc_ast::ast;
use rustc_ast::util::lev_distance::find_best_match_for_name;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId};
use rustc_hir as hir;
let old_diverges = self.diverges.replace(Diverges::Maybe);
let old_has_errors = self.has_errors.replace(false);
- let ty = self.check_expr_kind(expr, expected);
+ let ty = ensure_sufficient_stack(|| self.check_expr_kind(expr, expected));
// Warn for non-block expressions with diverging children.
match expr.kind {
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
- sym::miri_start_panic => {
- // FIXME - the relevant types aren't lang items,
- // so it's not trivial to check this
- return;
- }
-
sym::count_code_region => {
(0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit())
}
use crate::hir::GenericArg;
use rustc_hir as hir;
use rustc_infer::infer::{self, InferOk};
+use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::fold::TypeFoldable;
// signature (which is also done during probing).
let method_sig_rcvr =
self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]);
- self.unify_receivers(self_ty, method_sig_rcvr);
+ debug!(
+ "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}",
+ self_ty, method_sig_rcvr, method_sig, method_predicates
+ );
+ self.unify_receivers(self_ty, method_sig_rcvr, &pick, all_substs);
let (method_sig, method_predicates) =
self.normalize_associated_types_in(self.span, &(method_sig, method_predicates));
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
if let Some(mutbl) = pick.autoref {
- let region = self.next_region_var(infer::Autoref(self.span));
+ let region = self.next_region_var(infer::Autoref(self.span, pick.item));
target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
let mutbl = match mutbl {
hir::Mutability::Not => AutoBorrowMutability::Not,
)
}
- fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
- match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) {
+ fn unify_receivers(
+ &mut self,
+ self_ty: Ty<'tcx>,
+ method_self_ty: Ty<'tcx>,
+ pick: &probe::Pick<'tcx>,
+ substs: SubstsRef<'tcx>,
+ ) {
+ debug!(
+ "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}",
+ self_ty, method_self_ty, self.span, pick
+ );
+ let cause = self.cause(
+ self.span,
+ ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
+ assoc_item: pick.item,
+ param_env: self.param_env,
+ substs,
+ })),
+ );
+ match self.at(&cause, self.param_env).sup(method_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
/// opaque type.
opaque_types_vars: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
- /// Each type parameter has an implicit region bound that
- /// indicates it must outlive at least the function body (the user
- /// may specify stronger requirements). This field indicates the
- /// region of the callee. If it is `None`, then the parameter
- /// environment is for an item or something where the "callee" is
- /// not clear.
- implicit_region_bound: Option<ty::Region<'tcx>>,
-
body_id: Option<hir::BodyId>,
}
deferred_generator_interiors: RefCell::new(Vec::new()),
opaque_types: RefCell::new(Default::default()),
opaque_types_vars: RefCell::new(Default::default()),
- implicit_region_bound: None,
body_id,
}
}
fn resolve_regions_and_report_errors(&self, mode: RegionckMode) {
self.infcx.process_registered_region_obligations(
self.outlives_environment.region_bound_pairs_map(),
- self.implicit_region_bound,
+ Some(self.tcx.lifetimes.re_root_empty),
self.param_env,
);
self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
};
use rustc_session::parse::feature_err;
-use rustc_span::symbol::{sym, Symbol};
+use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
use rustc_trait_selection::opaque_types::may_define_opaque_type;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
_ => unreachable!(),
}
}
- hir::ItemKind::Fn(..) => {
- check_item_fn(tcx, item);
+ hir::ItemKind::Fn(ref sig, ..) => {
+ check_item_fn(tcx, item.hir_id, item.ident, item.span, sig.decl);
}
hir::ItemKind::Static(ref ty, ..) => {
check_item_type(tcx, item.hir_id, ty.span, false);
}
hir::ItemKind::ForeignMod(ref module) => {
for it in module.items.iter() {
- if let hir::ForeignItemKind::Static(ref ty, ..) = it.kind {
- check_item_type(tcx, it.hir_id, ty.span, true);
+ match it.kind {
+ hir::ForeignItemKind::Fn(ref decl, ..) => {
+ check_item_fn(tcx, it.hir_id, it.ident, it.span, decl)
+ }
+ hir::ForeignItemKind::Static(ref ty, ..) => {
+ check_item_type(tcx, it.hir_id, ty.span, true)
+ }
+ hir::ForeignItemKind::Type => (),
}
}
}
fcx,
item.ident.span,
sig,
- hir_sig,
+ hir_sig.decl,
item.def_id,
&mut implied_bounds,
);
}
}
-fn check_item_fn(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
- for_item(tcx, item).with_fcx(|fcx, tcx| {
- let def_id = fcx.tcx.hir().local_def_id(item.hir_id);
+fn check_item_fn(
+ tcx: TyCtxt<'_>,
+ item_id: hir::HirId,
+ ident: Ident,
+ span: Span,
+ decl: &hir::FnDecl<'_>,
+) {
+ for_id(tcx, item_id, span).with_fcx(|fcx, tcx| {
+ let def_id = fcx.tcx.hir().local_def_id(item_id);
let sig = fcx.tcx.fn_sig(def_id);
- let sig = fcx.normalize_associated_types_in(item.span, &sig);
+ let sig = fcx.normalize_associated_types_in(span, &sig);
let mut implied_bounds = vec![];
- let hir_sig = match &item.kind {
- ItemKind::Fn(sig, ..) => sig,
- _ => bug!("expected `ItemKind::Fn`, found `{:?}`", item.kind),
- };
check_fn_or_method(
tcx,
fcx,
- item.ident.span,
+ ident.span,
sig,
- hir_sig,
+ decl,
def_id.to_def_id(),
&mut implied_bounds,
);
fcx: &FnCtxt<'fcx, 'tcx>,
span: Span,
sig: ty::PolyFnSig<'tcx>,
- hir_sig: &hir::FnSig<'_>,
+ hir_decl: &hir::FnDecl<'_>,
def_id: DefId,
implied_bounds: &mut Vec<Ty<'tcx>>,
) {
let sig = fcx.normalize_associated_types_in(span, &sig);
let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig);
- for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) {
+ for (&input_ty, span) in sig.inputs().iter().zip(hir_decl.inputs.iter().map(|t| t.span)) {
fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation);
}
implied_bounds.extend(sig.inputs());
fcx.register_wf_obligation(
sig.output().into(),
- hir_sig.decl.output.span(),
+ hir_decl.output.span(),
ObligationCauseCode::ReturnType,
);
// FIXME(#25759) return types should not be implied bounds
implied_bounds.push(sig.output());
- check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_sig.decl.output.span())));
+ check_where_clauses(tcx, fcx, span, def_id, Some((sig.output(), hir_decl.output.span())));
}
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
placeholder_type_error(tcx, None, &[], visitor.0, false);
}
- hir::TraitItemKind::Type(_, None) => {}
+ hir::TraitItemKind::Type(_, None) => {
+ // #74612: Visit and try to find bad placeholders
+ // even if there is no concrete type.
+ let mut visitor = PlaceholderHirTyCollector::default();
+ visitor.visit_trait_item(trait_item);
+ placeholder_type_error(tcx, None, &[], visitor.0, false);
+ }
};
tcx.ensure().predicates_of(def_id);
let type_start = own_start - has_self as u32 + params.len() as u32;
let mut i = 0;
- // FIXME(const_generics): a few places in the compiler expect generic params
- // to be in the order lifetimes, then type params, then const params.
- //
- // To prevent internal errors in case const parameters are supplied before
- // type parameters we first add all type params, then all const params.
- params.extend(ast_generics.params.iter().filter_map(|param| {
- if let GenericParamKind::Type { ref default, synthetic, .. } = param.kind {
+ params.extend(ast_generics.params.iter().filter_map(|param| match param.kind {
+ GenericParamKind::Lifetime { .. } => None,
+ GenericParamKind::Type { ref default, synthetic, .. } => {
if !allow_defaults && default.is_some() {
if !tcx.features().default_type_parameter_fallback {
tcx.struct_span_lint_hir(
|lint| {
lint.build(
"defaults for type parameters are only allowed in \
- `struct`, `enum`, `type`, or `trait` definitions.",
+ `struct`, `enum`, `type`, or `trait` definitions.",
)
.emit();
},
};
i += 1;
Some(param_def)
- } else {
- None
}
- }));
-
- params.extend(ast_generics.params.iter().filter_map(|param| {
- if let GenericParamKind::Const { .. } = param.kind {
+ GenericParamKind::Const { .. } => {
let param_def = ty::GenericParamDef {
index: type_start + i as u32,
name: param.name.ident().name,
};
i += 1;
Some(param_def)
- } else {
- None
}
}));
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`).
for param in ast_generics.params {
- if let GenericParamKind::Type { .. } = param.kind {
- let name = param.name.ident().name;
- let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
- index += 1;
-
- let sized = SizedByDefault::Yes;
- let bounds = AstConv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span);
- predicates.extend(bounds.predicates(tcx, param_ty));
+ match param.kind {
+ // We already dealt with early bound lifetimes above.
+ GenericParamKind::Lifetime { .. } => (),
+ GenericParamKind::Type { .. } => {
+ let name = param.name.ident().name;
+ let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
+ index += 1;
+
+ let sized = SizedByDefault::Yes;
+ let bounds =
+ AstConv::compute_bounds(&icx, param_ty, ¶m.bounds, sized, param.span);
+ predicates.extend(bounds.predicates(tcx, param_ty));
+ }
+ GenericParamKind::Const { .. } => {
+ // Bounds on const parameters are currently not possible.
+ debug_assert!(param.bounds.is_empty());
+ index += 1;
+ }
}
}
let re_root_empty = tcx.lifetimes.re_root_empty;
let predicate = ty::OutlivesPredicate(ty, re_root_empty);
predicates.push((
- ty::PredicateKind::TypeOutlives(ty::Binder::dummy(predicate))
+ ty::PredicateKind::TypeOutlives(ty::Binder::bind(predicate))
.to_predicate(tcx),
span,
));
// such. This helps prevent dependencies of the standard library, for
// example, from getting documented as "traits `u32` implements" which
// isn't really too helpful.
- if let Some(stab) = cx.tcx.lookup_stability(did) {
- if stab.level.is_unstable() {
- return;
+ if let Some(trait_did) = associated_trait {
+ if let Some(stab) = cx.tcx.lookup_stability(trait_did.def_id) {
+ if stab.level.is_unstable() {
+ return;
+ }
}
}
}
attr::Stable { ref since } => since.to_string(),
_ => String::new(),
},
- deprecation: self.rustc_depr.as_ref().map(|d| Deprecation {
- note: Some(d.reason.to_string()).filter(|r| !r.is_empty()),
- since: Some(d.since.to_string()).filter(|d| !d.is_empty()),
- }),
unstable_reason: match self.level {
attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()),
_ => None,
Deprecation {
since: self.since.map(|s| s.to_string()).filter(|s| !s.is_empty()),
note: self.note.map(|n| n.to_string()).filter(|n| !n.is_empty()),
+ is_since_rustc_version: self.is_since_rustc_version,
}
}
}
classes.push("unstable");
}
- if s.deprecation.is_some() {
+ // FIXME: what about non-staged API items that are deprecated?
+ if self.deprecation.is_some() {
classes.push("deprecated");
}
ItemType::from(self)
}
- /// Returns the info in the item's `#[deprecated]` or `#[rustc_deprecated]` attributes.
- ///
- /// If the item is not deprecated, returns `None`.
- pub fn deprecation(&self) -> Option<&Deprecation> {
- self.deprecation
- .as_ref()
- .or_else(|| self.stability.as_ref().and_then(|s| s.deprecation.as_ref()))
- }
pub fn is_default(&self) -> bool {
match self.inner {
ItemEnum::MethodItem(ref meth) => {
pub level: stability::StabilityLevel,
pub feature: Option<String>,
pub since: String,
- pub deprecation: Option<Deprecation>,
pub unstable_reason: Option<String>,
pub issue: Option<NonZeroU32>,
}
pub struct Deprecation {
pub since: Option<String>,
pub note: Option<String>,
+ pub is_since_rustc_version: bool,
}
/// An type binding on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
}
// The trailing space after each tag is to space it properly against the rest of the docs.
- if item.deprecation().is_some() {
+ if let Some(depr) = &item.deprecation {
let mut message = "Deprecated";
- if let Some(ref stab) = item.stability {
- if let Some(ref depr) = stab.deprecation {
- if let Some(ref since) = depr.since {
- if !stability::deprecation_in_effect(&since) {
- message = "Deprecation planned";
- }
- }
- }
+ if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) {
+ message = "Deprecation planned";
}
tags += &tag_html("deprecated", message);
}
let mut stability = vec![];
let error_codes = cx.shared.codes;
- if let Some(Deprecation { note, since }) = &item.deprecation() {
+ if let Some(Deprecation { ref note, ref since, is_since_rustc_version }) = item.deprecation {
// We display deprecation messages for #[deprecated] and #[rustc_deprecated]
// but only display the future-deprecation messages for #[rustc_deprecated].
let mut message = if let Some(since) = since {
- format!("Deprecated since {}", Escape(since))
+ if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) {
+ format!("Deprecating in {}", Escape(&since))
+ } else {
+ format!("Deprecated since {}", Escape(&since))
+ }
} else {
String::from("Deprecated")
};
- if let Some(ref stab) = item.stability {
- if let Some(ref depr) = stab.deprecation {
- if let Some(ref since) = depr.since {
- if !stability::deprecation_in_effect(&since) {
- message = format!("Deprecating in {}", Escape(&since));
- }
- }
- }
- }
if let Some(note) = note {
let mut ids = cx.id_map.borrow_mut();
/* Media Queries */
+@media (min-width: 701px) {
+ /* In case there is no documentation before a code block, we need to add some margin at the top
+ to prevent an overlay between the "collapse toggle" and the information tooltip.
+ However, it's needed needed with smaller screen width because the doc/code block is always put
+ "one line" below. */
+ .information:first-child > .tooltip {
+ margin-top: 16px;
+ }
+}
+
@media (max-width: 700px) {
body {
padding-top: 0px;
#main > .line-numbers {
margin-top: 0;
}
+
+ .important-traits .important-traits-tooltiptext {
+ left: 0;
+ top: 100%;
+ }
}
@media print {
background-color: #14191f;
}
+.logo-container > img {
+ filter: drop-shadow(0 0 5px #fff);
+}
+
/* Improve the scrollbar display on firefox */
* {
scrollbar-color: #5c6773 transparent;
#crate-search+.search-input:focus {
box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
- color: #ffffff;
- background-color: #141920;
- box-shadow: none;
- transition: box-shadow 150ms ease-in-out;
- border-radius: 4px;
- margin-left: 8px;
-}
-
-#crate-search+.search-input:focus {
- box-shadow: 0px 6px 20px 0px black;
}
.search-focus:disabled {
font-size: 100%;
color: #788797;
border-radius: 4px;
- background-color: rgba(255, 255, 255, 0);
+ background-color: rgba(57, 175, 215, 0.09);
}
a.test-arrow:hover {
- background-color: rgba(242, 151, 24, 0.05);
- color: #ffb44c;
+ background-color: rgba(57, 175, 215, 0.368);
+ color: #c5c5c5;
}
.toggle-label {
:target > code, :target > .in-band {
background: rgba(255, 236, 164, 0.06);
- border-right: 3px solid #ffb44c;
+ border-right: 3px solid rgba(255, 180, 76, 0.85);
}
pre.compile_fail {
background-color: #505050;
}
+.logo-container > img {
+ filter: drop-shadow(0 0 5px #fff);
+}
+
/* Improve the scrollbar display on firefox */
* {
scrollbar-color: rgb(64, 65, 67) #717171;
:target > code, :target > .in-band {
background-color: #494a3d;
+ border-right: 3px solid #bb7410;
}
pre.compile_fail {
scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
}
+.logo-container > img {
+ filter: drop-shadow(0 0 5px #aaa);
+}
+
/* Improve the scrollbar display on webkit-based browsers */
::-webkit-scrollbar-track {
background-color: #ecebeb;
:target > code, :target > .in-band {
background: #FDFFD3;
+ border-right: 3px solid #ffb44c;
}
pre.compile_fail {
use rustc_ast::ast;
-use rustc_errors::Applicability;
+use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_expand::base::SyntaxExtensionKind;
use rustc_feature::UnstableFeatures;
use rustc_hir as hir;
enum ErrorKind {
ResolutionFailure,
- AnchorFailure(&'static str),
+ AnchorFailure(AnchorFailure),
+}
+
+enum AnchorFailure {
+ MultipleAnchors,
+ Primitive,
+ Variant,
+ AssocConstant,
+ AssocType,
+ Field,
+ Method,
}
struct LinkCollector<'a, 'tcx> {
// Not a trait item; just return what we found.
Res::PrimTy(..) => {
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(
- "primitive types cannot be followed by anchors",
- ));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
return Ok((res, Some(path_str.to_owned())));
}
if disambiguator == Some("type") {
if let Some(prim) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(
- "primitive types cannot be followed by anchors",
- ));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
return Ok((prim, Some(path_str.to_owned())));
}
}
} else if let Some(prim) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(
- "primitive types cannot be followed by anchors",
- ));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
}
return Ok((prim, Some(path_str.to_owned())));
} else {
};
if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Fn {
- "methods cannot be followed by anchors"
+ AnchorFailure::Method
} else {
- "associated constants cannot be followed by anchors"
+ AnchorFailure::AssocConstant
}))
} else {
Ok((ty_res, Some(format!("{}.{}", out, item_name))))
} {
if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(if def.is_enum() {
- "enum variants cannot be followed by anchors"
+ AnchorFailure::Variant
} else {
- "struct fields cannot be followed by anchors"
+ AnchorFailure::Field
}))
} else {
Ok((
if extra_fragment.is_some() {
Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const {
- "associated constants cannot be followed by anchors"
+ AnchorFailure::AssocConstant
} else if item.kind == ty::AssocKind::Type {
- "associated types cannot be followed by anchors"
+ AnchorFailure::AssocType
} else {
- "methods cannot be followed by anchors"
+ AnchorFailure::Method
}))
} else {
Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
let link = ori_link.replace("`", "");
let parts = link.split('#').collect::<Vec<_>>();
let (link, extra_fragment) = if parts.len() > 2 {
- build_diagnostic(
- cx,
- &item,
- &link,
- &dox,
- link_range,
- "has an issue with the link anchor.",
- "only one `#` is allowed in a link",
- None,
- );
+ anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors);
continue;
} else if parts.len() == 2 {
if parts[0].trim().is_empty() {
item.attrs.links.push((ori_link, None, fragment));
} else {
debug!("intra-doc link to {} resolved to {:?}", path_str, res);
- if let Some(local) = res.opt_def_id().and_then(|def_id| def_id.as_local()) {
+
+ // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+ if let Some((src_id, dst_id)) = res
+ .opt_def_id()
+ .and_then(|def_id| def_id.as_local())
+ .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
+ {
use rustc_hir::def_id::LOCAL_CRATE;
- let hir_id = self.cx.tcx.hir().as_local_hir_id(local);
- if !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_id)
- && (item.visibility == Visibility::Public)
- && !self.cx.render_options.document_private
+ let hir_src = self.cx.tcx.hir().as_local_hir_id(src_id);
+ let hir_dst = self.cx.tcx.hir().as_local_hir_id(dst_id);
+
+ if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
+ && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
{
- let item_name = item.name.as_deref().unwrap_or("<unknown>");
- let err_msg = format!(
- "public documentation for `{}` links to a private item",
- item_name
- );
- build_diagnostic(
- cx,
- &item,
- path_str,
- &dox,
- link_range,
- &err_msg,
- "this item is private",
- None,
- );
+ privacy_error(cx, &item, &path_str, &dox, link_range);
continue;
}
}
}
}
-fn build_diagnostic(
+/// Reports a diagnostic for an intra-doc link.
+///
+/// If no link range is provided, or the source span of the link cannot be determined, the span of
+/// the entire documentation block is used for the lint. If a range is provided but the span
+/// calculation fails, a note is added to the diagnostic pointing to the link in the markdown.
+///
+/// The `decorate` callback is invoked in all cases to allow further customization of the
+/// diagnostic before emission. If the span of the link was able to be determined, the second
+/// parameter of the callback will contain it, and the primary span of the diagnostic will be set
+/// to it.
+fn report_diagnostic(
cx: &DocContext<'_>,
+ msg: &str,
item: &Item,
- path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
- err_msg: &str,
- short_err_msg: &str,
- help_msg: Option<&str>,
+ decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option<rustc_span::Span>),
) {
let hir_id = match cx.as_local_hir_id(item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- info!("ignoring warning from parent crate: {}", err_msg);
+ info!("ignoring warning from parent crate: {}", msg);
return;
}
};
+
let attrs = &item.attrs;
let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
hir_id,
sp,
|lint| {
- let mut diag = lint.build(&format!("`[{}]` {}", path_str, err_msg));
+ let mut diag = lint.build(msg);
+
+ let span = link_range
+ .as_ref()
+ .and_then(|range| super::source_span_for_markdown_range(cx, dox, range, attrs));
+
if let Some(link_range) = link_range {
- if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
- {
+ if let Some(sp) = span {
diag.set_span(sp);
- diag.span_label(sp, short_err_msg);
} else {
// blah blah blah\nblah\nblah [blah] blah blah\nblah blah
// ^ ~~~~
found = link_range.len(),
));
}
- };
- if let Some(help_msg) = help_msg {
- diag.help(help_msg);
}
+
+ decorate(&mut diag, span);
+
diag.emit();
},
);
}
-/// Reports a resolution failure diagnostic.
-///
-/// If we cannot find the exact source span of the resolution failure, we use the span of the
-/// documentation attributes themselves. This is a little heavy-handed, so we display the markdown
-/// line containing the failure as a note as well.
fn resolution_failure(
cx: &DocContext<'_>,
item: &Item,
dox: &str,
link_range: Option<Range<usize>>,
) {
- build_diagnostic(
+ report_diagnostic(
cx,
+ &format!("unresolved link to `{}`", path_str),
item,
- path_str,
dox,
link_range,
- "cannot be resolved, ignoring it.",
- "cannot be resolved, ignoring",
- Some("to escape `[` and `]` characters, just add '\\' before them like `\\[` or `\\]`"),
+ |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "unresolved link");
+ }
+
+ diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#);
+ },
);
}
path_str: &str,
dox: &str,
link_range: Option<Range<usize>>,
- msg: &str,
+ failure: AnchorFailure,
) {
- build_diagnostic(
- cx,
- item,
- path_str,
- dox,
- link_range,
- "has an issue with the link anchor.",
- msg,
- None,
- );
+ let msg = match failure {
+ AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str),
+ AnchorFailure::Primitive
+ | AnchorFailure::Variant
+ | AnchorFailure::AssocConstant
+ | AnchorFailure::AssocType
+ | AnchorFailure::Field
+ | AnchorFailure::Method => {
+ let kind = match failure {
+ AnchorFailure::Primitive => "primitive type",
+ AnchorFailure::Variant => "enum variant",
+ AnchorFailure::AssocConstant => "associated constant",
+ AnchorFailure::AssocType => "associated type",
+ AnchorFailure::Field => "struct field",
+ AnchorFailure::Method => "method",
+ AnchorFailure::MultipleAnchors => unreachable!("should be handled already"),
+ };
+
+ format!(
+ "`{}` contains an anchor, but links to {kind}s are already anchored",
+ path_str,
+ kind = kind
+ )
+ }
+ };
+
+ report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "contains invalid anchor");
+ }
+ });
}
fn ambiguity_error(
link_range: Option<Range<usize>>,
candidates: PerNS<Option<Res>>,
) {
- let hir_id = match cx.as_local_hir_id(item.def_id) {
- Some(hir_id) => hir_id,
- None => {
- // If non-local, no need to check anything.
- return;
+ let mut msg = format!("`{}` is ", path_str);
+
+ let candidates = [TypeNS, ValueNS, MacroNS]
+ .iter()
+ .filter_map(|&ns| candidates[ns].map(|res| (res, ns)))
+ .collect::<Vec<_>>();
+ match candidates.as_slice() {
+ [(first_def, _), (second_def, _)] => {
+ msg += &format!(
+ "both {} {} and {} {}",
+ first_def.article(),
+ first_def.descr(),
+ second_def.article(),
+ second_def.descr(),
+ );
}
- };
- let attrs = &item.attrs;
- let sp = span_of_attrs(attrs).unwrap_or(item.source.span());
-
- cx.tcx.struct_span_lint_hir(
- lint::builtin::INTRA_DOC_LINK_RESOLUTION_FAILURE,
- hir_id,
- sp,
- |lint| {
- let mut msg = format!("`{}` is ", path_str);
-
- let candidates = [TypeNS, ValueNS, MacroNS]
- .iter()
- .filter_map(|&ns| candidates[ns].map(|res| (res, ns)))
- .collect::<Vec<_>>();
- match candidates.as_slice() {
- [(first_def, _), (second_def, _)] => {
- msg += &format!(
- "both {} {} and {} {}",
- first_def.article(),
- first_def.descr(),
- second_def.article(),
- second_def.descr(),
- );
- }
- _ => {
- let mut candidates = candidates.iter().peekable();
- while let Some((res, _)) = candidates.next() {
- if candidates.peek().is_some() {
- msg += &format!("{} {}, ", res.article(), res.descr());
- } else {
- msg += &format!("and {} {}", res.article(), res.descr());
- }
- }
+ _ => {
+ let mut candidates = candidates.iter().peekable();
+ while let Some((res, _)) = candidates.next() {
+ if candidates.peek().is_some() {
+ msg += &format!("{} {}, ", res.article(), res.descr());
+ } else {
+ msg += &format!("and {} {}", res.article(), res.descr());
}
}
+ }
+ }
- let mut diag = lint.build(&msg);
-
- if let Some(link_range) = link_range {
- if let Some(sp) = super::source_span_for_markdown_range(cx, dox, &link_range, attrs)
- {
- diag.set_span(sp);
- diag.span_label(sp, "ambiguous link");
+ report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "ambiguous link");
- for (res, ns) in candidates {
- let (action, mut suggestion) = match res {
- Res::Def(DefKind::AssocFn | DefKind::Fn, _) => {
- ("add parentheses", format!("{}()", path_str))
- }
- Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
- ("add an exclamation mark", format!("{}!", path_str))
- }
- _ => {
- let type_ = match (res, ns) {
- (Res::Def(DefKind::Const, _), _) => "const",
- (Res::Def(DefKind::Static, _), _) => "static",
- (Res::Def(DefKind::Struct, _), _) => "struct",
- (Res::Def(DefKind::Enum, _), _) => "enum",
- (Res::Def(DefKind::Union, _), _) => "union",
- (Res::Def(DefKind::Trait, _), _) => "trait",
- (Res::Def(DefKind::Mod, _), _) => "module",
- (_, TypeNS) => "type",
- (_, ValueNS) => "value",
- (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => {
- "derive"
- }
- (_, MacroNS) => "macro",
- };
+ let link_range = link_range.expect("must have a link range if we have a span");
- // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
- ("prefix with the item type", format!("{}@{}", type_, path_str))
- }
+ for (res, ns) in candidates {
+ let (action, mut suggestion) = match res {
+ Res::Def(DefKind::AssocFn | DefKind::Fn, _) => {
+ ("add parentheses", format!("{}()", path_str))
+ }
+ Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
+ ("add an exclamation mark", format!("{}!", path_str))
+ }
+ _ => {
+ let type_ = match (res, ns) {
+ (Res::Def(DefKind::Const, _), _) => "const",
+ (Res::Def(DefKind::Static, _), _) => "static",
+ (Res::Def(DefKind::Struct, _), _) => "struct",
+ (Res::Def(DefKind::Enum, _), _) => "enum",
+ (Res::Def(DefKind::Union, _), _) => "union",
+ (Res::Def(DefKind::Trait, _), _) => "trait",
+ (Res::Def(DefKind::Mod, _), _) => "module",
+ (_, TypeNS) => "type",
+ (_, ValueNS) => "value",
+ (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => "derive",
+ (_, MacroNS) => "macro",
};
- if dox.bytes().nth(link_range.start) == Some(b'`') {
- suggestion = format!("`{}`", suggestion);
- }
-
- diag.span_suggestion(
- sp,
- &format!("to link to the {}, {}", res.descr(), action),
- suggestion,
- Applicability::MaybeIncorrect,
- );
+ // FIXME: if this is an implied shortcut link, it's bad style to suggest `@`
+ ("prefix with the item type", format!("{}@{}", type_, path_str))
}
- } else {
- // blah blah blah\nblah\nblah [blah] blah blah\nblah blah
- // ^ ~~~~
- // | link_range
- // last_new_line_offset
- let last_new_line_offset =
- dox[..link_range.start].rfind('\n').map_or(0, |n| n + 1);
- let line = dox[last_new_line_offset..].lines().next().unwrap_or("");
+ };
- // Print the line containing the `link_range` and manually mark it with '^'s.
- diag.note(&format!(
- "the link appears in this line:\n\n{line}\n\
- {indicator: <before$}{indicator:^<found$}",
- line = line,
- indicator = "",
- before = link_range.start - last_new_line_offset,
- found = link_range.len(),
- ));
+ if dox.bytes().nth(link_range.start) == Some(b'`') {
+ suggestion = format!("`{}`", suggestion);
}
+
+ // FIXME: Create a version of this suggestion for when we don't have the span.
+ diag.span_suggestion(
+ sp,
+ &format!("to link to the {}, {}", res.descr(), action),
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
}
- diag.emit();
- },
- );
+ }
+ });
+}
+
+fn privacy_error(
+ cx: &DocContext<'_>,
+ item: &Item,
+ path_str: &str,
+ dox: &str,
+ link_range: Option<Range<usize>>,
+) {
+ let item_name = item.name.as_deref().unwrap_or("<unknown>");
+ let msg =
+ format!("public documentation for `{}` links to private item `{}`", item_name, path_str);
+
+ report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| {
+ if let Some(sp) = sp {
+ diag.span_label(sp, "this item is private");
+ }
+
+ let note_msg = if cx.render_options.document_private {
+ "this link resolves only because you passed `--document-private-items`, but will break without"
+ } else {
+ "this link will resolve properly if you pass `--document-private-items`"
+ };
+ diag.note(note_msg);
+ });
}
/// Given an enum variant's res, return the res of its enum and the associated fragment.
use rustc_middle::ty::DefIdTree;
if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure("variants cannot be followed by anchors"));
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant));
}
let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) {
parent
authors = ["The Rust Project Developers"]
name = "std"
version = "0.0.0"
-build = "build.rs"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rust-lang/rust.git"
description = "The Rust Standard Library"
unwind = { path = "../libunwind" }
hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] }
-# Dependencies of the `backtrace` crate
-addr2line = { version = "0.13.0", optional = true, default-features = false }
-rustc-demangle = { version = "0.1.4", optional = true }
-miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
-[dependencies.object]
-version = "0.20"
-optional = true
-default-features = false
-features = ['read_core', 'elf', 'macho', 'pe']
+[dependencies.backtrace_rs]
+package = "backtrace"
+version = "0.3.46"
+default-features = false # without the libstd `backtrace` feature, stub out everything
+features = [ "rustc-dep-of-std" ] # enable build support for integrating into libstd
[dev-dependencies]
rand = "0.7"
fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
-hermit-abi = { version = "0.1.14", features = ['rustc-dep-of-std'] }
+hermit-abi = { version = "0.1.15", features = ['rustc-dep-of-std'] }
[target.wasm32-wasi.dependencies]
wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
[features]
backtrace = [
- "gimli-symbolize",
- 'addr2line/rustc-dep-of-std',
- 'object/rustc-dep-of-std',
- 'rustc-demangle/rustc-dep-of-std',
- 'miniz_oxide/rustc-dep-of-std',
+ "backtrace_rs/dbghelp", # backtrace/symbolize on MSVC
+ "backtrace_rs/libbacktrace", # symbolize on most platforms
+ "backtrace_rs/libunwind", # backtrace on most platforms
+ "backtrace_rs/dladdr", # symbolize on platforms w/o libbacktrace
]
-gimli-symbolize = []
panic-unwind = ["panic_unwind"]
profiler = ["profiler_builtins"]
// `Backtrace`, but that's a relatively small price to pay relative to capturing
// a backtrace or actually symbolizing it.
-use crate::backtrace_rs::{self, BytesOrWideString};
use crate::env;
use crate::ffi::c_void;
use crate::fmt;
use crate::sync::Mutex;
use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec;
+use backtrace::BytesOrWideString;
+use backtrace_rs as backtrace;
/// A captured OS thread stack backtrace.
///
}
enum RawFrame {
- Actual(backtrace_rs::Frame),
+ Actual(backtrace::Frame),
#[cfg(test)]
Fake,
}
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(fmt, "{{ ")?;
- if let Some(fn_name) = self.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)) {
+ if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
write!(fmt, "fn: \"{:#}\"", fn_name)?;
} else {
write!(fmt, "fn: <unknown>")?;
BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
},
- backtrace_rs::PrintFmt::Short,
+ backtrace::PrintFmt::Short,
crate::env::current_dir().as_ref().ok(),
)
}
Backtrace::create(Backtrace::force_capture as usize)
}
+ /// Forcibly captures a disabled backtrace, regardless of environment
+ /// variable configuration.
+ pub const fn disabled() -> Backtrace {
+ Backtrace { inner: Inner::Disabled }
+ }
+
// Capture a backtrace which start just before the function addressed by
// `ip`
fn create(ip: usize) -> Backtrace {
let mut frames = Vec::new();
let mut actual_start = None;
unsafe {
- backtrace_rs::trace_unsynchronized(|frame| {
+ backtrace::trace_unsynchronized(|frame| {
frames.push(BacktraceFrame {
frame: RawFrame::Actual(frame.clone()),
symbols: Vec::new(),
let full = fmt.alternate();
let (frames, style) = if full {
- (&capture.frames[..], backtrace_rs::PrintFmt::Full)
+ (&capture.frames[..], backtrace::PrintFmt::Full)
} else {
- (&capture.frames[capture.actual_start..], backtrace_rs::PrintFmt::Short)
+ (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
};
// When printing paths we try to strip the cwd if it exists, otherwise
output_filename(fmt, path, style, cwd.as_ref().ok())
};
- let mut f = backtrace_rs::BacktraceFmt::new(fmt, style, &mut print_path);
+ let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
f.add_context()?;
for frame in frames {
let mut f = f.frame();
for symbol in frame.symbols.iter() {
f.print_raw(
frame.frame.ip(),
- symbol.name.as_ref().map(|b| backtrace_rs::SymbolName::new(b)),
+ symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
symbol.filename.as_ref().map(|b| match b {
BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
RawFrame::Fake => unimplemented!(),
};
unsafe {
- backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| {
+ backtrace::resolve_frame_unsynchronized(frame, |symbol| {
symbols.push(BacktraceSymbol {
name: symbol.name().map(|m| m.as_bytes().to_vec()),
filename: symbol.filename_raw().map(|b| match b {
use std::env;
fn main() {
+ println!("cargo:rerun-if-changed=build.rs");
let target = env::var("TARGET").expect("TARGET was not set");
if target.contains("linux") {
if target.contains("android") {
println!("cargo:rustc-cfg=feature=\"restricted-std\"");
}
println!("cargo:rustc-env=STD_ENV_ARCH={}", env::var("CARGO_CFG_TARGET_ARCH").unwrap());
- println!("cargo:rustc-cfg=backtrace_in_libstd");
}
//! cost are suffixed with a `~`.
//!
//! All amortized costs are for the potential need to resize when capacity is
-//! exhausted. If a resize occurs it will take O(n) time. Our collections never
+//! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never
//! automatically shrink, so removal operations aren't amortized. Over a
//! sufficiently large series of operations, the average cost per operation will
//! deterministically equal the given cost.
assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0);
assert_approx_eq!(f32::from_bits(0xc1640000), -14.25);
- // Check that NaNs roundtrip their bits regardless of signalingness
+ // Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA;
let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555;
assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
- // Check that NaNs roundtrip their bits regardless of signalingness
+ // Check that NaNs roundtrip their bits regardless of signaling-ness
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
/// No guarantees are provided about the contents of `buf` when this
/// function is called, implementations cannot rely on any property of the
/// contents of `buf` being true. It is recommended that implementations
- /// only write data to `buf` instead of reading its contents.
+ /// only write data to `buf` instead of reading its contents. The
+ /// documentation on [`read`] has a more detailed explanation on this
+ /// subject.
///
/// # Errors
///
///
/// [`File`]s implement `Read`:
///
+ /// [`read`]: Read::read
/// [`File`]: crate::fs::File
///
/// ```no_run
//
/// A value of type [`bool`] representing logical **false**.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `false` is the logical opposite of [`true`].
///
-/// [`bool`]: primitive.bool.html
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// See the documentation for [`true`] for more information.
+///
+/// [`true`]: keyword.true.html
mod false_keyword {}
#[doc(keyword = "fn")]
/// * `for` is also used for [higher-ranked trait bounds] as in `for<'a> &'a T: PartialEq<i32>`.
///
/// for-in-loops, or to be more precise, iterator loops, are a simple syntactic sugar over a common
-/// practice within Rust, which is to loop over an iterator until that iterator returns `None` (or
-/// `break` is called).
+/// practice within Rust, which is to loop over anything that implements [`IntoIterator`] until the
+/// iterator returned by `.into_iter()` returns `None` (or the loop body uses `break`).
///
/// ```rust
/// for i in 0..5 {
//
/// Iterate over a series of values with [`for`].
///
-/// The expression immediately following `in` must implement the [`Iterator`] trait.
+/// The expression immediately following `in` must implement the [`IntoIterator`] trait.
///
/// ## Literal Examples:
///
///
/// (Read more about [range patterns])
///
-/// [`Iterator`]: ../book/ch13-04-performance.html
+/// [`IntoIterator`]: ../book/ch13-04-performance.html
/// [range patterns]: ../reference/patterns.html?highlight=range#range-patterns
/// [`for`]: keyword.for.html
mod in_keyword {}
//
/// Bind by reference during pattern matching.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `ref` annotates pattern bindings to make them borrow rather than move.
+/// It is **not** a part of the pattern as far as matching is concerned: it does
+/// not affect *whether* a value is matched, only *how* it is matched.
///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// By default, [`match`] statements consume all they can, which can sometimes
+/// be a problem, when you don't really need the value to be moved and owned:
+///
+/// ```compile_fail,E0382
+/// let maybe_name = Some(String::from("Alice"));
+/// // The variable 'maybe_name' is consumed here ...
+/// match maybe_name {
+/// Some(n) => println!("Hello, {}", n),
+/// _ => println!("Hello, world"),
+/// }
+/// // ... and is now unavailable.
+/// println!("Hello again, {}", maybe_name.unwrap_or("world".into()));
+/// ```
+///
+/// Using the `ref` keyword, the value is only borrowed, not moved, making it
+/// available for use after the [`match`] statement:
+///
+/// ```
+/// let maybe_name = Some(String::from("Alice"));
+/// // Using `ref`, the value is borrowed, not moved ...
+/// match maybe_name {
+/// Some(ref n) => println!("Hello, {}", n),
+/// _ => println!("Hello, world"),
+/// }
+/// // ... so it's available here!
+/// println!("Hello again, {}", maybe_name.unwrap_or("world".into()));
+/// ```
+///
+/// # `&` vs `ref`
+///
+/// - `&` denotes that your pattern expects a reference to an object. Hence `&`
+/// is a part of said pattern: `&Foo` matches different objects than `Foo` does.
+///
+/// - `ref` indicates that you want a reference to an unpacked value. It is not
+/// matched against: `Foo(ref foo)` matches the same objects as `Foo(foo)`.
+///
+/// See also the [Reference] for more information.
+///
+/// [`match`]: keyword.match.html
+/// [Reference]: ../reference/patterns.html#identifier-patterns
mod ref_keyword {}
#[doc(keyword = "return")]
//
/// Add constraints that must be upheld to use an item.
///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// `where` allows specifying constraints on lifetime and generic parameters.
+/// The [RFC] introducing `where` contains detailed informations about the
+/// keyword.
///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+/// # Examples
+///
+/// `where` can be used for constraints with traits:
+///
+/// ```rust
+/// fn new<T: Default>() -> T {
+/// T::default()
+/// }
+///
+/// fn new_where<T>() -> T
+/// where
+/// T: Default,
+/// {
+/// T::default()
+/// }
+///
+/// assert_eq!(0.0, new());
+/// assert_eq!(0.0, new_where());
+///
+/// assert_eq!(0, new());
+/// assert_eq!(0, new_where());
+/// ```
+///
+/// `where` can also be used for lifetimes.
+///
+/// This compiles because `longer` outlives `shorter`, thus the constraint is
+/// respected:
+///
+/// ```rust
+/// fn select<'short, 'long>(s1: &'short str, s2: &'long str, second: bool) -> &'short str
+/// where
+/// 'long: 'short,
+/// {
+/// if second { s2 } else { s1 }
+/// }
+///
+/// let outer = String::from("Long living ref");
+/// let longer = &outer;
+/// {
+/// let inner = String::from("Short living ref");
+/// let shorter = &inner;
+///
+/// assert_eq!(select(shorter, longer, false), shorter);
+/// assert_eq!(select(shorter, longer, true), longer);
+/// }
+/// ```
+///
+/// On the other hand, this will not compile because the `where 'b: 'a` clause
+/// is missing: the `'b` lifetime is not known to live at least as long as `'a`
+/// which means this function cannot ensure it always returns a valid reference:
+///
+/// ```rust,compile_fail,E0623
+/// fn select<'a, 'b>(s1: &'a str, s2: &'b str, second: bool) -> &'a str
+/// {
+/// if second { s2 } else { s1 }
+/// }
+/// ```
+///
+/// `where` can also be used to express more complicated constraints that cannot
+/// be written with the `<T: Trait>` syntax:
+///
+/// ```rust
+/// fn first_or_default<I>(mut i: I) -> I::Item
+/// where
+/// I: Iterator,
+/// I::Item: Default,
+/// {
+/// i.next().unwrap_or_else(I::Item::default)
+/// }
+///
+/// assert_eq!(first_or_default(vec![1, 2, 3].into_iter()), 1);
+/// assert_eq!(first_or_default(Vec::<i32>::new().into_iter()), 0);
+/// ```
+///
+/// `where` is available anywhere generic and lifetime parameters are available,
+/// as can be seen with the [`Cow`](crate::borrow::Cow) type from the standard
+/// library:
+///
+/// ```rust
+/// # #![allow(dead_code)]
+/// pub enum Cow<'a, B>
+/// where
+/// B: 'a + ToOwned + ?Sized,
+/// {
+/// Borrowed(&'a B),
+/// Owned(<B as ToOwned>::Owned),
+/// }
+/// ```
+///
+/// [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/0135-where.md
mod where_keyword {}
// 2018 Edition keywords
all(target_vendor = "fortanix", target_env = "sgx"),
feature(slice_index_methods, coerce_unsized, sgx_platform, ptr_wrapping_offset_from)
)]
-#![cfg_attr(
- all(test, target_vendor = "fortanix", target_env = "sgx"),
- feature(fixed_size_array, maybe_uninit_extra)
-)]
+#![cfg_attr(all(test, target_vendor = "fortanix", target_env = "sgx"), feature(fixed_size_array))]
// std is implemented with unstable features, many of which are internal
// compiler details that will never be stable
// NB: the following list is sorted to minimize merge conflicts.
// compiler
pub mod rt;
-#[path = "../backtrace/src/lib.rs"]
-#[allow(dead_code, unused_attributes)]
-mod backtrace_rs;
-
// Pull in the `std_detect` crate directly into libstd. The contents of
// `std_detect` are in a different repository: rust-lang/stdarch.
//
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
- /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ /// Returns the "preferred" block size for efficient filesystem I/O.
///
/// # Examples
///
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
- /// Returns the "preferred" blocksize for efficient filesystem I/O.
+ /// Returns the "preferred" block size for efficient filesystem I/O.
///
/// # Examples
///
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
let backtrace_env = if panic_count::get() >= 2 {
- RustBacktrace::Print(crate::backtrace_rs::PrintFmt::Full)
+ RustBacktrace::Print(backtrace_rs::PrintFmt::Full)
} else {
backtrace::rust_backtrace_env()
};
///
/// let path = Path::new("foo.rs");
/// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
+ ///
+ /// let path = Path::new("foo.tar.gz");
+ /// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`.
/// The type of `x` must be [`Copy`][copy].
///
-/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if
-/// the element type allows it:
+/// Arrays of *any* size implement the following traits if the element type allows it:
///
/// - [`Debug`][debug]
/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`)
/// - [`Hash`][hash]
/// - [`AsRef`][asref], [`AsMut`][asmut]
/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut]
-/// - [`Default`][default]
///
-/// This limitation on the size `N` exists because Rust does not yet support
-/// code that is generic over the size of an array type. `[Foo; 3]` and `[Bar; 3]`
-/// are instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are
-/// entirely different types. As a stopgap, trait implementations are
+/// Arrays of sizes from 0 to 32 (inclusive) implement [`Default`][default] trait
+/// if the element type allows it. As a stopgap, trait implementations are
/// statically generated up to size 32.
///
/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy]
/// for x in array.iter() { }
/// ```
///
-/// If the array has 32 or fewer elements (see above), you can also use the
-/// array reference's [`IntoIterator`] implementation:
+/// You can also use the array reference's [`IntoIterator`] implementation:
///
/// ```
/// # let array: [i32; 3] = [0; 3];
-use crate::cmp;
+use crate::ffi::c_void;
+use crate::ptr;
+use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sys::hermit::abi;
use crate::sys::mutex::Mutex;
use crate::time::Duration;
+// The implementation is inspired by Andrew D. Birrell's paper
+// "Implementing Condition Variables with Semaphores"
+
pub struct Condvar {
- identifier: usize,
+ counter: AtomicUsize,
+ sem1: *const c_void,
+ sem2: *const c_void,
}
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
impl Condvar {
pub const fn new() -> Condvar {
- Condvar { identifier: 0 }
+ Condvar { counter: AtomicUsize::new(0), sem1: ptr::null(), sem2: ptr::null() }
}
pub unsafe fn init(&mut self) {
- let _ = abi::init_queue(self.id());
+ let _ = abi::sem_init(&mut self.sem1 as *mut *const c_void, 0);
+ let _ = abi::sem_init(&mut self.sem2 as *mut *const c_void, 0);
}
pub unsafe fn notify_one(&self) {
- let _ = abi::notify(self.id(), 1);
+ if self.counter.load(SeqCst) > 0 {
+ self.counter.fetch_sub(1, SeqCst);
+ abi::sem_post(self.sem1);
+ abi::sem_timedwait(self.sem2, 0);
+ }
}
- #[inline]
pub unsafe fn notify_all(&self) {
- let _ = abi::notify(self.id(), -1 /* =all */);
+ let counter = self.counter.swap(0, SeqCst);
+ for _ in 0..counter {
+ abi::sem_post(self.sem1);
+ }
+ for _ in 0..counter {
+ abi::sem_timedwait(self.sem2, 0);
+ }
}
pub unsafe fn wait(&self, mutex: &Mutex) {
- // add current task to the wait queue
- let _ = abi::add_queue(self.id(), -1 /* no timeout */);
+ self.counter.fetch_add(1, SeqCst);
mutex.unlock();
- let _ = abi::wait(self.id());
+ abi::sem_timedwait(self.sem1, 0);
+ abi::sem_post(self.sem2);
mutex.lock();
}
- pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
- let nanos = dur.as_nanos();
- let nanos = cmp::min(i64::MAX as u128, nanos);
-
- // add current task to the wait queue
- let _ = abi::add_queue(self.id(), nanos as i64);
-
- mutex.unlock();
- // If the return value is !0 then a timeout happened, so we return
- // `false` as we weren't actually notified.
- let ret = abi::wait(self.id()) == 0;
- mutex.lock();
-
- ret
+ pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+ panic!("wait_timeout not supported on hermit");
}
pub unsafe fn destroy(&self) {
- let _ = abi::destroy_queue(self.id());
- }
-
- #[inline]
- fn id(&self) -> usize {
- &self.identifier as *const usize as usize
+ let _ = abi::sem_destroy(self.sem1);
+ let _ = abi::sem_destroy(self.sem2);
}
}
-use super::mutex::Mutex;
+use crate::cell::UnsafeCell;
+use crate::sys::condvar::Condvar;
+use crate::sys::mutex::Mutex;
pub struct RWLock {
- mutex: Mutex,
+ lock: Mutex,
+ cond: Condvar,
+ state: UnsafeCell<State>,
+}
+
+enum State {
+ Unlocked,
+ Reading(usize),
+ Writing,
}
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
+// This rwlock implementation is a relatively simple implementation which has a
+// condition variable for readers/writers as well as a mutex protecting the
+// internal state of the lock. A current downside of the implementation is that
+// unlocking the lock will notify *all* waiters rather than just readers or just
+// writers. This can cause lots of "thundering stampede" problems. While
+// hopefully correct this implementation is very likely to want to be changed in
+// the future.
+
impl RWLock {
pub const fn new() -> RWLock {
- RWLock { mutex: Mutex::new() }
+ RWLock { lock: Mutex::new(), cond: Condvar::new(), state: UnsafeCell::new(State::Unlocked) }
}
#[inline]
pub unsafe fn read(&self) {
- self.mutex.lock();
+ self.lock.lock();
+ while !(*self.state.get()).inc_readers() {
+ self.cond.wait(&self.lock);
+ }
+ self.lock.unlock();
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
- self.mutex.try_lock()
+ self.lock.lock();
+ let ok = (*self.state.get()).inc_readers();
+ self.lock.unlock();
+ return ok;
}
#[inline]
pub unsafe fn write(&self) {
- self.mutex.lock();
+ self.lock.lock();
+ while !(*self.state.get()).inc_writers() {
+ self.cond.wait(&self.lock);
+ }
+ self.lock.unlock();
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
- self.mutex.try_lock()
+ self.lock.lock();
+ let ok = (*self.state.get()).inc_writers();
+ self.lock.unlock();
+ return ok;
}
#[inline]
pub unsafe fn read_unlock(&self) {
- self.mutex.unlock();
+ self.lock.lock();
+ let notify = (*self.state.get()).dec_readers();
+ self.lock.unlock();
+ if notify {
+ // FIXME: should only wake up one of these some of the time
+ self.cond.notify_all();
+ }
}
#[inline]
pub unsafe fn write_unlock(&self) {
- self.mutex.unlock();
+ self.lock.lock();
+ (*self.state.get()).dec_writers();
+ self.lock.unlock();
+ // FIXME: should only wake up one of these some of the time
+ self.cond.notify_all();
}
#[inline]
pub unsafe fn destroy(&self) {
- self.mutex.destroy();
+ self.lock.destroy();
+ self.cond.destroy();
+ }
+}
+
+impl State {
+ fn inc_readers(&mut self) -> bool {
+ match *self {
+ State::Unlocked => {
+ *self = State::Reading(1);
+ true
+ }
+ State::Reading(ref mut cnt) => {
+ *cnt += 1;
+ true
+ }
+ State::Writing => false,
+ }
+ }
+
+ fn inc_writers(&mut self) -> bool {
+ match *self {
+ State::Unlocked => {
+ *self = State::Writing;
+ true
+ }
+ State::Reading(_) | State::Writing => false,
+ }
+ }
+
+ fn dec_readers(&mut self) -> bool {
+ let zero = match *self {
+ State::Reading(ref mut cnt) => {
+ *cnt -= 1;
+ *cnt == 0
+ }
+ State::Unlocked | State::Writing => invalid(),
+ };
+ if zero {
+ *self = State::Unlocked;
+ }
+ zero
}
+
+ fn dec_writers(&mut self) {
+ match *self {
+ State::Writing => {}
+ State::Unlocked | State::Reading(_) => invalid(),
+ }
+ *self = State::Unlocked;
+ }
+}
+
+fn invalid() -> ! {
+ panic!("inconsistent rwlock");
}
self.fd
}
- /// Extracts the actual filedescriptor without closing it.
+ /// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> Fd {
let fd = self.fd;
mem::forget(self);
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime_nsec(&self) -> i64;
- /// Returns the blocksize for filesystem I/O.
+ /// Returns the block size for filesystem I/O.
///
/// # Examples
///
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
- /// let blocksize = meta.blksize();
+ /// let block_size = meta.blksize();
/// Ok(())
/// }
/// ```
use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
use crate::mem;
-use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::cvt;
use crate::sys_common::AsInner;
-use libc::{c_int, c_void, ssize_t};
+use libc::{c_int, c_void};
#[derive(Debug)]
pub struct FileDesc {
fd: c_int,
}
-fn max_len() -> usize {
- // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
- // with the man page quoting that if the count of bytes to read is
- // greater than `SSIZE_MAX` the result is "unspecified".
- //
- // On macOS, however, apparently the 64-bit libc is either buggy or
- // intentionally showing odd behavior by rejecting any read with a size
- // larger than or equal to INT_MAX. To handle both of these the read
- // size is capped on both platforms.
- if cfg!(target_os = "macos") { <c_int>::MAX as usize - 1 } else { <ssize_t>::MAX as usize }
-}
+// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
+// with the man page quoting that if the count of bytes to read is
+// greater than `SSIZE_MAX` the result is "unspecified".
+//
+// On macOS, however, apparently the 64-bit libc is either buggy or
+// intentionally showing odd behavior by rejecting any read with a size
+// larger than or equal to INT_MAX. To handle both of these the read
+// size is capped on both platforms.
+#[cfg(target_os = "macos")]
+const READ_LIMIT: usize = c_int::MAX as usize - 1;
+#[cfg(not(target_os = "macos"))]
+const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()))
+ libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pread64(
self.fd,
buf.as_mut_ptr() as *mut c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()))
+ libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pwrite64(
self.fd,
buf.as_ptr() as *const c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
pub fn duplicate(&self) -> io::Result<FileDesc> {
// We want to atomically duplicate this file descriptor and set the
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
- // flag, however, isn't supported on older Linux kernels (earlier than
- // 2.6.24).
- //
- // To detect this and ensure that CLOEXEC is still set, we
- // follow a strategy similar to musl [1] where if passing
- // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
- // supported (the third parameter, 0, is always valid), so we stop
- // trying that.
- //
- // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
- // resolve so we at least compile this.
- //
- // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
- #[cfg(any(target_os = "android", target_os = "haiku"))]
- use libc::F_DUPFD as F_DUPFD_CLOEXEC;
- #[cfg(not(any(target_os = "android", target_os = "haiku")))]
- use libc::F_DUPFD_CLOEXEC;
-
- let make_filedesc = |fd| {
- let fd = FileDesc::new(fd);
- fd.set_cloexec()?;
- Ok(fd)
- };
- static TRY_CLOEXEC: AtomicBool = AtomicBool::new(!cfg!(target_os = "android"));
- let fd = self.raw();
- if TRY_CLOEXEC.load(Ordering::Relaxed) {
- match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
- // We *still* call the `set_cloexec` method as apparently some
- // linux kernel at some point stopped setting CLOEXEC even
- // though it reported doing so on F_DUPFD_CLOEXEC.
- Ok(fd) => {
- return Ok(if cfg!(target_os = "linux") {
- make_filedesc(fd)?
- } else {
- FileDesc::new(fd)
- });
- }
- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
- TRY_CLOEXEC.store(false, Ordering::Relaxed);
- }
- Err(e) => return Err(e),
- }
- }
- cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
+ // is a POSIX flag that was added to Linux in 2.6.24.
+ let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?;
+ Ok(FileDesc::new(fd))
}
}
// However, since this is a variadic function, C integer promotion rules mean that on
// the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms).
let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?;
- let fd = FileDesc::new(fd);
-
- // Currently the standard library supports Linux 2.6.18 which did not
- // have the O_CLOEXEC flag (passed above). If we're running on an older
- // Linux kernel then the flag is just ignored by the OS. After we open
- // the first file, we check whether it has CLOEXEC set. If it doesn't,
- // we will explicitly ask for a CLOEXEC fd for every further file we
- // open, if it does, we will skip that step.
- //
- // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
- // that we support, so we only do this on Linux currently.
- #[cfg(target_os = "linux")]
- fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> {
- use crate::sync::atomic::{AtomicUsize, Ordering};
-
- const OPEN_CLOEXEC_UNKNOWN: usize = 0;
- const OPEN_CLOEXEC_SUPPORTED: usize = 1;
- const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
- static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
-
- let need_to_set;
- match OPEN_CLOEXEC.load(Ordering::Relaxed) {
- OPEN_CLOEXEC_UNKNOWN => {
- need_to_set = !fd.get_cloexec()?;
- OPEN_CLOEXEC.store(
- if need_to_set {
- OPEN_CLOEXEC_NOTSUPPORTED
- } else {
- OPEN_CLOEXEC_SUPPORTED
- },
- Ordering::Relaxed,
- );
- }
- OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
- OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
- _ => unreachable!(),
- }
- if need_to_set {
- fd.set_cloexec()?;
- }
- Ok(())
- }
-
- #[cfg(not(target_os = "linux"))]
- fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
- Ok(())
- }
-
- ensure_cloexec(&fd)?;
- Ok(File(fd))
+ Ok(File(FileDesc::new(fd)))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
unsafe {
- // On linux we first attempt to pass the SOCK_CLOEXEC flag to
- // atomically create the socket and set it as CLOEXEC. Support for
- // this option, however, was added in 2.6.27, and we still support
- // 2.6.18 as a kernel, so if the returned error is EINVAL we
- // fallthrough to the fallback.
- #[cfg(target_os = "linux")]
- {
- match cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0)) {
- Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
- Err(e) => return Err(e),
- }
- }
-
- let fd = cvt(libc::socket(fam, ty, 0))?;
- let fd = FileDesc::new(fd);
- fd.set_cloexec()?;
- let socket = Socket(fd);
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "linux")] {
+ // On Linux we pass the SOCK_CLOEXEC flag to atomically create
+ // the socket and set it as CLOEXEC, added in 2.6.27.
+ let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
+ Ok(Socket(FileDesc::new(fd)))
+ } else {
+ let fd = cvt(libc::socket(fam, ty, 0))?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ let socket = Socket(fd);
- // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
- // flag to disable `SIGPIPE` emission on socket.
- #[cfg(target_vendor = "apple")]
- setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
+ // macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
+ // flag to disable `SIGPIPE` emission on socket.
+ #[cfg(target_vendor = "apple")]
+ setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
- Ok(socket)
+ Ok(socket)
+ }
+ }
}
}
unsafe {
let mut fds = [0, 0];
- // Like above, see if we can set cloexec atomically
- #[cfg(target_os = "linux")]
- {
- match cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
- Ok(_) => {
- return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
- }
- Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
- Err(e) => return Err(e),
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "linux")] {
+ // Like above, set cloexec atomically
+ cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
+ Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))))
+ } else {
+ cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
+ let a = FileDesc::new(fds[0]);
+ let b = FileDesc::new(fds[1]);
+ a.set_cloexec()?;
+ b.set_cloexec()?;
+ Ok((Socket(a), Socket(b)))
}
}
-
- cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
- let a = FileDesc::new(fds[0]);
- let b = FileDesc::new(fds[1]);
- a.set_cloexec()?;
- b.set_cloexec()?;
- Ok((Socket(a), Socket(b)))
}
}
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
// Unfortunately the only known way right now to accept a socket and
// atomically set the CLOEXEC flag is to use the `accept4` syscall on
- // Linux. This was added in 2.6.28, however, and because we support
- // 2.6.18 we must detect this support dynamically.
- #[cfg(target_os = "linux")]
- {
- syscall! {
- fn accept4(
- fd: c_int,
- addr: *mut sockaddr,
- addr_len: *mut socklen_t,
- flags: c_int
- ) -> c_int
- }
- let res = cvt_r(|| unsafe { accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) });
- match res {
- Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
- Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
- Err(e) => return Err(e),
+ // Linux. This was added in 2.6.28, glibc 2.10 and musl 0.9.5.
+ cfg_if::cfg_if! {
+ if #[cfg(target_os = "linux")] {
+ let fd = cvt_r(|| unsafe {
+ libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC)
+ })?;
+ Ok(Socket(FileDesc::new(fd)))
+ } else {
+ let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(Socket(fd))
}
}
-
- let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?;
- let fd = FileDesc::new(fd);
- fd.set_cloexec()?;
- Ok(Socket(fd))
}
pub fn duplicate(&self) -> io::Result<Socket> {
/// Sets the platform-specific value of errno
#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall!
+#[allow(dead_code)] // but not all target cfgs actually end up using it
pub fn set_errno(e: i32) {
unsafe { *errno_location() = e as c_int }
}
use crate::io::{self, IoSlice, IoSliceMut};
use crate::mem;
-use crate::sync::atomic::{AtomicBool, Ordering};
use crate::sys::fd::FileDesc;
use crate::sys::{cvt, cvt_r};
-use libc::c_int;
-
////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
////////////////////////////////////////////////////////////////////////////////
pub struct AnonPipe(FileDesc);
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
- syscall! { fn pipe2(fds: *mut c_int, flags: c_int) -> c_int }
- static INVALID: AtomicBool = AtomicBool::new(false);
-
let mut fds = [0; 2];
- // Unfortunately the only known way right now to create atomically set the
- // CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
- // 2.6.27, however, and because we support 2.6.18 we must detect this
- // support dynamically.
- if cfg!(any(
- target_os = "dragonfly",
- target_os = "freebsd",
- target_os = "linux",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "redox"
- )) && !INVALID.load(Ordering::SeqCst)
- {
- // Note that despite calling a glibc function here we may still
- // get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
- // emulate on older kernels, so if you happen to be running on
- // an older kernel you may see `pipe2` as a symbol but still not
- // see the syscall.
- match cvt(unsafe { pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
- Ok(_) => {
- return Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))));
- }
- Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
- INVALID.store(true, Ordering::SeqCst);
- }
- Err(e) => return Err(e),
+ // The only known way right now to create atomically set the CLOEXEC flag is
+ // to use the `pipe2` syscall. This was added to Linux in 2.6.27, glibc 2.9
+ // and musl 0.9.3, and some other targets also have it.
+ cfg_if::cfg_if! {
+ if #[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "linux",
+ target_os = "netbsd",
+ target_os = "openbsd",
+ target_os = "redox"
+ ))] {
+ cvt(unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) })?;
+ Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
+ } else {
+ cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
+
+ let fd0 = FileDesc::new(fds[0]);
+ let fd1 = FileDesc::new(fds[1]);
+ fd0.set_cloexec()?;
+ fd1.set_cloexec()?;
+ Ok((AnonPipe(fd0), AnonPipe(fd1)))
}
}
- cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
-
- let fd0 = FileDesc::new(fds[0]);
- let fd1 = FileDesc::new(fds[1]);
- fd0.set_cloexec()?;
- fd1.set_cloexec()?;
- Ok((AnonPipe(fd0), AnonPipe(fd1)))
}
impl AnonPipe {
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).
+// There are a variety of `#[cfg]`s controlling which targets are involved in
+// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
+// that, we'll just allow that some unix targets don't use this module at all.
+#![allow(dead_code, unused_macros)]
+
use crate::ffi::CStr;
use crate::marker;
use crate::mem;
fd: c_int,
}
-fn max_len() -> usize {
- // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
- // with the man page quoting that if the count of bytes to read is
- // greater than `SSIZE_MAX` the result is "unspecified".
- <ssize_t>::MAX as usize
-}
+// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
+// with the man page quoting that if the count of bytes to read is
+// greater than `SSIZE_MAX` the result is "unspecified".
+const READ_LIMIT: usize = ssize_t::MAX as usize;
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
self.fd
}
- /// Extracts the actual filedescriptor without closing it.
+ /// Extracts the actual file descriptor without closing it.
pub fn into_raw(self) -> c_int {
let fd = self.fd;
mem::forget(self);
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), max_len()))
+ libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pread(
self.fd,
buf.as_mut_ptr() as *mut c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
- libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), max_len()))
+ libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
})?;
Ok(ret as usize)
}
cvt_pwrite(
self.fd,
buf.as_ptr() as *const c_void,
- cmp::min(buf.len(), max_len()),
+ cmp::min(buf.len(), READ_LIMIT),
offset as i64,
)
.map(|n| n as usize)
use crate::cmp::Ordering;
use crate::time::Duration;
-use ::core::hash::{Hash, Hasher};
+use core::hash::{Hash, Hasher};
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
use crate::convert::TryInto;
pub use crate::sys::ext::fs::{DirEntryExt, FileExt, MetadataExt, OpenOptionsExt};
#[doc(no_inline)]
#[stable(feature = "rust1", since = "1.0.0")]
- pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd};
+ pub use crate::sys::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
}
///
/// WASI has no fundamental capability to do this. All syscalls and operations
/// are relative to already-open file descriptors. The C library, however,
-/// manages a map of preopened file descriptors to their path, and then the C
+/// manages a map of pre-opened file descriptors to their path, and then the C
/// library provides an API to look at this. In other words, when you want to
/// open a path `p`, you have to find a previously opened file descriptor in a
/// global table and then see if `p` is relative to that file descriptor.
///
/// This function, if successful, will return two items:
///
-/// * The first is a `ManuallyDrop<WasiFd>`. This represents a preopened file
+/// * The first is a `ManuallyDrop<WasiFd>`. This represents a pre-opened file
/// descriptor which we don't have ownership of, but we can use. You shouldn't
/// actually drop the `fd`.
///
/// appropriate rights for performing `rights` actions.
///
/// Note that this can fail if `p` doesn't look like it can be opened relative
-/// to any preopened file descriptor.
+/// to any pre-opened file descriptor.
fn open_parent(p: &Path) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
let p = CString::new(p.as_os_str().as_bytes())?;
unsafe {
let fd = __wasilibc_find_relpath(p.as_ptr(), &mut ret);
if fd == -1 {
let msg = format!(
- "failed to find a preopened file descriptor \
+ "failed to find a pre-opened file descriptor \
through which {:?} could be opened",
p
);
next: *mut Node,
}
+#[cfg(miri)]
+extern "Rust" {
+ /// Miri-provided extern function to mark the block `ptr` points to as a "root"
+ /// for some static memory. This memory and everything reachable by it is not
+ /// considered leaking even if it still exists when the program terminates.
+ ///
+ /// `ptr` has to point to the beginning of an allocated block.
+ fn miri_static_root(ptr: *const u8);
+}
+
unsafe fn register_dtor(key: Key, dtor: Dtor) {
let mut node = Box::new(Node { key, dtor, next: ptr::null_mut() });
loop {
node.next = head;
match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) {
- Ok(_) => return mem::forget(node),
+ Ok(_) => {
+ #[cfg(miri)]
+ miri_static_root(&*node as *const _ as *const u8);
+
+ mem::forget(node);
+ return;
+ }
Err(cur) => head = cur,
}
}
-use crate::backtrace_rs::{self, BacktraceFmt, BytesOrWideString, PrintFmt};
use crate::borrow::Cow;
/// Common code for printing the backtrace in the same way across the different
/// supported platforms.
use crate::sync::atomic::{self, Ordering};
use crate::sys::mutex::Mutex;
+use backtrace_rs::{BacktraceFmt, BytesOrWideString, PrintFmt};
+
/// Max number of frames to print.
const MAX_NB_FRAMES: usize = 100;
authors = ["The Rust Project Developers"]
name = "unwind"
version = "0.0.0"
-build = "build.rs"
edition = "2018"
include = [
'/libunwind/*',
-// compile-flags:-Zprint-mono-items=eager
+// compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on
#![feature(start)]
pub fn foo<T>() { }
-//~ MONO_ITEM fn static_init::foo[0]<i32>
+//~ MONO_ITEM fn static_init::foo[0]<T>
//~ MONO_ITEM static static_init::FN[0]
//~ MONO_ITEM fn static_init::start[0]
-// compile-flags:-Zprint-mono-items=eager
+// compile-flags:-Zprint-mono-items=eager -Zpolymorphize=on
#![deny(dead_code)]
#![feature(start)]
// For the non-generic foo(), we should generate a codegen-item even if it
// is not called anywhere
- //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0]<i32, u64>
+ //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0]<i32, T1>
}
// Non-generic impl of generic trait
--- /dev/null
+// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
+// ignore-tidy-linelength
+
+#![crate_type = "rlib"]
+
+// This test checks that the polymorphization analysis correctly reduces the
+// generated mono items.
+
+mod functions {
+ // Function doesn't have any type parameters to be unused.
+ pub fn no_parameters() {}
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::no_parameters[0]
+
+ // Function has an unused type parameter.
+ pub fn unused<T>() {
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::unused[0]<T>
+
+ // Function uses type parameter in value of a binding.
+ pub fn used_binding_value<T: Default>() {
+ let _: T = Default::default();
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0]<u64>
+
+ // Function uses type parameter in type of a binding.
+ pub fn used_binding_type<T>() {
+ let _: Option<T> = None;
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0]<u64>
+
+ // Function uses type parameter in argument.
+ pub fn used_argument<T>(_: T) {
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0]<u64>
+//
+ // Function uses type parameter in substitutions to another function.
+ pub fn used_substs<T>() {
+ unused::<T>()
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0]<u64>
+}
+
+
+mod closures {
+ // Function doesn't have any type parameters to be unused.
+ pub fn no_parameters() {
+ let _ = || {};
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::no_parameters[0]
+
+ // Function has an unused type parameter in parent and closure.
+ pub fn unused<T>() -> u32 {
+ let add_one = |x: u32| x + 1;
+ add_one(3)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]::{{closure}}[0]<T, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]<T>
+
+ // Function has an unused type parameter in closure, but not in parent.
+ pub fn used_parent<T: Default>() -> u32 {
+ let _: T = Default::default();
+ let add_one = |x: u32| x + 1;
+ add_one(3)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]::{{closure}}[0]<T, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]<u64>
+
+ // Function uses type parameter in value of a binding in closure.
+ pub fn used_binding_value<T: Default>() -> T {
+ let x = || {
+ let y: T = Default::default();
+ y
+ };
+
+ x()
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()) -> u64, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]<u64>
+
+ // Function uses type parameter in type of a binding in closure.
+ pub fn used_binding_type<T>() -> Option<T> {
+ let x = || {
+ let y: Option<T> = None;
+ y
+ };
+
+ x()
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()) -> core::option[0]::Option[0]<u32>, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()) -> core::option[0]::Option[0]<u64>, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]<u64>
+
+ // Function and closure uses type parameter in argument.
+ pub fn used_argument<T>(t: T) -> u32 {
+ let x = |_: T| 3;
+ x(t)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn((u64)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]<u64>
+
+ // Closure uses type parameter in argument.
+ pub fn used_argument_closure<T: Default>() -> u32 {
+ let t: T = Default::default();
+ let x = |_: T| 3;
+ x(t)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn((u64)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]<u64>
+
+ // Closure uses type parameter as upvar.
+ pub fn used_upvar<T: Default>() -> T {
+ let x: T = Default::default();
+ let y = || x;
+ y()
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0]<u32, i32, extern "rust-call" fn(()) -> u32, (u32)>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0]<u64, i32, extern "rust-call" fn(()) -> u64, (u64)>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]<u64>
+
+ // Closure uses type parameter in substitutions to another function.
+ pub fn used_substs<T>() {
+ let x = || super::functions::unused::<T>();
+ x()
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]<u64>
+}
+
+mod methods {
+ pub struct Foo<F>(F);
+
+ impl<F: Default> Foo<F> {
+ // Function has an unused type parameter from impl.
+ pub fn unused_impl() {
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_impl[0]<F>
+
+ // Function has an unused type parameter from impl and fn.
+ pub fn unused_both<G: Default>() {
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_both[0]<F, G>
+
+ // Function uses type parameter from impl.
+ pub fn used_impl() {
+ let _: F = Default::default();
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0]<u64>
+
+ // Function uses type parameter from impl.
+ pub fn used_fn<G: Default>() {
+ let _: G = Default::default();
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0]<F, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0]<F, u64>
+
+ // Function uses type parameter from impl.
+ pub fn used_both<G: Default>() {
+ let _: F = Default::default();
+ let _: G = Default::default();
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0]<u32, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0]<u64, u64>
+
+ // Function uses type parameter in substitutions to another function.
+ pub fn used_substs() {
+ super::functions::unused::<F>()
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0]<u64>
+
+ // Function has an unused type parameter from impl and fn.
+ pub fn closure_unused_all<G: Default>() -> u32 {
+ let add_one = |x: u32| x + 1;
+ add_one(3)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]::{{closure}}[0]<F, G, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]<F, G>
+
+ // Function uses type parameter from impl and fn in closure.
+ pub fn closure_used_both<G: Default>() -> u32 {
+ let add_one = |x: u32| {
+ let _: F = Default::default();
+ let _: G = Default::default();
+ x + 1
+ };
+
+ add_one(3)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0]<u32, u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0]<u64, u64, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]<u32, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]<u64, u64>
+
+ // Function uses type parameter from fn in closure.
+ pub fn closure_used_fn<G: Default>() -> u32 {
+ let add_one = |x: u32| {
+ let _: G = Default::default();
+ x + 1
+ };
+
+ add_one(3)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0]<F, u32, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0]<F, u64, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]<F, u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]<F, u64>
+
+ // Function uses type parameter from impl in closure.
+ pub fn closure_used_impl<G: Default>() -> u32 {
+ let add_one = |x: u32| {
+ let _: F = Default::default();
+ x + 1
+ };
+
+ add_one(3)
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0]<u32, G, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0]<u64, G, i8, extern "rust-call" fn((u32)) -> u32, ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]<u32, G>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]<u64, G>
+
+ // Closure uses type parameter in substitutions to another function.
+ pub fn closure_used_substs() {
+ let x = || super::functions::unused::<F>();
+ x()
+ }
+
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0]<u32, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0]<u64, i8, extern "rust-call" fn(()), ()>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]<u64>
+ }
+}
+
+
+
+fn dispatch<T: Default>() {
+ functions::no_parameters();
+ functions::unused::<T>();
+ functions::used_binding_value::<T>();
+ functions::used_binding_type::<T>();
+ functions::used_argument::<T>(Default::default());
+ functions::used_substs::<T>();
+
+ closures::no_parameters();
+ let _ = closures::unused::<T>();
+ let _ = closures::used_parent::<T>();
+ let _ = closures::used_binding_value::<T>();
+ let _ = closures::used_binding_type::<T>();
+ let _ = closures::used_argument::<T>(Default::default());
+ let _ = closures::used_argument_closure::<T>();
+ let _ = closures::used_upvar::<T>();
+ let _ = closures::used_substs::<T>();
+
+ methods::Foo::<T>::unused_impl();
+ methods::Foo::<T>::unused_both::<T>();
+ methods::Foo::<T>::used_impl();
+ methods::Foo::<T>::used_fn::<T>();
+ methods::Foo::<T>::used_both::<T>();
+ methods::Foo::<T>::used_substs();
+ let _ = methods::Foo::<T>::closure_unused_all::<T>();
+ let _ = methods::Foo::<T>::closure_used_both::<T>();
+ let _ = methods::Foo::<T>::closure_used_impl::<T>();
+ let _ = methods::Foo::<T>::closure_used_fn::<T>();
+ let _ = methods::Foo::<T>::closure_used_substs();
+}
+
+//~ MONO_ITEM fn unused_type_parameters::dispatch[0]<u32>
+//~ MONO_ITEM fn unused_type_parameters::dispatch[0]<u64>
+
+pub fn foo() {
+ // Generate two copies of each function to check that where the type parameter is unused,
+ // there is only a single copy.
+ dispatch::<u32>();
+ dispatch::<u64>();
+}
+
+//~ MONO_ITEM fn unused_type_parameters::foo[0] @@ unused_type_parameters-cgu.0[External]
+
+// These are all the items that aren't relevant to the test.
+//~ MONO_ITEM fn core::default[0]::{{impl}}[6]::default[0]
+//~ MONO_ITEM fn core::default[0]::{{impl}}[7]::default[0]
// revisions:x86_64 i686 arm
-// min-llvm-version 9.0
+// min-llvm-version: 9.0
//[x86_64] compile-flags: --target x86_64-unknown-uefi
//[i686] compile-flags: --target i686-unknown-linux-musl
--- /dev/null
+// compile-flags: -O --target=avr-unknown-unknown --crate-type=rlib
+
+// This test validates that function pointers can be stored in global variables
+// and called upon. It ensures that Rust emits function pointers in the correct
+// address space to LLVM so that an assertion error relating to casting is
+// not triggered.
+//
+// It also validates that functions can be called through function pointers
+// through traits.
+
+#![feature(no_core, lang_items, unboxed_closures, arbitrary_self_types)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized { }
+#[lang = "copy"]
+pub trait Copy { }
+#[lang = "receiver"]
+pub trait Receiver { }
+
+pub struct Result<T, E> { _a: T, _b: E }
+
+impl Copy for usize {}
+
+#[lang = "drop_in_place"]
+pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
+
+#[lang = "fn_once"]
+pub trait FnOnce<Args> {
+ #[lang = "fn_once_output"]
+ type Output;
+
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+pub trait FnMut<Args> : FnOnce<Args> {
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn"]
+pub trait Fn<Args>: FnOnce<Args> {
+ /// Performs the call operation.
+ extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
+impl<'a, A, R> FnOnce<A> for &'a fn(A) -> R {
+ type Output = R;
+
+ extern "rust-call" fn call_once(self, args: A) -> R {
+ (*self)(args)
+ }
+}
+
+pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
+pub static mut STORAGE_BAR: u32 = 12;
+
+fn arbitrary_black_box(ptr: &usize, _: &mut u32) -> Result<(), ()> {
+ let raw_ptr = ptr as *const usize;
+ let _v: usize = unsafe { *raw_ptr };
+ loop {}
+}
+
+#[inline(never)]
+#[no_mangle]
+fn call_through_fn_trait(a: &mut impl Fn<(), Output=()>) {
+ (*a)()
+}
+
+#[inline(never)]
+fn update_bar_value() {
+ unsafe {
+ STORAGE_BAR = 88;
+ }
+}
+
+// CHECK: define void @test(){{.+}}addrspace(1)
+#[no_mangle]
+pub extern "C" fn test() {
+ let mut buf = 7;
+
+ // A call through the Fn trait must use address space 1.
+ //
+ // CHECK: call{{.+}}addrspace(1) void @call_through_fn_trait()
+ call_through_fn_trait(&mut update_bar_value);
+
+ // A call through a global variable must use address space 1.
+ // CHECK: load {{.*}}addrspace(1){{.+}}FOO
+ unsafe {
+ STORAGE_FOO(&1, &mut buf);
+ }
+}
-// compile-flags: -Z control-flow-guard=checks
+// compile-flags: -C control-flow-guard=checks
// only-msvc
#![crate_type = "lib"]
-// compile-flags: -Z control-flow-guard=no
+// compile-flags: -C control-flow-guard=no
// only-msvc
#![crate_type = "lib"]
-// compile-flags: -Z control-flow-guard=nochecks
+// compile-flags: -C control-flow-guard=nochecks
// only-msvc
#![crate_type = "lib"]
-// compile-flags: -Z control-flow-guard
+// compile-flags: -C control-flow-guard
// ignore-msvc
#![crate_type = "lib"]
-// min-llvm-version 8.0
+// min-llvm-version: 8.0
// compile-flags: -C no-prepopulate-passes -C force-unwind-tables=y
#![crate_type="lib"]
// CHECK-LABEL: @already_sliced_no_bounds_check
#[no_mangle]
pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
- // CHECK: slice_index_len_fail
+ // CHECK: slice_end_index_len_fail
// CHECK-NOT: panic_bounds_check
let _ = (&a[..2048], &b[..2048], &mut c[..2048]);
for i in 0..1024 {
// CHECK-LABEL: @already_sliced_no_bounds_check_exact
#[no_mangle]
pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) {
- // CHECK: slice_index_len_fail
+ // CHECK: slice_end_index_len_fail
// CHECK-NOT: panic_bounds_check
let _ = (&a[..1024], &b[..1024], &mut c[..1024]);
for i in 0..1024 {
// CHECK-LABEL: @already_sliced_bounds_check
#[no_mangle]
pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) {
- // CHECK: slice_index_len_fail
+ // CHECK: slice_end_index_len_fail
// CHECK: panic_bounds_check
let _ = (&a[..1023], &b[..2048], &mut c[..2048]);
for i in 0..1024 {
// unchecked intrinsics.
// compile-flags: -C opt-level=3
+// ignore-wasm32 the wasm target is tested in `wasm_casts_*`
#![crate_type = "lib"]
a as _
}
-
// CHECK-LABEL: @cast_f64_u64
#[no_mangle]
pub fn cast_f64_u64(a: f64) -> u64 {
a as _
}
-
-
// CHECK-LABEL: @cast_unchecked_f64_i64
#[no_mangle]
pub unsafe fn cast_unchecked_f64_i64(a: f64) -> i64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi double {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f64_i32
#[no_mangle]
pub unsafe fn cast_unchecked_f64_i32(a: f64) -> i32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi double {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_i64
#[no_mangle]
pub unsafe fn cast_unchecked_f32_i64(a: f32) -> i64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi float {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_i32
#[no_mangle]
pub unsafe fn cast_unchecked_f32_i32(a: f32) -> i32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptosi float {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.signed.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
-
// CHECK-LABEL: @cast_unchecked_f64_u64
#[no_mangle]
pub unsafe fn cast_unchecked_f64_u64(a: f64) -> u64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui double {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f64_u32
#[no_mangle]
pub unsafe fn cast_unchecked_f64_u32(a: f64) -> u32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui double {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_u64
#[no_mangle]
pub unsafe fn cast_unchecked_f32_u64(a: f32) -> u64 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui float {{.*}} to i64
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i64 {{.*}}
a.to_int_unchecked()
}
// CHECK-LABEL: @cast_unchecked_f32_u32
#[no_mangle]
pub unsafe fn cast_unchecked_f32_u32(a: f32) -> u32 {
- // CHECK-NOT: {{.*}} call {{.*}} @llvm.wasm.trunc.{{.*}}
- // CHECK: fptoui float {{.*}} to i32
+ // CHECK: {{.*}} call {{.*}} @llvm.wasm.trunc.unsigned.{{.*}}
// CHECK-NEXT: ret i32 {{.*}}
a.to_int_unchecked()
}
// This test does not passed with gdb < 8.0. See #53497.
-// min-gdb-version 8.0
+// min-gdb-version: 8.0
// compile-flags:-g
// ignore-freebsd: gdb package too new
// ignore-android: FIXME(#10381)
// compile-flags:-g
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
// min-lldb-version: 310
// === GDB TESTS ===================================================================================
// The pretty printers being tested here require the patch from
// https://sourceware.org/bugzilla/show_bug.cgi?id=21763
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
// min-lldb-version: 310
// only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155
// ignore-android: FIXME(#10381)
// compile-flags:-g
-// min-gdb-version 7.7
+// min-gdb-version: 7.7
// min-lldb-version: 310
// === GDB TESTS ===================================================================================
// ignore-freebsd: gdb package too new
// ignore-android: FIXME(#10381)
// compile-flags:-g
-// min-gdb-version 8.1
+// min-gdb-version: 8.1
// min-lldb-version: 310
// === GDB TESTS ===================================================================================
--- /dev/null
+// revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
+
+// We use #[inline(always)] to ensure that the downstream crate
+// will always load the MIR for these functions
+
+#![feature(rustc_attrs)]
+
+#[allow(unused)]
+macro_rules! first_macro {
+ () => {
+ println!("New call!");
+ }
+}
+
+#[rustc_dirty(label="typeck", cfg="rpass2")]
+#[inline(always)]
+pub fn changed_fn() {
+ // This will cause additional hygiene to be generate,
+ // which will cause the SyntaxContext/ExpnId raw ids to be
+ // different when we write out `my_fn` to the crate metadata.
+ #[cfg(rpass2)]
+ first_macro!();
+}
+
+macro_rules! print_loc {
+ () => {
+ println!("Caller loc: {}", std::panic::Location::caller());
+ }
+}
+
+#[rustc_clean(cfg="rpass2")]
+#[inline(always)]
+pub fn unchanged_fn() {
+ print_loc!();
+}
--- /dev/null
+// revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
+// aux-build:cached_hygiene.rs
+
+// This tests the folllowing scenario
+// 1. A foreign crate is compiled with incremental compilation.
+// This causes hygiene information to be saved to the incr cache.
+// 2. One function is the foreign crate is modified. This causes the
+// optimized mir for an unmodified function to be loaded from the
+// incremental cache and written out to the crate metadata.
+// 3. In the process of loading and writing out this function's MIR,
+// we load hygiene information from the incremental cache and
+// write it to our metadata.
+// 4. This hygiene information is loaded by another crate (this file)
+
+// Previously, this situation would cause hygiene identifiers
+// (SyntaxContexts and ExpnIds) to get corrupted when we tried to
+// serialize the hygiene information loaded from the incr cache into
+// the metadata. Specifically, we were not resetting `orig_id`
+// for an `EpxnData` generate in the current crate, which would cause
+// us to serialize the `ExpnId` pointing to a garbage location in
+// the metadata.
+
+#![feature(rustc_attrs)]
+
+#![rustc_partition_reused(module="load_cached_hygiene-call_unchanged_function", cfg="rpass2")]
+#![rustc_partition_codegened(module="load_cached_hygiene-call_changed_function", cfg="rpass2")]
+
+
+extern crate cached_hygiene;
+
+pub mod call_unchanged_function {
+
+ pub fn unchanged() {
+ cached_hygiene::unchanged_fn();
+ }
+}
+
+pub mod call_changed_function {
+ pub fn changed() {
+ cached_hygiene::changed_fn();
+ }
+}
+
+pub fn main() {
+ call_unchanged_function::unchanged();
+ call_changed_function::changed();
+}
+ // mir::Constant
+ // + span: $DIR/array_index.rs:5:18: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/array_index.rs:5:18: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000004))
++ // mir::Constant
++ // + span: $DIR/array_index.rs:5:18: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000004)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000002))
++ // mir::Constant
++ // + span: $DIR/array_index.rs:5:18: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
}
bb1: {
+ // mir::Constant
+ // + span: $DIR/array_index.rs:5:18: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/array_index.rs:5:18: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000004))
++ // mir::Constant
++ // + span: $DIR/array_index.rs:5:18: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000004)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000002))
++ // mir::Constant
++ // + span: $DIR/array_index.rs:5:18: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
}
bb1: {
- // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + span: $DIR/bad_op_div_by_zero.rs:5:18: 5:19
// + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+- assert(!move _4, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ _4 = const true; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ assert(!const true, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
- assert(!move _4, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
- // ty::Const
++ // ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
- assert(!move _7, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
-+ // ty::Const
++ assert(!const false, "attempt to compute `{} / {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
- // ty::Const
++ // ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++ // ty::Const
++ // + ty: i32
++ // + val: Value(Scalar(0x00000000))
++ // mir::Constant
++ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
}
bb2: {
- _2 = Div(const 1_i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
+- _2 = Div(const 1_i32, move _3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++ _2 = Div(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:15
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++ // ty::Const
++ // + ty: i32
++ // + val: Value(Scalar(0x00000000))
++ // mir::Constant
++ // + span: $DIR/bad_op_div_by_zero.rs:5:14: 5:19
++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
StorageDead(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19
_0 = const (); // scope 0 at $DIR/bad_op_div_by_zero.rs:3:11: 6:2
// ty::Const
- // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + span: $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
// + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+- assert(!move _4, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ assert(!const true, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
- assert(!move _4, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
- // ty::Const
++ // ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
- _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
- assert(!move _7, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
-+ // ty::Const
++ assert(!const false, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
- // ty::Const
++ // ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++ // ty::Const
++ // + ty: i32
++ // + val: Value(Scalar(0x00000000))
++ // mir::Constant
++ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
}
bb2: {
- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
+- _2 = Rem(const 1_i32, move _3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++ _2 = Rem(const 1_i32, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x00000001))
// mir::Constant
// + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:15
// + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++ // ty::Const
++ // + ty: i32
++ // + val: Value(Scalar(0x00000000))
++ // mir::Constant
++ // + span: $DIR/bad_op_mod_by_zero.rs:5:14: 5:19
++ // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
StorageDead(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19
_0 = const (); // scope 0 at $DIR/bad_op_mod_by_zero.rs:3:11: 6:2
// ty::Const
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
// + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
_7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000003))
++ // mir::Constant
++ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
++ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000003))
++ // mir::Constant
++ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
}
bb1: {
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
// + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
_7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+- _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000003))
++ // mir::Constant
++ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
++ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000003))
++ // mir::Constant
++ // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
}
bb1: {
--- /dev/null
+// compile-flags: -O -Zmir-opt-level=3
+
+// EMIT_MIR rustc.test.ConstProp.diff
+pub fn test(x: bool, y: bool) -> bool {
+ (y | true) & (x & false)
+}
+
+fn main() {
+ test(true, false);
+}
--- /dev/null
+- // MIR for `test` before ConstProp
++ // MIR for `test` after ConstProp
+
+ fn test(_1: bool, _2: bool) -> bool {
+ debug x => _1; // in scope 0 at $DIR/boolean_identities.rs:4:13: 4:14
+ debug y => _2; // in scope 0 at $DIR/boolean_identities.rs:4:22: 4:23
+ let mut _0: bool; // return place in scope 0 at $DIR/boolean_identities.rs:4:34: 4:38
+ let mut _3: bool; // in scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
+ let mut _4: bool; // in scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
+ let mut _5: bool; // in scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
+ let mut _6: bool; // in scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
+
+ bb0: {
+ StorageLive(_3); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
+ StorageLive(_4); // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
+ _4 = _2; // scope 0 at $DIR/boolean_identities.rs:5:6: 5:7
+- _3 = BitOr(move _4, const true); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
++ _3 = const true; // scope 0 at $DIR/boolean_identities.rs:5:5: 5:15
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+- // + span: $DIR/boolean_identities.rs:5:10: 5:14
++ // + span: $DIR/boolean_identities.rs:5:5: 5:15
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
+ StorageDead(_4); // scope 0 at $DIR/boolean_identities.rs:5:14: 5:15
+ StorageLive(_5); // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
+ StorageLive(_6); // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
+ _6 = _1; // scope 0 at $DIR/boolean_identities.rs:5:19: 5:20
+- _5 = BitAnd(move _6, const false); // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
++ _5 = const false; // scope 0 at $DIR/boolean_identities.rs:5:18: 5:29
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+- // + span: $DIR/boolean_identities.rs:5:23: 5:28
++ // + span: $DIR/boolean_identities.rs:5:18: 5:29
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ StorageDead(_6); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
+- _0 = BitAnd(move _3, move _5); // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29
++ _0 = const false; // scope 0 at $DIR/boolean_identities.rs:5:5: 5:29
++ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x00))
++ // mir::Constant
++ // + span: $DIR/boolean_identities.rs:5:5: 5:29
++ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ StorageDead(_5); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
+ StorageDead(_3); // scope 0 at $DIR/boolean_identities.rs:5:28: 5:29
+ return; // scope 0 at $DIR/boolean_identities.rs:6:2: 6:2
+ }
+ }
+
}
bb2: {
- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
+- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
++ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
++ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/discriminant.rs:11:26: 11:30
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
}
bb3: {
}
bb2: {
- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
+- switchInt(((_3 as Some).0: bool)) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
++ switchInt(const true) -> [false: bb1, otherwise: bb3]; // scope 0 at $DIR/discriminant.rs:11:26: 11:30
++ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/discriminant.rs:11:26: 11:30
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
}
bb3: {
+ // mir::Constant
+ // + span: $DIR/indirect.rs:5:13: 5:29
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
-+ assert(!const false, "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
++ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x00))
+ // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+ // ty::Const
// + ty: u8
++ // + val: Value(Scalar(0x02))
++ // mir::Constant
++ // + span: $DIR/indirect.rs:5:13: 5:29
++ // + literal: Const { ty: u8, val: Value(Scalar(0x02)) }
++ // ty::Const
++ // + ty: u8
// + val: Value(Scalar(0x01))
// mir::Constant
// + span: $DIR/indirect.rs:5:28: 5:29
--- /dev/null
+// compile-flags: -O -Zmir-opt-level=3
+
+// EMIT_MIR rustc.test.ConstProp.diff
+fn test(x : i32) -> i32 {
+ x * 0
+}
+
+fn main() {
+ test(10);
+}
--- /dev/null
+- // MIR for `test` before ConstProp
++ // MIR for `test` after ConstProp
+
+ fn test(_1: i32) -> i32 {
+ debug x => _1; // in scope 0 at $DIR/mult_by_zero.rs:4:9: 4:10
+ let mut _0: i32; // return place in scope 0 at $DIR/mult_by_zero.rs:4:21: 4:24
+ let mut _2: i32; // in scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
+ _2 = _1; // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:4
+- _0 = Mul(move _2, const 0_i32); // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8
++ _0 = const 0_i32; // scope 0 at $DIR/mult_by_zero.rs:5:3: 5:8
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000000))
+ // mir::Constant
+- // + span: $DIR/mult_by_zero.rs:5:7: 5:8
++ // + span: $DIR/mult_by_zero.rs:5:3: 5:8
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000000)) }
+ StorageDead(_2); // scope 0 at $DIR/mult_by_zero.rs:5:7: 5:8
+ return; // scope 0 at $DIR/mult_by_zero.rs:6:2: 6:2
+ }
+ }
+
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000006))
++ // mir::Constant
++ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000006)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000003))
++ // mir::Constant
++ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
}
bb2: {
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000006))
++ // mir::Constant
++ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000006)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000003))
++ // mir::Constant
++ // + span: $DIR/optimizes_into_variable.rs:13:13: 13:34
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
}
bb2: {
+ // mir::Constant
+ // + span: $DIR/repeat.rs:6:18: 6:28
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/repeat.rs:6:18: 6:28
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000008))
++ // mir::Constant
++ // + span: $DIR/repeat.rs:6:18: 6:28
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000008)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000002))
++ // mir::Constant
++ // + span: $DIR/repeat.rs:6:18: 6:28
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
}
bb1: {
+ // mir::Constant
+ // + span: $DIR/repeat.rs:6:18: 6:28
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/repeat.rs:6:18: 6:28
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000008))
++ // mir::Constant
++ // + span: $DIR/repeat.rs:6:18: 6:28
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000008)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000002))
++ // mir::Constant
++ // + span: $DIR/repeat.rs:6:18: 6:28
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
}
bb1: {
+ // mir::Constant
+ // + span: $DIR/slice_len.rs:5:5: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/slice_len.rs:5:5: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000003))
++ // mir::Constant
++ // + span: $DIR/slice_len.rs:5:5: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000001))
++ // mir::Constant
++ // + span: $DIR/slice_len.rs:5:5: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000001)) }
}
bb1: {
+ // mir::Constant
+ // + span: $DIR/slice_len.rs:5:5: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
-+ assert(const true, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // scope 0 at $DIR/slice_len.rs:5:5: 5:33
+ // ty::Const
+ // + ty: bool
+ // + val: Value(Scalar(0x01))
+ // mir::Constant
+ // + span: $DIR/slice_len.rs:5:5: 5:33
+ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000003))
++ // mir::Constant
++ // + span: $DIR/slice_len.rs:5:5: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000001))
++ // mir::Constant
++ // + span: $DIR/slice_len.rs:5:5: 5:33
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000001)) }
}
bb1: {
// all of the bindings for that scope.
// * No drop flags are used.
-// EMIT_MIR rustc.complicated_match.SimplifyCfg-initial.after.mir
-// EMIT_MIR rustc.complicated_match.ElaborateDrops.after.mir
+// EMIT_MIR rustc.complicated_match SimplifyCfg-initial.after ElaborateDrops.after
fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
match items {
(false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,
+++ /dev/null
-// MIR for `complicated_match` after ElaborateDrops
-
-fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
- debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:14:22: 14:26
- debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:14:34: 14:39
- let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:14:66: 14:69
- let mut _3: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- let mut _4: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- let _5: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- let _6: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- let _7: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- let _8: &std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- let mut _9: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- let mut _10: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- let mut _11: !; // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- let mut _12: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- let mut _13: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- let mut _14: !; // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- let _15: bool; // in scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
- let _16: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
- scope 1 {
- debug a => _5; // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
- debug a => _6; // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
- debug s => _7; // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
- debug s => _8; // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
- }
- scope 2 {
- debug b => _15; // in scope 2 at $DIR/match-arm-scopes.rs:17:16: 17:17
- debug t => _16; // in scope 2 at $DIR/match-arm-scopes.rs:17:19: 17:20
- }
-
- bb0: {
- switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:15
- }
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/match-arm-scopes.rs:14:1: 19:2
- }
-
- bb2: {
- switchInt((_2.1: bool)) -> [false: bb14, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:16:29: 16:34
- }
-
- bb3: {
- switchInt((_2.0: bool)) -> [false: bb4, otherwise: bb21]; // scope 0 at $DIR/match-arm-scopes.rs:17:10: 17:14
- }
-
- bb4: {
- StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
- _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
- StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
- _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
- goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb5: {
- _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000001))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:16:77: 16:78
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
- drop(_7) -> [return: bb19, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- }
-
- bb6: {
- StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- _6 = &(_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- StorageLive(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- StorageLive(_10); // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- _10 = _1; // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- switchInt(_10) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb7: {
- _9 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
- StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- switchInt(move _9) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb8: {
- _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000003))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
- StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb11; // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- }
-
- bb9: {
- return; // scope 0 at $DIR/match-arm-scopes.rs:19:2: 19:2
- }
-
- bb10 (cleanup): {
- goto -> bb25; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb11: {
- drop(_2) -> [return: bb9, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb12: {
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- _5 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- goto -> bb5; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb13: {
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb2; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb14: {
- StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- _6 = &(_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- StorageLive(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- StorageLive(_13); // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- _13 = _1; // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- switchInt(_13) -> [false: bb15, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb15: {
- _12 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
- StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- switchInt(move _12) -> [false: bb18, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb16: {
- _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000003))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
- StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb11; // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- }
-
- bb17: {
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- _5 = (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- goto -> bb5; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb18: {
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb3; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb19: {
- StorageDead(_7); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_5); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb20: {
- _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000002))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:17:41: 17:42
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
- drop(_16) -> [return: bb22, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
- }
-
- bb21: {
- StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
- _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
- StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
- _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
- goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb22: {
- StorageDead(_16); // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
- StorageDead(_15); // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
- goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb23: {
- goto -> bb29; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb24 (cleanup): {
- goto -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb25 (cleanup): {
- goto -> bb24; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb26: {
- goto -> bb9; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb27 (cleanup): {
- goto -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb28 (cleanup): {
- goto -> bb27; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb29: {
- goto -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-}
--- /dev/null
+- // MIR for `complicated_match` after SimplifyCfg-initial
++ // MIR for `complicated_match` after ElaborateDrops
+
+ fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
+ debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:13:22: 13:26
+ debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:13:34: 13:39
+ let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:13:66: 13:69
+ let mut _3: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+ let mut _4: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+ let _5: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ let _6: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ let _7: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+ let _8: &std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+ let mut _9: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ let mut _10: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+ let mut _11: !; // in scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+ let mut _12: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ let mut _13: bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+ let mut _14: !; // in scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+ let _15: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
+ let _16: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
+ scope 1 {
+ debug a => _5; // in scope 1 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ debug a => _6; // in scope 1 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ debug s => _7; // in scope 1 at $DIR/match-arm-scopes.rs:15:20: 15:21
+ debug s => _8; // in scope 1 at $DIR/match-arm-scopes.rs:15:20: 15:21
+ }
+ scope 2 {
+ debug b => _15; // in scope 2 at $DIR/match-arm-scopes.rs:16:16: 16:17
+ debug t => _16; // in scope 2 at $DIR/match-arm-scopes.rs:16:19: 16:20
+ }
+
+ bb0: {
+- FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+- switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
++ switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:15:10: 15:15
+ }
+
+ bb1 (cleanup): {
+ resume; // scope 0 at $DIR/match-arm-scopes.rs:13:1: 18:2
+ }
+
+ bb2: {
+- falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:15:9: 15:22
++ switchInt((_2.1: bool)) -> [false: bb14, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
+ }
+
+ bb3: {
+- switchInt((_2.1: bool)) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:15:29: 15:34
++ switchInt((_2.0: bool)) -> [false: bb4, otherwise: bb21]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
+ }
+
+ bb4: {
+- falseEdge -> [real: bb18, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:15:25: 15:38
+- }
+-
+- bb5: {
+- switchInt((_2.0: bool)) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:14
+- }
+-
+- bb6: {
+- falseEdge -> [real: bb26, imaginary: bb7]; // scope 0 at $DIR/match-arm-scopes.rs:16:9: 16:21
+- }
+-
+- bb7: {
+ StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33
+ _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:32: 16:33
+ StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36
+ _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:35: 16:36
+- goto -> bb25; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++ goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+ }
+
+- bb8: {
++ bb5: {
+ _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000001))
+ // mir::Constant
+ // + span: $DIR/match-arm-scopes.rs:15:77: 15:78
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
+- drop(_7) -> [return: bb24, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
++ drop(_7) -> [return: bb19, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ }
+
+- bb9: {
++ bb6: {
+ StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ _6 = &(_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+ _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+ StorageLive(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ StorageLive(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+ _10 = _1; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+- FakeRead(ForMatchedPlace, _10); // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+- switchInt(_10) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++ switchInt(_10) -> [false: bb7, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ }
+
+- bb10: {
+- falseEdge -> [real: bb12, imaginary: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+- }
+-
+- bb11: {
++ bb7: {
+ _9 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71
+ StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- switchInt(move _9) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++ switchInt(move _9) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ }
+
+- bb12: {
++ bb8: {
+ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000003))
+ // mir::Constant
+ // + span: $DIR/match-arm-scopes.rs:15:59: 15:60
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
+ StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+ StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+- goto -> bb15; // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
++ goto -> bb11; // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+ }
+
+- bb13: {
++ bb9: {
+ return; // scope 0 at $DIR/match-arm-scopes.rs:18:2: 18:2
+ }
+
+- bb14 (cleanup): {
+- drop(_2) -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ bb10 (cleanup): {
++ goto -> bb25; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+ }
+
+- bb15: {
+- drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ bb11: {
++ drop(_2) -> [return: bb9, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+ }
+
+- bb16: {
++ bb12: {
+ StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+ StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ _5 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:17: 15:18
+ StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+ _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:20: 15:21
+- goto -> bb8; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++ goto -> bb5; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+ }
+
+- bb17: {
++ bb13: {
+ StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+- falseEdge -> [real: bb3, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++ goto -> bb2; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ }
+
+- bb18: {
++ bb14: {
+ StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+ _6 = &(_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+ StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+ _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:14:11: 14:16
+ StorageLive(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ StorageLive(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+ _13 = _1; // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+- FakeRead(ForMatchedPlace, _13); // scope 0 at $DIR/match-arm-scopes.rs:15:45: 15:49
+- switchInt(_13) -> [false: bb20, otherwise: bb19]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++ switchInt(_13) -> [false: bb15, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ }
+
+- bb19: {
+- falseEdge -> [real: bb21, imaginary: bb20]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+- }
+-
+- bb20: {
++ bb15: {
+ _12 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:15:70: 15:71
+ StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- switchInt(move _12) -> [false: bb23, otherwise: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++ switchInt(move _12) -> [false: bb18, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ }
+
+- bb21: {
++ bb16: {
+ _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:15:59: 15:60
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000003))
+ // mir::Constant
+ // + span: $DIR/match-arm-scopes.rs:15:59: 15:60
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
+ StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+ StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+- goto -> bb15; // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
++ goto -> bb11; // scope 0 at $DIR/match-arm-scopes.rs:15:52: 15:60
+ }
+
+- bb22: {
++ bb17: {
+ StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:15:72: 15:73
+ StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+ _5 = (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:26: 15:27
+ StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+ _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:15:36: 15:37
+- goto -> bb8; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++ goto -> bb5; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+ }
+
+- bb23: {
++ bb18: {
+ StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+- falseEdge -> [real: bb5, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
++ goto -> bb3; // scope 0 at $DIR/match-arm-scopes.rs:15:42: 15:73
+ }
+
+- bb24: {
++ bb19: {
+ StorageDead(_7); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_5); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+ StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:15:77: 15:78
+- goto -> bb28; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+ }
+
+- bb25: {
++ bb20: {
+ _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:16:41: 16:42
+ // ty::Const
+ // + ty: i32
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/match-arm-scopes.rs:16:41: 16:42
+ // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
+- drop(_16) -> [return: bb27, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
++ drop(_16) -> [return: bb22, unwind: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
+ }
+
+- bb26: {
++ bb21: {
+ StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
+ _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:16: 16:17
+ StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
+ _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:19: 16:20
+- goto -> bb25; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++ goto -> bb20; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+ }
+
+- bb27: {
++ bb22: {
+ StorageDead(_16); // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
+ StorageDead(_15); // scope 0 at $DIR/match-arm-scopes.rs:16:41: 16:42
+- goto -> bb28; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
++ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:14:5: 17:6
+ }
+
+- bb28: {
+- drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ bb23: {
++ goto -> bb29; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ }
++
++ bb24 (cleanup): {
++ goto -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ }
++
++ bb25 (cleanup): {
++ goto -> bb24; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ }
++
++ bb26: {
++ goto -> bb9; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ }
++
++ bb27 (cleanup): {
++ goto -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ }
++
++ bb28 (cleanup): {
++ goto -> bb27; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
++ }
++
++ bb29: {
++ goto -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:18:1: 18:2
+ }
+ }
+
+++ /dev/null
-// MIR for `complicated_match` after SimplifyCfg-initial
-
-fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 {
- debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:14:22: 14:26
- debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:14:34: 14:39
- let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:14:66: 14:69
- let mut _3: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- let mut _4: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- let _5: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- let _6: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- let _7: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- let _8: &std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- let mut _9: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- let mut _10: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- let mut _11: !; // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- let mut _12: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- let mut _13: bool; // in scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- let mut _14: !; // in scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- let _15: bool; // in scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
- let _16: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
- scope 1 {
- debug a => _5; // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
- debug a => _6; // in scope 1 at $DIR/match-arm-scopes.rs:16:17: 16:18
- debug s => _7; // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
- debug s => _8; // in scope 1 at $DIR/match-arm-scopes.rs:16:20: 16:21
- }
- scope 2 {
- debug b => _15; // in scope 2 at $DIR/match-arm-scopes.rs:17:16: 17:17
- debug t => _16; // in scope 2 at $DIR/match-arm-scopes.rs:17:19: 17:20
- }
-
- bb0: {
- FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- switchInt((_2.0: bool)) -> [false: bb2, otherwise: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:16:10: 16:15
- }
-
- bb1 (cleanup): {
- resume; // scope 0 at $DIR/match-arm-scopes.rs:14:1: 19:2
- }
-
- bb2: {
- falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:16:9: 16:22
- }
-
- bb3: {
- switchInt((_2.1: bool)) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:16:29: 16:34
- }
-
- bb4: {
- falseEdge -> [real: bb18, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:25: 16:38
- }
-
- bb5: {
- switchInt((_2.0: bool)) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:17:10: 17:14
- }
-
- bb6: {
- falseEdge -> [real: bb26, imaginary: bb7]; // scope 0 at $DIR/match-arm-scopes.rs:17:9: 17:21
- }
-
- bb7: {
- StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
- _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:17:32: 17:33
- StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
- _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:35: 17:36
- goto -> bb25; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb8: {
- _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:16:77: 16:78
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000001))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:16:77: 16:78
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
- drop(_7) -> [return: bb24, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- }
-
- bb9: {
- StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- _6 = &(_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- StorageLive(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- StorageLive(_10); // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- _10 = _1; // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- FakeRead(ForMatchedPlace, _10); // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- switchInt(_10) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb10: {
- falseEdge -> [real: bb12, imaginary: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb11: {
- _9 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
- StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- switchInt(move _9) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb12: {
- _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000003))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
- StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb15; // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- }
-
- bb13: {
- return; // scope 0 at $DIR/match-arm-scopes.rs:19:2: 19:2
- }
-
- bb14 (cleanup): {
- drop(_2) -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb15: {
- drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-
- bb16: {
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- _5 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:17: 16:18
- StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:20: 16:21
- goto -> bb8; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb17: {
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- falseEdge -> [real: bb3, imaginary: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb18: {
- StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- _6 = &(_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:15:11: 15:16
- StorageLive(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- StorageLive(_13); // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- _13 = _1; // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- FakeRead(ForMatchedPlace, _13); // scope 0 at $DIR/match-arm-scopes.rs:16:45: 16:49
- switchInt(_13) -> [false: bb20, otherwise: bb19]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb19: {
- falseEdge -> [real: bb21, imaginary: bb20]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb20: {
- _12 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:16:70: 16:71
- StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- switchInt(move _12) -> [false: bb23, otherwise: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb21: {
- _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:16:59: 16:60
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000003))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:16:59: 16:60
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000003)) }
- StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb15; // scope 0 at $DIR/match-arm-scopes.rs:16:52: 16:60
- }
-
- bb22: {
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:16:72: 16:73
- StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- _5 = (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:16:26: 16:27
- StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:16:36: 16:37
- goto -> bb8; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb23: {
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- falseEdge -> [real: bb5, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:16:42: 16:73
- }
-
- bb24: {
- StorageDead(_7); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_5); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:16:77: 16:78
- goto -> bb28; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb25: {
- _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:17:41: 17:42
- // ty::Const
- // + ty: i32
- // + val: Value(Scalar(0x00000002))
- // mir::Constant
- // + span: $DIR/match-arm-scopes.rs:17:41: 17:42
- // + literal: Const { ty: i32, val: Value(Scalar(0x00000002)) }
- drop(_16) -> [return: bb27, unwind: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
- }
-
- bb26: {
- StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
- _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:17:16: 17:17
- StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
- _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:17:19: 17:20
- goto -> bb25; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb27: {
- StorageDead(_16); // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
- StorageDead(_15); // scope 0 at $DIR/match-arm-scopes.rs:17:41: 17:42
- goto -> bb28; // scope 0 at $DIR/match-arm-scopes.rs:15:5: 18:6
- }
-
- bb28: {
- drop(_2) -> [return: bb13, unwind: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:19:1: 19:2
- }
-}
pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize {
0
}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize {
+ continue_if!(ap.arg::<c_int>() == 1);
+ continue_if!(ap.arg::<c_int>() == 2);
+ continue_if!(ap.arg::<c_int>() == 3);
+ continue_if!(ap.arg::<c_int>() == 4);
+ continue_if!(ap.arg::<c_int>() == 5);
+ continue_if!(ap.arg::<c_int>() == 6);
+ continue_if!(ap.arg::<c_int>() == 7);
+ continue_if!(ap.arg::<c_int>() == 8);
+ continue_if!(ap.arg::<c_int>() == 9);
+ continue_if!(ap.arg::<c_int>() == 10);
+ 0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize {
+ continue_if!(ap.arg::<c_double>() == 1.0);
+ continue_if!(ap.arg::<c_double>() == 2.0);
+ continue_if!(ap.arg::<c_double>() == 3.0);
+ continue_if!(ap.arg::<c_double>() == 4.0);
+ continue_if!(ap.arg::<c_double>() == 5.0);
+ continue_if!(ap.arg::<c_double>() == 6.0);
+ continue_if!(ap.arg::<c_double>() == 7.0);
+ continue_if!(ap.arg::<c_double>() == 8.0);
+ continue_if!(ap.arg::<c_double>() == 9.0);
+ continue_if!(ap.arg::<c_double>() == 10.0);
+ 0
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
+ continue_if!(ap.arg::<c_double>() == 1.0);
+ continue_if!(ap.arg::<c_int>() == 1);
+ continue_if!(ap.arg::<c_double>() == 2.0);
+ continue_if!(ap.arg::<c_int>() == 2);
+ continue_if!(ap.arg::<c_double>() == 3.0);
+ continue_if!(ap.arg::<c_int>() == 3);
+ continue_if!(ap.arg::<c_double>() == 4.0);
+ continue_if!(ap.arg::<c_int>() == 4);
+ continue_if!(ap.arg::<c_int>() == 5);
+ continue_if!(ap.arg::<c_double>() == 5.0);
+ continue_if!(ap.arg::<c_int>() == 6);
+ continue_if!(ap.arg::<c_double>() == 6.0);
+ continue_if!(ap.arg::<c_int>() == 7);
+ continue_if!(ap.arg::<c_double>() == 7.0);
+ continue_if!(ap.arg::<c_int>() == 8);
+ continue_if!(ap.arg::<c_double>() == 8.0);
+ continue_if!(ap.arg::<c_int>() == 9);
+ continue_if!(ap.arg::<c_double>() == 9.0);
+ continue_if!(ap.arg::<c_int>() == 10);
+ continue_if!(ap.arg::<c_double>() == 10.0);
+ 0
+}
extern size_t check_varargs_0(int fixed, ...);
extern size_t check_varargs_1(int fixed, ...);
extern size_t check_varargs_2(int fixed, ...);
+extern size_t check_varargs_3(int fixed, ...);
+extern size_t check_varargs_4(double fixed, ...);
+extern size_t check_varargs_5(int fixed, ...);
int test_rust(size_t (*fn)(va_list), ...) {
size_t ret = 0;
assert(check_varargs_2(0, "All", "of", "these", "are", "ignored", ".") == 0);
+ assert(check_varargs_3(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 0);
+
+ assert(check_varargs_4(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0) == 0);
+
+ assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0,
+ 9, 9.0, 10, 10.0) == 0);
+
return 0;
}
-error: `[v2]` cannot be resolved, ignoring it.
+error: unresolved link to `v2`
--> $DIR/deny-intra-link-resolution-failure.rs:3:6
|
LL | /// [v2]
- | ^^ cannot be resolved, ignoring
+ | ^^ unresolved link
|
note: the lint level is defined here
--> $DIR/deny-intra-link-resolution-failure.rs:1:9
|
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error
-error: `[TypeAlias::hoge]` cannot be resolved, ignoring it.
+error: unresolved link to `TypeAlias::hoge`
--> $DIR/intra-doc-alias-ice.rs:5:30
|
LL | /// [broken cross-reference](TypeAlias::hoge)
- | ^^^^^^^^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^^^^^^^^ unresolved link
|
note: the lint level is defined here
--> $DIR/intra-doc-alias-ice.rs:1:9
|
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error
/// ## For example:
///
/// (arr[i])
-//~^ ERROR `[i]` cannot be resolved, ignoring it.
+//~^ ERROR `i`
pub fn test_ice() {
unimplemented!();
}
-error: `[i]` cannot be resolved, ignoring it.
+error: unresolved link to `i`
--> $DIR/intra-link-span-ice-55723.rs:9:10
|
LL | /// (arr[i])
- | ^ cannot be resolved, ignoring
+ | ^ unresolved link
|
note: the lint level is defined here
--> $DIR/intra-link-span-ice-55723.rs:1:9
|
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: aborting due to previous error
/// Like [Foo#hola].
///
/// Or maybe [Foo::f#hola].
-//~^ ERROR `[Foo::f#hola]` has an issue with the link anchor.
+//~^ ERROR `Foo::f#hola` contains an anchor
pub fn foo() {}
/// Empty.
///
/// Another anchor error: [hello#people#!].
-//~^ ERROR `[hello#people#!]` has an issue with the link anchor.
+//~^ ERROR `hello#people#!` contains multiple anchors
pub fn bar() {}
/// Empty?
///
/// Damn enum's variants: [Enum::A#whatever].
-//~^ ERROR `[Enum::A#whatever]` has an issue with the link anchor.
+//~^ ERROR `Enum::A#whatever` contains an anchor
pub fn enum_link() {}
/// Primitives?
///
/// [u32#hello]
-//~^ ERROR `[u32#hello]` has an issue with the link anchor.
+//~^ ERROR `u32#hello` contains an anchor
pub fn x() {}
-error: `[Foo::f#hola]` has an issue with the link anchor.
+error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored
--> $DIR/intra-links-anchors.rs:25:15
|
LL | /// Or maybe [Foo::f#hola].
- | ^^^^^^^^^^^ struct fields cannot be followed by anchors
+ | ^^^^^^^^^^^ contains invalid anchor
|
note: the lint level is defined here
--> $DIR/intra-links-anchors.rs:1:9
LL | #![deny(intra_doc_link_resolution_failure)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `[hello#people#!]` has an issue with the link anchor.
+error: `hello#people#!` contains multiple anchors
--> $DIR/intra-links-anchors.rs:31:28
|
LL | /// Another anchor error: [hello#people#!].
- | ^^^^^^^^^^^^^^ only one `#` is allowed in a link
+ | ^^^^^^^^^^^^^^ contains invalid anchor
-error: `[Enum::A#whatever]` has an issue with the link anchor.
+error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored
--> $DIR/intra-links-anchors.rs:37:28
|
LL | /// Damn enum's variants: [Enum::A#whatever].
- | ^^^^^^^^^^^^^^^^ variants cannot be followed by anchors
+ | ^^^^^^^^^^^^^^^^ contains invalid anchor
-error: `[u32#hello]` has an issue with the link anchor.
+error: `u32#hello` contains an anchor, but links to primitive types are already anchored
--> $DIR/intra-links-anchors.rs:43:6
|
LL | /// [u32#hello]
- | ^^^^^^^^^ primitive types cannot be followed by anchors
+ | ^^^^^^^^^ contains invalid anchor
error: aborting due to 4 previous errors
--- /dev/null
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+ --> $DIR/intra-links-private.rs:5:11
+ |
+LL | /// docs [DontDocMe]
+ | ^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 1 warning emitted
+
-warning: `[DontDocMe]` public documentation for `DocMe` links to a private item
- --> $DIR/intra-links-private.rs:6:11
+warning: public documentation for `DocMe` links to private item `DontDocMe`
+ --> $DIR/intra-links-private.rs:5:11
|
LL | /// docs [DontDocMe]
| ^^^^^^^^^ this item is private
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link will resolve properly if you pass `--document-private-items`
warning: 1 warning emitted
// check-pass
// revisions: public private
// [private]compile-flags: --document-private-items
-#![cfg_attr(private, deny(intra_doc_link_resolution_failure))]
/// docs [DontDocMe]
-//[public]~^ WARNING `[DontDocMe]` public documentation for `DocMe` links to a private item
+//~^ WARNING public documentation for `DocMe` links to private item `DontDocMe`
// FIXME: for [private] we should also make sure the link was actually generated
pub struct DocMe;
struct DontDocMe;
/// [error]
pub struct A;
-//~^^ WARNING `[error]` cannot be resolved
+//~^^ WARNING `error`
///
/// docs [error1]
-//~^ WARNING `[error1]` cannot be resolved
+//~^ WARNING `error1`
/// docs [error2]
///
pub struct B;
-//~^^^ WARNING `[error2]` cannot be resolved
+//~^^^ WARNING `error2`
/**
* This is a multi-line comment.
* It also has an [error].
*/
pub struct C;
-//~^^^ WARNING `[error]` cannot be resolved
+//~^^^ WARNING `error`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning-crlf.rs:7:6
|
LL | /// [error]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error1]` cannot be resolved, ignoring it.
+warning: unresolved link to `error1`
--> $DIR/intra-links-warning-crlf.rs:12:11
|
LL | /// docs [error1]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error2]` cannot be resolved, ignoring it.
+warning: unresolved link to `error2`
--> $DIR/intra-links-warning-crlf.rs:15:11
|
LL | /// docs [error2]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning-crlf.rs:23:20
|
LL | * It also has an [error].
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: 4 warnings emitted
// check-pass
//! Test with [Foo::baz], [Bar::foo], ...
-//~^ WARNING `[Foo::baz]` cannot be resolved
-//~| WARNING `[Bar::foo]` cannot be resolved
+//~^ WARNING `Foo::baz`
+//~| WARNING `Bar::foo`
//! , [Uniooon::X] and [Qux::Z].
-//~^ WARNING `[Uniooon::X]` cannot be resolved
-//~| WARNING `[Qux::Z]` cannot be resolved
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
//!
//! , [Uniooon::X] and [Qux::Z].
-//~^ WARNING `[Uniooon::X]` cannot be resolved
-//~| WARNING `[Qux::Z]` cannot be resolved
+//~^ WARNING `Uniooon::X`
+//~| WARNING `Qux::Z`
/// [Qux:Y]
-//~^ WARNING `[Qux:Y]` cannot be resolved
+//~^ WARNING `Qux:Y`
pub struct Foo {
pub bar: usize,
}
/// Foo
-/// bar [BarA] bar //~ WARNING `[BarA]` cannot be resolved
+/// bar [BarA] bar //~ WARNING `BarA`
/// baz
pub fn a() {}
/**
* Foo
- * bar [BarB] bar //~ WARNING `[BarB]` cannot be resolved
+ * bar [BarB] bar //~ WARNING `BarB`
* baz
*/
pub fn b() {}
/** Foo
-bar [BarC] bar //~ WARNING `[BarC]` cannot be resolved
+bar [BarC] bar //~ WARNING `BarC`
baz
let bar_c_1 = 0;
*/
pub fn c() {}
-#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `[BarD]` cannot be resolved
+#[doc = "Foo\nbar [BarD] bar\nbaz"] //~ WARNING `BarD`
pub fn d() {}
macro_rules! f {
($f:expr) => {
- #[doc = $f] //~ WARNING `[BarF]` cannot be resolved
+ #[doc = $f] //~ WARNING `BarF`
pub fn f() {}
}
}
/** # for example,
*
- * time to introduce a link [error]*/ //~ WARNING `[error]` cannot be resolved
+ * time to introduce a link [error]*/ //~ WARNING `error`
pub struct A;
/**
* # for example,
*
- * time to introduce a link [error] //~ WARNING `[error]` cannot be resolved
+ * time to introduce a link [error] //~ WARNING `error`
*/
pub struct B;
-#[doc = "single line [error]"] //~ WARNING `[error]` cannot be resolved
+#[doc = "single line [error]"] //~ WARNING `error`
pub struct C;
-#[doc = "single line with \"escaping\" [error]"] //~ WARNING `[error]` cannot be resolved
+#[doc = "single line with \"escaping\" [error]"] //~ WARNING `error`
pub struct D;
-/// Item docs. //~ WARNING `[error]` cannot be resolved
+/// Item docs. //~ WARNING `error`
#[doc="Hello there!"]
/// [error]
pub struct E;
///
-/// docs [error1] //~ WARNING `[error1]` cannot be resolved
+/// docs [error1] //~ WARNING `error1`
-/// docs [error2] //~ WARNING `[error2]` cannot be resolved
+/// docs [error2] //~ WARNING `error2`
///
pub struct F;
-warning: `[Foo::baz]` cannot be resolved, ignoring it.
+warning: unresolved link to `Foo::baz`
--> $DIR/intra-links-warning.rs:3:23
|
LL | //! Test with [Foo::baz], [Bar::foo], ...
- | ^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^ unresolved link
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Bar::foo]` cannot be resolved, ignoring it.
+warning: unresolved link to `Bar::foo`
--> $DIR/intra-links-warning.rs:3:35
|
LL | //! Test with [Foo::baz], [Bar::foo], ...
- | ^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Uniooon::X]` cannot be resolved, ignoring it.
+warning: unresolved link to `Uniooon::X`
--> $DIR/intra-links-warning.rs:6:13
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Qux::Z]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux::Z`
--> $DIR/intra-links-warning.rs:6:30
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Uniooon::X]` cannot be resolved, ignoring it.
+warning: unresolved link to `Uniooon::X`
--> $DIR/intra-links-warning.rs:10:14
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Qux::Z]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux::Z`
--> $DIR/intra-links-warning.rs:10:31
|
LL | //! , [Uniooon::X] and [Qux::Z].
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[Qux:Y]` cannot be resolved, ignoring it.
+warning: unresolved link to `Qux:Y`
--> $DIR/intra-links-warning.rs:14:13
|
LL | /// [Qux:Y]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:58:30
|
LL | * time to introduce a link [error]*/
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:64:30
|
LL | * time to introduce a link [error]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:68:1
|
LL | #[doc = "single line [error]"]
single line [error]
^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:71:1
|
LL | #[doc = "single line with \"escaping\" [error]"]
single line with "escaping" [error]
^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error]` cannot be resolved, ignoring it.
+warning: unresolved link to `error`
--> $DIR/intra-links-warning.rs:74:1
|
LL | / /// Item docs.
[error]
^^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error1]` cannot be resolved, ignoring it.
+warning: unresolved link to `error1`
--> $DIR/intra-links-warning.rs:80:11
|
LL | /// docs [error1]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[error2]` cannot be resolved, ignoring it.
+warning: unresolved link to `error2`
--> $DIR/intra-links-warning.rs:82:11
|
LL | /// docs [error2]
- | ^^^^^^ cannot be resolved, ignoring
+ | ^^^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarA]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarA`
--> $DIR/intra-links-warning.rs:21:10
|
LL | /// bar [BarA] bar
- | ^^^^ cannot be resolved, ignoring
+ | ^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarB]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarB`
--> $DIR/intra-links-warning.rs:27:9
|
LL | * bar [BarB] bar
- | ^^^^ cannot be resolved, ignoring
+ | ^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarC]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarC`
--> $DIR/intra-links-warning.rs:34:6
|
LL | bar [BarC] bar
- | ^^^^ cannot be resolved, ignoring
+ | ^^^^ unresolved link
|
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarD]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarD`
--> $DIR/intra-links-warning.rs:45:1
|
LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
bar [BarD] bar
^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
-warning: `[BarF]` cannot be resolved, ignoring it.
+warning: unresolved link to `BarF`
--> $DIR/intra-links-warning.rs:50:9
|
LL | #[doc = $f]
bar [BarF] bar
^^^^
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 19 warnings emitted
--- /dev/null
+warning: public documentation for `public_item` links to private item `PrivateType`
+ --> $DIR/issue-74134.rs:19:10
+ |
+LL | /// [`PrivateType`]
+ | ^^^^^^^^^^^^^ this item is private
+ |
+ = note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link resolves only because you passed `--document-private-items`, but will break without
+
+warning: 1 warning emitted
+
-warning: `[PrivateType]` public documentation for `public_item` links to a private item
+warning: public documentation for `public_item` links to private item `PrivateType`
--> $DIR/issue-74134.rs:19:10
|
LL | /// [`PrivateType`]
| ^^^^^^^^^^^^^ this item is private
|
= note: `#[warn(intra_doc_link_resolution_failure)]` on by default
+ = note: this link will resolve properly if you pass `--document-private-items`
warning: 1 warning emitted
// There are 4 cases here:
// 1. public item -> public type: no warning
-// 2. public item -> private type: warning, if --document-private-items is not passed
+// 2. public item -> private type: warning
// 3. private item -> public type: no warning
// 4. private item -> private type: no warning
// All 4 cases are tested with and without --document-private-items.
pub struct Public {
/// [`PublicType`]
/// [`PrivateType`]
- //[public]~^ WARNING public documentation for `public_item` links to a private
+ //~^ WARNING public documentation for `public_item` links to private item `PrivateType`
pub public_item: u32,
/// [`PublicType`]
/// ```
/// println!("sup");
/// ```
-pub fn link_error() {} //~^^^^^ ERROR cannot be resolved, ignoring it
+pub fn link_error() {} //~^^^^^ ERROR unresolved link to `error`
/// wait, this doesn't have a doctest?
pub fn no_doctest() {} //~^ ERROR missing code example in this documentation
| ^^^^^^^
= note: `#[deny(private_doc_tests)]` implied by `#[deny(rustdoc)]`
-error: `[error]` cannot be resolved, ignoring it.
+error: unresolved link to `error`
--> $DIR/lint-group.rs:9:29
|
LL | /// what up, let's make an [error]
- | ^^^^^ cannot be resolved, ignoring
+ | ^^^^^ unresolved link
|
note: the lint level is defined here
--> $DIR/lint-group.rs:7:9
LL | #![deny(rustdoc)]
| ^^^^^^^
= note: `#[deny(intra_doc_link_resolution_failure)]` implied by `#[deny(rustdoc)]`
- = help: to escape `[` and `]` characters, just add '\' before them like `\[` or `\]`
+ = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
error: missing code example in this documentation
--> $DIR/lint-group.rs:16:1
--- /dev/null
+#![feature(staged_api)]
+#![stable(feature = "private_general", since = "1.0.0")]
+
+#[unstable(feature = "private_trait", issue = "none")]
+pub trait Bar {}
+
+#[stable(feature = "private_general", since = "1.0.0")]
+pub struct Foo {
+ // nothing
+}
+
+impl Foo {
+ #[stable(feature = "private_general", since = "1.0.0")]
+ pub fn stable_impl() {}
+}
+
+impl Foo {
+ #[unstable(feature = "private_trait", issue = "none")]
+ pub fn bar() {}
+
+ #[stable(feature = "private_general", since = "1.0.0")]
+ pub fn bar2() {}
+}
+
+#[stable(feature = "private_general", since = "1.0.0")]
+impl Bar for Foo {}
--- /dev/null
+// aux-build:unstable-trait.rs
+
+#![crate_name = "foo"]
+#![feature(private_trait)]
+
+extern crate unstable_trait;
+
+// @has foo/struct.Foo.html 'bar'
+// @has foo/struct.Foo.html 'bar2'
+#[doc(inline)]
+pub use unstable_trait::Foo;
--- /dev/null
+// Test that associated type bounds are correctly normalized when checking
+// default associated type values.
+// check-pass
+
+#![allow(incomplete_features)]
+#![feature(specialization)]
+
+#[derive(PartialEq)]
+enum Never {}
+trait Foo {
+ type Assoc: PartialEq; // PartialEq<<Self as Foo>::Assoc>
+}
+impl<T> Foo for T {
+ default type Assoc = Never;
+}
+
+trait Trait1 {
+ type Selection: PartialEq;
+}
+trait Trait2: PartialEq<Self> {}
+impl<T: Trait2> Trait1 for T {
+ default type Selection = T;
+}
+
+fn main() {}
#[cfg(transmute)] // one instantiations: BAD
fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
- bar(foo, x) //[transmute]~ ERROR E0495
+ bar(foo, x) //[transmute]~ ERROR E0759
}
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/project-fn-ret-contravariant.rs:38:8
|
-LL | bar(foo, x)
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 37:8...
- --> $DIR/project-fn-ret-contravariant.rs:37:8
- |
LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 {
- | ^^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/project-fn-ret-contravariant.rs:38:13
- |
-LL | bar(foo, x)
- | ^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
- --> $DIR/project-fn-ret-contravariant.rs:38:4
- |
+ | ------- this data with lifetime `'a`...
LL | bar(foo, x)
- | ^^^^^^^^^^^
+ | ----^^^---- ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
// Cannot instantiate `foo` with any lifetime other than `'a`,
// since it is provided as input.
- bar(foo, x) //[transmute]~ ERROR E0495
+ bar(foo, x) //[transmute]~ ERROR E0759
}
#[cfg(krisskross)] // two instantiations, mixing and matching: BAD
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/project-fn-ret-invariant.rs:49:9
|
-LL | bar(foo, x)
- | ^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 45:8...
- --> $DIR/project-fn-ret-invariant.rs:45:8
- |
LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> {
- | ^^
-note: ...so that the expression is assignable
- --> $DIR/project-fn-ret-invariant.rs:49:14
- |
-LL | bar(foo, x)
- | ^
- = note: expected `Type<'_>`
- found `Type<'a>`
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the expression is assignable
- --> $DIR/project-fn-ret-invariant.rs:49:5
- |
+ | -------- this data with lifetime `'a`...
+...
LL | bar(foo, x)
- | ^^^^^^^^^^^
- = note: expected `Type<'static>`
- found `Type<'_>`
+ | ----^^^---- ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
--- /dev/null
+struct S {}
+
+trait T<'a> {
+ type A;
+}
+
+impl T<'_> for S {
+ type A = u32;
+}
+
+fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
+//~^ ERROR binding for associated type `Output` references an anonymous lifetime
+//~^^ NOTE lifetimes appearing in an associated type are not considered constrained
+
+fn main() {}
--- /dev/null
+error[E0582]: binding for associated type `Output` references an anonymous lifetime, which does not appear in the trait input types
+ --> $DIR/issue-62200.rs:11:39
+ |
+LL | fn foo(x: impl Fn(<S as T<'_>>::A) -> <S as T<'_>>::A) {}
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: lifetimes appearing in an associated type are not considered constrained
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0582`.
struct Struct;
impl Struct {
- pub async fn run_dummy_fn(&self) { //~ ERROR cannot infer
+ pub async fn run_dummy_fn(&self) { //~ ERROR E0759
foo(|| self.bar()).await;
}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-62097.rs:12:31
|
LL | pub async fn run_dummy_fn(&self) {
// run-pass
-// compile-flags: -Z control-flow-guard
+// compile-flags: -C control-flow-guard
pub fn main() {
println!("hello, world");
| ^ expected an `FnOnce<()>` closure, found `{integer}`
|
= help: the trait `std::ops::FnOnce<()>` is not implemented for `{integer}`
- = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
error: aborting due to previous error
error[E0038]: the trait `NotObjectSafe` cannot be made into an object
- --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:6
+ --> $DIR/coherence-impl-trait-for-trait-object-safe.rs:7:24
|
LL | trait NotObjectSafe { fn eq(&self, other: Self); }
| ------------- ---- ...because method `eq` references the `Self` type in this parameter
| |
| this trait cannot be made into an object...
LL | impl NotObjectSafe for dyn NotObjectSafe { }
- | ^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^ the trait `NotObjectSafe` cannot be made into an object
|
= help: consider moving `eq` to another trait
another: T,
}
-fn main() { }
+struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
+ //~^ ERROR type parameters must be declared prior
+ //~| ERROR lifetime parameters must be declared prior
+ a: &'a T,
+ b: &'b U,
+}
+
+fn main() {
+ let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
+ //~^ ERROR lifetime provided when a type was expected
+ }
LL | struct Bad<const N: usize, T> {
| -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `<T, const N: usize>`
+error: lifetime parameters must be declared prior to const parameters
+ --> $DIR/argument_order.rs:9:32
+ |
+LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
+ | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
+
+error: type parameters must be declared prior to const parameters
+ --> $DIR/argument_order.rs:9:36
+ |
+LL | struct AlsoBad<const N: usize, 'a, T, 'b, const M: usize, U> {
+ | ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>`
+
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/argument_order.rs:1:12
|
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-error: aborting due to previous error; 1 warning emitted
+error[E0747]: lifetime provided when a type was expected
+ --> $DIR/argument_order.rs:17:23
+ |
+LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>;
+ | ^^^^^^^
+ |
+ = note: lifetime arguments must be provided before type arguments
+ = help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>`
+
+error: aborting due to 4 previous errors; 1 warning emitted
+For more information about this error, try `rustc --explain E0747`.
--- /dev/null
+// check-pass
+
+pub fn yes_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
+where
+ A: PartialEq<B>,
+{
+ Vec::<A>::new()
+}
+
+pub fn yes_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
+where
+ A: PartialEq<B>,
+{
+ Vec::<A>::new()
+}
+
+use std::collections::VecDeque;
+
+pub fn yes_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+pub fn yes_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+pub fn yes_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]>
+where
+ A: PartialEq<B>,
+{
+ VecDeque::<A>::new()
+}
+
+fn main() {}
+++ /dev/null
-pub fn no_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
-//~^ ERROR arrays only have std trait implementations for lengths 0..=32
-where
- A: PartialEq<B>,
-{
- Vec::<A>::new()
-}
-
-pub fn no_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
-//~^ ERROR arrays only have std trait implementations for lengths 0..=32
-where
- A: PartialEq<B>,
-{
- Vec::<A>::new()
-}
-
-use std::collections::VecDeque;
-
-pub fn no_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
-//~^ ERROR arrays only have std trait implementations for lengths 0..=32
-where
- A: PartialEq<B>,
-{
- VecDeque::<A>::new()
-}
-
-pub fn no_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
-//~^ ERROR arrays only have std trait implementations for lengths 0..=32
-where
- A: PartialEq<B>,
-{
- VecDeque::<A>::new()
-}
-
-pub fn no_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]>
-//~^ ERROR arrays only have std trait implementations for lengths 0..=32
-where
- A: PartialEq<B>,
-{
- VecDeque::<A>::new()
-}
-
-fn main() {}
+++ /dev/null
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/alloc-traits-no-impls-length-33.rs:1:43
- |
-LL | pub fn no_vec_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
- | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
-...
-LL | Vec::<A>::new()
- | --------------- this returned value is of type `std::vec::Vec<A>`
- |
- = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::vec::Vec<A>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/alloc-traits-no-impls-length-33.rs:9:51
- |
-LL | pub fn no_vec_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
-...
-LL | Vec::<A>::new()
- | --------------- this returned value is of type `std::vec::Vec<A>`
- |
- = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::vec::Vec<A>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/alloc-traits-no-impls-length-33.rs:19:48
- |
-LL | pub fn no_vecdeque_partial_eq_array<A, B>() -> impl PartialEq<[B; 33]>
- | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
-...
-LL | VecDeque::<A>::new()
- | -------------------- this returned value is of type `std::collections::VecDeque<A>`
- |
- = note: required because of the requirements on the impl of `std::cmp::PartialEq<[B; 33]>` for `std::collections::VecDeque<A>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/alloc-traits-no-impls-length-33.rs:27:56
- |
-LL | pub fn no_vecdeque_partial_eq_ref_array<'a, A, B>() -> impl PartialEq<&'a [B; 33]>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
-...
-LL | VecDeque::<A>::new()
- | -------------------- this returned value is of type `std::collections::VecDeque<A>`
- |
- = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a [B; 33]>` for `std::collections::VecDeque<A>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/alloc-traits-no-impls-length-33.rs:35:60
- |
-LL | pub fn no_vecdeque_partial_eq_ref_mut_array<'a, A, B>() -> impl PartialEq<&'a mut [B; 33]>
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[B; 33]`
-...
-LL | VecDeque::<A>::new()
- | -------------------- this returned value is of type `std::collections::VecDeque<A>`
- |
- = note: required because of the requirements on the impl of `std::cmp::PartialEq<&'a mut [B; 33]>` for `std::collections::VecDeque<A>`
- = note: the return type of a function must have a statically known size
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+use std::{convert::TryFrom, rc::Rc, sync::Arc};
+
+pub fn yes_vec() {
+ let v: Vec<_> = [0; 33].into();
+}
+
+pub fn yes_box() {
+ let boxed_slice = Box::new([0; 33]) as Box<[i32]>;
+ let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
+ let boxed_slice = <Box<[i32]>>::from([0; 33]);
+}
+
+pub fn yes_rc() {
+ let boxed_slice = Rc::new([0; 33]) as Rc<[i32]>;
+ let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
+}
+
+pub fn yes_arc() {
+ let boxed_slice = Arc::new([0; 33]) as Arc<[i32]>;
+ let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
+}
+
+fn main() {}
+++ /dev/null
-// ignore-tidy-linelength
-
-use std::{convert::TryFrom, rc::Rc, sync::Arc};
-
-pub fn no_vec() {
- let v: Vec<_> = [0; 33].into();
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_box() {
- let boxed_slice = Box::new([0; 33]) as Box<[i32]>;
- let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
- //~^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::From<std::boxed::Box<[i32]>>` is not satisfied
- //~^^ ERROR the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom<std::boxed::Box<[i32]>>` is not satisfied
- let boxed_slice = <Box<[i32]>>::from([0; 33]);
- //~^ 15:42: 15:49: arrays only have std trait implementations for lengths 0..=32 [E0277]
-}
-
-pub fn no_rc() {
- let boxed_slice = Rc::new([0; 33]) as Rc<[i32]>;
- let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
- //~^ ERROR the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From<std::rc::Rc<[i32]>>` is not satisfied
- //~^^ ERROR the trait bound `std::rc::Rc<[i32; 33]>: std::convert::TryFrom<std::rc::Rc<[i32]>>` is not satisfied
-}
-
-pub fn no_arc() {
- let boxed_slice = Arc::new([0; 33]) as Arc<[i32]>;
- let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
- //~^ ERROR the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From<std::sync::Arc<[i32]>>` is not satisfied
- //~^^ ERROR the trait bound `std::sync::Arc<[i32; 33]>: std::convert::TryFrom<std::sync::Arc<[i32]>>` is not satisfied
-}
-
-fn main() {}
+++ /dev/null
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/alloc-types-no-impls-length-33.rs:6:29
- |
-LL | let v: Vec<_> = [0; 33].into();
- | ^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[{integer}; 33]`
- |
- = note: required because of the requirements on the impl of `std::convert::From<[{integer}; 33]>` for `std::vec::Vec<{integer}>`
- = note: required because of the requirements on the impl of `std::convert::Into<std::vec::Vec<{integer}>>` for `[{integer}; 33]`
-
-error[E0277]: the trait bound `std::boxed::Box<[i32; 33]>: std::convert::From<std::boxed::Box<[i32]>>` is not satisfied
- --> $DIR/alloc-types-no-impls-length-33.rs:12:23
- |
-LL | let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::boxed::Box<[i32]>>` is not implemented for `std::boxed::Box<[i32; 33]>`
- |
- = help: the following implementations were found:
- <std::boxed::Box<(dyn std::error::Error + 'a)> as std::convert::From<E>>
- <std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<&str>>
- <std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<std::borrow::Cow<'a, str>>>
- <std::boxed::Box<(dyn std::error::Error + 'static)> as std::convert::From<std::string::String>>
- and 22 others
- = note: required because of the requirements on the impl of `std::convert::Into<std::boxed::Box<[i32; 33]>>` for `std::boxed::Box<[i32]>`
- = note: required because of the requirements on the impl of `std::convert::TryFrom<std::boxed::Box<[i32]>>` for `std::boxed::Box<[i32; 33]>`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/alloc-types-no-impls-length-33.rs:15:42
- |
-LL | let boxed_slice = <Box<[i32]>>::from([0; 33]);
- | ^^^^^^^
- | |
- | expected an implementor of trait `std::convert::From<[{integer}; 33]>`
- | help: consider borrowing here: `&[0; 33]`
- |
- = note: the trait bound `[i32; 33]: std::convert::From<[{integer}; 33]>` is not satisfied
- = note: required because of the requirements on the impl of `std::convert::From<[i32; 33]>` for `std::boxed::Box<[i32]>`
- = note: required by `std::convert::From::from`
-
-error[E0277]: the trait bound `std::boxed::Box<[i32; 33]>: std::convert::TryFrom<std::boxed::Box<[i32]>>` is not satisfied
- --> $DIR/alloc-types-no-impls-length-33.rs:12:23
- |
-LL | let boxed_array = <Box<[i32; 33]>>::try_from(boxed_slice);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::boxed::Box<[i32]>>` is not implemented for `std::boxed::Box<[i32; 33]>`
- |
- = help: the following implementations were found:
- <std::boxed::Box<[T; N]> as std::convert::TryFrom<std::boxed::Box<[T]>>>
-
-error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::From<std::rc::Rc<[i32]>>` is not satisfied
- --> $DIR/alloc-types-no-impls-length-33.rs:21:23
- |
-LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::rc::Rc<[i32]>>` is not implemented for `std::rc::Rc<[i32; 33]>`
- |
- = help: the following implementations were found:
- <std::rc::Rc<B> as std::convert::From<std::borrow::Cow<'a, B>>>
- <std::rc::Rc<T> as std::convert::From<T>>
- <std::rc::Rc<T> as std::convert::From<std::boxed::Box<T>>>
- <std::rc::Rc<[T]> as std::convert::From<&[T]>>
- and 9 others
- = note: required because of the requirements on the impl of `std::convert::Into<std::rc::Rc<[i32; 33]>>` for `std::rc::Rc<[i32]>`
- = note: required because of the requirements on the impl of `std::convert::TryFrom<std::rc::Rc<[i32]>>` for `std::rc::Rc<[i32; 33]>`
-
-error[E0277]: the trait bound `std::rc::Rc<[i32; 33]>: std::convert::TryFrom<std::rc::Rc<[i32]>>` is not satisfied
- --> $DIR/alloc-types-no-impls-length-33.rs:21:23
- |
-LL | let boxed_array = <Rc<[i32; 33]>>::try_from(boxed_slice);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::rc::Rc<[i32]>>` is not implemented for `std::rc::Rc<[i32; 33]>`
- |
- = help: the following implementations were found:
- <std::rc::Rc<[T; N]> as std::convert::TryFrom<std::rc::Rc<[T]>>>
-
-error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::From<std::sync::Arc<[i32]>>` is not satisfied
- --> $DIR/alloc-types-no-impls-length-33.rs:28:23
- |
-LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<std::sync::Arc<[i32]>>` is not implemented for `std::sync::Arc<[i32; 33]>`
- |
- = help: the following implementations were found:
- <std::sync::Arc<B> as std::convert::From<std::borrow::Cow<'a, B>>>
- <std::sync::Arc<T> as std::convert::From<T>>
- <std::sync::Arc<T> as std::convert::From<std::boxed::Box<T>>>
- <std::sync::Arc<[T]> as std::convert::From<&[T]>>
- and 9 others
- = note: required because of the requirements on the impl of `std::convert::Into<std::sync::Arc<[i32; 33]>>` for `std::sync::Arc<[i32]>`
- = note: required because of the requirements on the impl of `std::convert::TryFrom<std::sync::Arc<[i32]>>` for `std::sync::Arc<[i32; 33]>`
-
-error[E0277]: the trait bound `std::sync::Arc<[i32; 33]>: std::convert::TryFrom<std::sync::Arc<[i32]>>` is not satisfied
- --> $DIR/alloc-types-no-impls-length-33.rs:28:23
- |
-LL | let boxed_array = <Arc<[i32; 33]>>::try_from(boxed_slice);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::TryFrom<std::sync::Arc<[i32]>>` is not implemented for `std::sync::Arc<[i32; 33]>`
- |
- = help: the following implementations were found:
- <std::sync::Arc<[T; N]> as std::convert::TryFrom<std::sync::Arc<[T]>>>
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+pub fn yes_as_ref() -> impl AsRef<[u8]> {
+ [0; 33]
+}
+
+pub fn yes_as_mut() -> impl AsMut<[u8]> {
+ [0; 33]
+}
+
+pub fn yes_borrow() -> impl std::borrow::Borrow<[u8]> {
+ [0; 33]
+}
+
+pub fn yes_borrow_mut() -> impl std::borrow::BorrowMut<[u8]> {
+ [0; 33]
+}
+
+pub fn yes_try_from_slice() -> impl std::convert::TryFrom<&'static [u8]> {
+ [0; 33]
+}
+
+pub fn yes_ref_try_from_slice() -> impl std::convert::TryFrom<&'static [u8]> {
+ let a: &'static _ = &[0; 33];
+ a
+}
+
+pub fn yes_hash() -> impl std::hash::Hash {
+ [0; 33]
+}
+
+pub fn yes_debug() -> impl std::fmt::Debug {
+ [0; 33]
+}
+
+pub fn yes_ref_into_iterator() -> impl IntoIterator<Item=&'static u8> {
+ let a: &'static _ = &[0; 33];
+ a
+}
+
+pub fn yes_partial_eq() -> impl PartialEq<[u8; 33]> {
+ [0; 33]
+}
+
+pub fn yes_partial_eq_slice() -> impl PartialEq<[u8]> {
+ [0; 33]
+}
+
+pub fn yes_slice_partial_eq() -> impl PartialEq<[u8; 33]> {
+ let a: &'static _ = &[0; 33];
+ &a[..]
+}
+
+pub fn yes_eq() -> impl Eq {
+ [0; 33]
+}
+
+pub fn yes_partial_ord() -> impl PartialOrd<[u8; 33]> {
+ [0; 33]
+}
+
+pub fn yes_ord() -> impl Ord {
+ [0; 33]
+}
+
+fn main() {}
+++ /dev/null
-pub fn no_debug() {
- println!("{:?}", [0_usize; 33]);
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_hash() {
- use std::collections::HashSet;
- let mut set = HashSet::new();
- set.insert([0_usize; 33]);
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_partial_eq() -> bool {
- [0_usize; 33] == [1_usize; 33]
- //~^ ERROR binary operation `==` cannot be applied to type `[usize; 33]`
-}
-
-pub fn no_partial_ord() -> bool {
- [0_usize; 33] < [1_usize; 33]
- //~^ ERROR binary operation `<` cannot be applied to type `[usize; 33]`
-}
-
-pub fn no_into_iterator() {
- for _ in &[0_usize; 33] {
- //~^ ERROR the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/core-traits-no-impls-length-33.rs:2:22
- |
-LL | println!("{:?}", [0_usize; 33]);
- | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]`
- |
- = note: required because of the requirements on the impl of `std::fmt::Debug` for `[usize; 33]`
- = note: required by `std::fmt::Debug::fmt`
- = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/core-traits-no-impls-length-33.rs:9:16
- |
-LL | set.insert([0_usize; 33]);
- | ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]`
- |
- = note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]`
-
-error[E0369]: binary operation `==` cannot be applied to type `[usize; 33]`
- --> $DIR/core-traits-no-impls-length-33.rs:14:19
- |
-LL | [0_usize; 33] == [1_usize; 33]
- | ------------- ^^ ------------- [usize; 33]
- | |
- | [usize; 33]
-
-error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]`
- --> $DIR/core-traits-no-impls-length-33.rs:19:19
- |
-LL | [0_usize; 33] < [1_usize; 33]
- | ------------- ^ ------------- [usize; 33]
- | |
- | [usize; 33]
-
-error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied
- --> $DIR/core-traits-no-impls-length-33.rs:24:14
- |
-LL | for _ in &[0_usize; 33] {
- | ^^^^^^^^^^^^^^ the trait `std::iter::IntoIterator` is not implemented for `&[usize; 33]`
- |
- = help: the following implementations were found:
- <&'a [T; N] as std::iter::IntoIterator>
- <&'a [T] as std::iter::IntoIterator>
- <&'a mut [T; N] as std::iter::IntoIterator>
- <&'a mut [T] as std::iter::IntoIterator>
- = note: required by `std::iter::IntoIterator::into_iter`
-
-error: aborting due to 5 previous errors
-
-Some errors have detailed explanations: E0277, E0369.
-For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+#![feature(array_value_iter)]
+#![feature(trusted_len)]
+
+use std::{
+ array::IntoIter,
+ fmt::Debug,
+ iter::{ExactSizeIterator, FusedIterator, TrustedLen},
+};
+
+pub fn yes_iterator() -> impl Iterator<Item = i32> {
+ IntoIter::new([0i32; 33])
+}
+
+pub fn yes_double_ended_iterator() -> impl DoubleEndedIterator {
+ IntoIter::new([0i32; 33])
+}
+
+pub fn yes_exact_size_iterator() -> impl ExactSizeIterator {
+ IntoIter::new([0i32; 33])
+}
+
+pub fn yes_fused_iterator() -> impl FusedIterator {
+ IntoIter::new([0i32; 33])
+}
+
+pub fn yes_trusted_len() -> impl TrustedLen {
+ IntoIter::new([0i32; 33])
+}
+
+pub fn yes_clone() -> impl Clone {
+ IntoIter::new([0i32; 33])
+}
+
+pub fn yes_debug() -> impl Debug {
+ IntoIter::new([0i32; 33])
+}
+
+
+fn main() {}
+++ /dev/null
-#![feature(array_value_iter)]
-#![feature(trusted_len)]
-
-use std::{
- array::IntoIter,
- fmt::Debug,
- iter::{ExactSizeIterator, FusedIterator, TrustedLen},
-};
-
-pub fn no_iterator() -> impl Iterator<Item = i32> {
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
- IntoIter::new([0i32; 33])
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_double_ended_iterator() -> impl DoubleEndedIterator {
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
- IntoIter::new([0i32; 33])
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_exact_size_iterator() -> impl ExactSizeIterator {
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
- IntoIter::new([0i32; 33])
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_fused_iterator() -> impl FusedIterator {
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
- IntoIter::new([0i32; 33])
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_trusted_len() -> impl TrustedLen {
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
- IntoIter::new([0i32; 33])
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_clone() -> impl Clone {
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
- IntoIter::new([0i32; 33])
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-pub fn no_debug() -> impl Debug {
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
- IntoIter::new([0i32; 33])
- //~^ ERROR arrays only have std trait implementations for lengths 0..=32
-}
-
-
-fn main() {}
+++ /dev/null
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:12:19
- |
-LL | IntoIter::new([0i32; 33])
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
- |
- = note: required by `std::array::IntoIter::<T, N>::new`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:10:25
- |
-LL | pub fn no_iterator() -> impl Iterator<Item = i32> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
-LL |
-LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
- |
- = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::array::IntoIter<i32, 33_usize>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:18:19
- |
-LL | IntoIter::new([0i32; 33])
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
- |
- = note: required by `std::array::IntoIter::<T, N>::new`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:16:38
- |
-LL | pub fn no_double_ended_iterator() -> impl DoubleEndedIterator {
- | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
-LL |
-LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
- |
- = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::array::IntoIter<i32, 33_usize>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:24:19
- |
-LL | IntoIter::new([0i32; 33])
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
- |
- = note: required by `std::array::IntoIter::<T, N>::new`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:22:36
- |
-LL | pub fn no_exact_size_iterator() -> impl ExactSizeIterator {
- | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
-LL |
-LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
- |
- = note: required because of the requirements on the impl of `std::iter::ExactSizeIterator` for `std::array::IntoIter<i32, 33_usize>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:30:19
- |
-LL | IntoIter::new([0i32; 33])
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
- |
- = note: required by `std::array::IntoIter::<T, N>::new`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:28:31
- |
-LL | pub fn no_fused_iterator() -> impl FusedIterator {
- | ^^^^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
-LL |
-LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
- |
- = note: required because of the requirements on the impl of `std::iter::FusedIterator` for `std::array::IntoIter<i32, 33_usize>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:36:19
- |
-LL | IntoIter::new([0i32; 33])
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
- |
- = note: required by `std::array::IntoIter::<T, N>::new`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:34:28
- |
-LL | pub fn no_trusted_len() -> impl TrustedLen {
- | ^^^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
-LL |
-LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
- |
- = note: required because of the requirements on the impl of `std::iter::TrustedLen` for `std::array::IntoIter<i32, 33_usize>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:42:19
- |
-LL | IntoIter::new([0i32; 33])
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
- |
- = note: required by `std::array::IntoIter::<T, N>::new`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:40:22
- |
-LL | pub fn no_clone() -> impl Clone {
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
-LL |
-LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
- |
- = note: required because of the requirements on the impl of `std::clone::Clone` for `std::array::IntoIter<i32, 33_usize>`
- = note: the return type of a function must have a statically known size
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:48:19
- |
-LL | IntoIter::new([0i32; 33])
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
- |
- = note: required by `std::array::IntoIter::<T, N>::new`
-
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/into-iter-no-impls-length-33.rs:46:22
- |
-LL | pub fn no_debug() -> impl Debug {
- | ^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[i32; 33]`
-LL |
-LL | IntoIter::new([0i32; 33])
- | ------------------------- this returned value is of type `std::array::IntoIter<i32, 33_usize>`
- |
- = note: required because of the requirements on the impl of `std::fmt::Debug` for `std::array::IntoIter<i32, 33_usize>`
- = note: the return type of a function must have a statically known size
-
-error: aborting due to 14 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
+// run-pass
+
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
#[derive(Debug)]
struct S<T: Debug, const N: usize>([T; N]);
-//~^ ERROR arrays only have std trait implementations for lengths 0..=32
fn main() {}
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/broken-mir-2.rs:1:12
+ --> $DIR/broken-mir-2.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/broken-mir-2.rs:7:36
- |
-LL | struct S<T: Debug, const N: usize>([T; N]);
- | ^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[T; N]`
- |
- = note: required because of the requirements on the impl of `std::fmt::Debug` for `[T; N]`
- = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[T; N]`
- = note: required for the cast to the object type `dyn std::fmt::Debug`
- = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-pass
+
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+#![allow(dead_code)]
+
+fn test<const N: usize>() {}
+
+fn wow<'a>() -> &'a () {
+ test::<{
+ let _: &'a ();
+ 3
+ }>();
+ &()
+}
+
+fn main() {}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/const-argument-non-static-lifetime.rs:3:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
--- /dev/null
+#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+
+struct A<T = u32, const N: usize> {
+ //~^ ERROR type parameters with a default must be trailing
+ arg: T,
+}
+
+fn main() {}
--- /dev/null
+error: type parameters with a default must be trailing
+ --> $DIR/wrong-order.rs:3:10
+ |
+LL | struct A<T = u32, const N: usize> {
+ | ^
+ |
+ = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/wrong-order.rs:1:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: aborting due to previous error; 1 warning emitted
+
+// run-pass
+
#![feature(const_generics)]
//~^ WARN the feature `const_generics` is incomplete
#[derive(Debug)]
struct X<const N: usize> {
- a: [u32; N], //~ ERROR arrays only have std trait implementations for lengths 0..=32
+ a: [u32; N],
}
fn main() {}
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/derive-debug-array-wrapper.rs:1:12
+ --> $DIR/derive-debug-array-wrapper.rs:3:12
|
LL | #![feature(const_generics)]
| ^^^^^^^^^^^^^^
= note: `#[warn(incomplete_features)]` on by default
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-error[E0277]: arrays only have std trait implementations for lengths 0..=32
- --> $DIR/derive-debug-array-wrapper.rs:6:5
- |
-LL | a: [u32; N],
- | ^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[u32; N]`
- |
- = note: required because of the requirements on the impl of `std::fmt::Debug` for `[u32; N]`
- = note: required because of the requirements on the impl of `std::fmt::Debug` for `&[u32; N]`
- = note: required for the cast to the object type `dyn std::fmt::Debug`
- = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error; 1 warning emitted
+warning: 1 warning emitted
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995.
+
+#![feature(const_generics)]
+//~^ WARN: the feature `const_generics` is incomplete
+#![crate_type = "lib"]
+
+use std::marker::PhantomData;
+
+struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+//~^ ERROR: use of non-static lifetime `'a` in const generic
+
+impl Bug<'_, ""> {}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-56445.rs:3:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0771]: use of non-static lifetime `'a` in const generic
+ --> $DIR/issue-56445.rs:9:26
+ |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+ | ^^
+ |
+ = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0771`.
// build-fail
// Regression test for #66975
-#![warn(const_err)]
+#![warn(const_err, unconditional_panic)]
#![feature(never_type)]
struct PrintName<T>(T);
impl<T> PrintName<T> {
const VOID: ! = { let x = 0 * std::mem::size_of::<T>(); [][x] };
//~^ WARN any use of this value will cause an error
+
}
fn f<T>() {
note: the lint level is defined here
--> $DIR/index-out-of-bounds-never-type.rs:4:9
|
-LL | #![warn(const_err)]
+LL | #![warn(const_err, unconditional_panic)]
| ^^^^^^^^^
error: erroneous constant encountered
- --> $DIR/index-out-of-bounds-never-type.rs:15:13
+ --> $DIR/index-out-of-bounds-never-type.rs:16:13
|
LL | let _ = PrintName::<T>::VOID;
| ^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// check-pass
+//
+// This test is complement to the test in issue-73976-polymorphic.rs.
+// In that test we ensure that polymorphic use of type_id and type_name in patterns
+// will be properly rejected. This test will ensure that monomorphic use of these
+// would not be wrongly rejected in patterns.
+
+#![feature(const_type_id)]
+#![feature(const_type_name)]
+
+use std::any::{self, TypeId};
+
+pub struct GetTypeId<T>(T);
+
+impl<T: 'static> GetTypeId<T> {
+ pub const VALUE: TypeId = TypeId::of::<T>();
+}
+
+const fn check_type_id<T: 'static>() -> bool {
+ matches!(GetTypeId::<T>::VALUE, GetTypeId::<usize>::VALUE)
+}
+
+pub struct GetTypeNameLen<T>(T);
+
+impl<T: 'static> GetTypeNameLen<T> {
+ pub const VALUE: usize = any::type_name::<T>().len();
+}
+
+const fn check_type_name_len<T: 'static>() -> bool {
+ matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<usize>::VALUE)
+}
+
+fn main() {
+ assert!(check_type_id::<usize>());
+ assert!(check_type_name_len::<usize>());
+}
--- /dev/null
+// This test is from #73976. We previously did not check if a type is monomorphized
+// before calculating its type id, which leads to the bizzare behaviour below that
+// TypeId of a generic type does not match itself.
+//
+// This test case should either run-pass or be rejected at compile time.
+// Currently we just disallow this usage and require pattern is monomorphic.
+
+#![feature(const_type_id)]
+#![feature(const_type_name)]
+
+use std::any::{self, TypeId};
+
+pub struct GetTypeId<T>(T);
+
+impl<T: 'static> GetTypeId<T> {
+ pub const VALUE: TypeId = TypeId::of::<T>();
+}
+
+const fn check_type_id<T: 'static>() -> bool {
+ matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+ //~^ ERROR could not evaluate constant pattern
+ //~| ERROR could not evaluate constant pattern
+}
+
+pub struct GetTypeNameLen<T>(T);
+
+impl<T: 'static> GetTypeNameLen<T> {
+ pub const VALUE: usize = any::type_name::<T>().len();
+}
+
+const fn check_type_name_len<T: 'static>() -> bool {
+ matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+ //~^ ERROR could not evaluate constant pattern
+ //~| ERROR could not evaluate constant pattern
+}
+
+fn main() {
+ assert!(check_type_id::<usize>());
+ assert!(check_type_name_len::<usize>());
+}
--- /dev/null
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:20:37
+ |
+LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:32:42
+ |
+LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:20:37
+ |
+LL | matches!(GetTypeId::<T>::VALUE, GetTypeId::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^
+
+error: could not evaluate constant pattern
+ --> $DIR/issue-73976-polymorphic.rs:32:42
+ |
+LL | matches!(GetTypeNameLen::<T>::VALUE, GetTypeNameLen::<T>::VALUE)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
pub fn crash() -> bool {
[5; Self::HOST_SIZE] == [6; 0]
//~^ ERROR constant expression depends on a generic parameter
- //~| ERROR binary operation `==` cannot be applied to type `[{integer}; _]`
+ //~| ERROR constant expression depends on a generic parameter
+ //~| ERROR can't compare `[{integer}; _]` with `[{integer}; 0]`
}
}
|
= note: this may fail depending on what value the parameter takes
-error[E0369]: binary operation `==` cannot be applied to type `[{integer}; _]`
+error: constant expression depends on a generic parameter
+ --> $DIR/too_generic_eval_ice.rs:7:30
+ |
+LL | [5; Self::HOST_SIZE] == [6; 0]
+ | ^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error[E0277]: can't compare `[{integer}; _]` with `[{integer}; 0]`
--> $DIR/too_generic_eval_ice.rs:7:30
|
LL | [5; Self::HOST_SIZE] == [6; 0]
- | -------------------- ^^ ------ [{integer}; 0]
- | |
- | [{integer}; _]
+ | ^^ no implementation for `[{integer}; _] == [{integer}; 0]`
+ |
+ = help: the trait `std::cmp::PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]`
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0369`.
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+trait DynEq {}
+
+impl<'a> PartialEq for &'a (dyn DynEq + 'static) {
+ fn eq(&self, _other: &Self) -> bool {
+ true
+ }
+}
+
+impl Eq for &dyn DynEq {} //~ ERROR E0308
+
+fn main() {
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/E0308-2.rs:9:6
+ |
+LL | impl Eq for &dyn DynEq {}
+ | ^^ lifetime mismatch
+ |
+ = note: expected trait `std::cmp::PartialEq`
+ found trait `std::cmp::PartialEq`
+note: the lifetime `'_` as defined on the impl at 9:13...
+ --> $DIR/E0308-2.rs:9:13
+ |
+LL | impl Eq for &dyn DynEq {}
+ | ^
+ = note: ...does not necessarily outlive the static lifetime
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![feature(const_generics)]
+//~^ WARN the feature `const_generics` is incomplete
+
+fn function_with_str<'a, const STRING: &'a str>() {} //~ ERROR E0771
+
+fn main() {
+ function_with_str::<"Hello, world!">()
+}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/E0771.rs:1:12
+ |
+LL | #![feature(const_generics)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0771]: use of non-static lifetime `'a` in const generic
+ --> $DIR/E0771.rs:4:41
+ |
+LL | fn function_with_str<'a, const STRING: &'a str>() {}
+ | ^^
+ |
+ = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0771`.
| ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `extern "C" fn() {f}`
- = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }`
error: aborting due to previous error
= help: consider moving `foo` to another trait
error[E0038]: the trait `NonObjectSafe1` cannot be made into an object
- --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:6
+ --> $DIR/feature-gate-object_safe_for_dispatch.rs:38:16
|
LL | trait NonObjectSafe1: Sized {}
| -------------- ----- ...because it requires `Self: Sized`
| this trait cannot be made into an object...
...
LL | impl Trait for dyn NonObjectSafe1 {}
- | ^^^^^ the trait `NonObjectSafe1` cannot be made into an object
+ | ^^^^^^^^^^^^^^^^^^ the trait `NonObjectSafe1` cannot be made into an object
error: aborting due to 5 previous errors
LL | type F<'a> = Self;
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
- = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
help: consider restricting type parameter `T`
|
LL | impl<T: std::ops::Fn<()>> Fun for T {
LL | type F<'a> = Self;
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
- = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
help: consider restricting type parameter `T`
|
LL | impl<T: std::ops::Fn<()>> Fun for T {
LL | type F<'a> = Self;
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
- = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
help: consider restricting type parameter `T`
|
LL | impl<T: std::ops::Fn<()>> Fun for T {
LL | type F<'a> = Self;
| ^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `T`
|
- = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }`
help: consider restricting type parameter `T`
|
LL | impl<T: std::ops::Fn<()>> Fun for T {
--- /dev/null
+#![feature(decl_macro)]
+macro x() { struct MyStruct; }
+
+x!();
+x!();
--- /dev/null
+pub const IN_DEF_CRATE: &str = "In def crate!";
+
+macro_rules! make_it {
+ () => {
+ #[macro_export]
+ macro_rules! inner {
+ () => {
+ $crate::IN_DEF_CRATE
+ }
+ }
+ }
+}
+
+make_it!();
--- /dev/null
+// check-pass
+// aux-build:needs_hygiene.rs
+
+extern crate needs_hygiene;
+
+use needs_hygiene::*;
+
+fn main() {}
--- /dev/null
+// aux-build:nested-dollar-crate.rs
+// edition:2018
+// run-pass
+
+extern crate nested_dollar_crate;
+
+fn main() {
+ assert_eq!(nested_dollar_crate::inner!(), "In def crate!");
+}
--- /dev/null
+// run-fail
+// check-run-results
+// exec-env:RUST_BACKTRACE=0
+//
+// Regression test for issue #70963
+// The captured stderr from this test reports a location
+// inside `VecDeque::with_capacity`, instead of `<::core::macros::panic macros>`
+fn main() {
+ std::collections::VecDeque::<String>::with_capacity(!0);
+}
--- /dev/null
+thread 'main' panicked at 'capacity overflow', $SRC_DIR/liballoc/collections/vec_deque.rs:LL:COL
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
}
fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
- static_val(x); //~ ERROR cannot infer
+ static_val(x); //~ ERROR E0759
}
fn not_static_val<T: NotStaticTrait>(_: T) {
-error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/dyn-trait.rs:20:16
|
-LL | static_val(x);
- | ^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 19:26...
- --> $DIR/dyn-trait.rs:19:26
- |
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
- | ^^
-note: ...so that the expression is assignable
- --> $DIR/dyn-trait.rs:20:16
- |
+ | ------------------- this data with lifetime `'a`...
LL | static_val(x);
- | ^
- = note: expected `std::boxed::Box<dyn std::fmt::Debug>`
- found `std::boxed::Box<(dyn std::fmt::Debug + 'a)>`
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that the types are compatible
+ | ^ ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
--> $DIR/dyn-trait.rs:20:5
|
LL | static_val(x);
| ^^^^^^^^^^
- = note: expected `StaticTrait`
- found `StaticTrait`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
--- /dev/null
+// Regression test for #72911.
+
+pub struct Lint {}
+
+impl Lint {}
+
+pub fn gather_all() -> impl Iterator<Item = Lint> {
+ //~^ ERROR: cannot resolve opaque type
+ lint_files().flat_map(|f| gather_from_file(&f))
+}
+
+fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
+ //~^ ERROR: failed to resolve
+ unimplemented!()
+}
+
+fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
+ //~^ ERROR: failed to resolve
+ unimplemented!()
+}
+
+fn main() {}
--- /dev/null
+error[E0433]: failed to resolve: use of undeclared type or module `foo`
+ --> $DIR/issue-72911.rs:12:33
+ |
+LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
+ | ^^^ use of undeclared type or module `foo`
+
+error[E0433]: failed to resolve: use of undeclared type or module `foo`
+ --> $DIR/issue-72911.rs:17:41
+ |
+LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
+ | ^^^ use of undeclared type or module `foo`
+
+error[E0720]: cannot resolve opaque type
+ --> $DIR/issue-72911.rs:7:24
+ |
+LL | pub fn gather_all() -> impl Iterator<Item = Lint> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
+LL |
+LL | lint_files().flat_map(|f| gather_from_file(&f))
+ | -----------------------------------------------
+ | |
+ | returning here with type `std::iter::FlatMap<impl std::iter::Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+ | returning here with type `std::iter::FlatMap<impl std::iter::Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+...
+LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator<Item = Lint> {
+ | -------------------------- returning this opaque type `std::iter::FlatMap<impl std::iter::Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+...
+LL | fn lint_files() -> impl Iterator<Item = foo::MissingItem> {
+ | -------------------------------------- returning this opaque type `std::iter::FlatMap<impl std::iter::Iterator, [type error], [closure@$DIR/issue-72911.rs:9:27: 9:51]>`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0433, E0720.
+For more information about an error, try `rustc --explain E0433`.
| ^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+ --> $DIR/must_outlive_least_region_or_bound.rs:5:32
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| -- ^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
| ^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+ --> $DIR/must_outlive_least_region_or_bound.rs:7:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| - ^ returning this value requires that `'1` must outlive `'static`
= help: consider replacing `'1` with `'static`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
= help: consider replacing `'a` with `'static`
error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:15:41
+ --> $DIR/must_outlive_least_region_or_bound.rs:11:41
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^ lifetime `'a` required
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:30:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:24
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'1` must outlive `'static`
| let's call the lifetime of this reference `'1`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+ --> $DIR/must_outlive_least_region_or_bound.rs:28:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| -- lifetime `'a` defined here ^ returning this value requires that `'a` must outlive `'static`
= help: consider replacing `'a` with `'static`
error: lifetime may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:42:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:32:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| -- -- lifetime `'b` defined here ^^^^^^^^^^^^^^^^ opaque type requires that `'b` must outlive `'a`
= help: consider adding the following bound: `'b: 'a`
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:47:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:37:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| ^^^^^^^^^^^^^^^^^^^^
use std::fmt::Debug;
-fn elided(x: &i32) -> impl Copy { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided(x: &i32) -> impl Copy { x } //~ ERROR E0759
-fn explicit<'a>(x: &'a i32) -> impl Copy { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit<'a>(x: &'a i32) -> impl Copy { x } //~ ERROR E0759
-fn elided2(x: &i32) -> impl Copy + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided2(x: &i32) -> impl Copy + 'static { x } //~ ERROR E0759
-fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } //~ ERROR E0759
fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
//~^ ERROR explicit lifetime required in the type of `x`
-fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759
-fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) } //~ ERROR E0759
-fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
-fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
-//~^ ERROR cannot infer an appropriate lifetime
+fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) } //~ ERROR E0759
-fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
-//~^ ERROR cannot infer an appropriate lifetime
-//~| ERROR cannot infer an appropriate lifetime
+fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) } //~ ERROR E0759
+//~^ ERROR E0759
trait LifetimeTrait<'a> {}
impl<'a> LifetimeTrait<'a> for &'a i32 {}
-fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
-//~^ ERROR cannot infer an appropriate lifetime
+fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } //~ ERROR E0759
// Tests that a closure type containing 'b cannot be returned from a type where
// only 'a was expected.
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/must_outlive_least_region_or_bound.rs:3:35
|
LL | fn elided(x: &i32) -> impl Copy { x }
LL | fn elided(x: &i32) -> impl Copy + '_ { x }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:6:44
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:5:44
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| ------- ^ ...is captured here...
| this data with lifetime `'a`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:6:32
+ --> $DIR/must_outlive_least_region_or_bound.rs:5:32
|
LL | fn explicit<'a>(x: &'a i32) -> impl Copy { x }
| ^^^^^^^^^
LL | fn explicit<'a>(x: &'a i32) -> impl Copy + 'a { x }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:9:46
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:7:46
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ---- ^ ...is captured here...
| this data with an anonymous lifetime `'_`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:9:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:7:24
|
LL | fn elided2(x: &i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^^^^^^^^
LL | fn elided2(x: &'static i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:12:55
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:55
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ------- ^ ...is captured here...
| this data with lifetime `'a`...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:12:33
+ --> $DIR/must_outlive_least_region_or_bound.rs:9:33
|
LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x }
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^
error[E0621]: explicit lifetime required in the type of `x`
- --> $DIR/must_outlive_least_region_or_bound.rs:15:24
+ --> $DIR/must_outlive_least_region_or_bound.rs:11:24
|
LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
| ---- ^^^^^^^^^^^^^^ lifetime `'a` required
| |
| help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:30:65
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:65
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static`
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:30:69
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:69
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| ---- this data with an anonymous lifetime `'_`... ^ ...is captured here...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:30:41
+ --> $DIR/must_outlive_least_region_or_bound.rs:22:41
|
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug) { (Box::new(x), x) }
| ^^^^^^^^^^
LL | fn elided5(x: &i32) -> (Box<dyn Debug>, impl Debug + '_) { (Box::new(x), x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:37:69
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:28:69
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ------- this data with lifetime `'a`... ^ ...is captured here...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/must_outlive_least_region_or_bound.rs:37:34
+ --> $DIR/must_outlive_least_region_or_bound.rs:28:34
|
LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^
error[E0623]: lifetime mismatch
- --> $DIR/must_outlive_least_region_or_bound.rs:42:61
+ --> $DIR/must_outlive_least_region_or_bound.rs:32:61
|
LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32) {
| ------- ^^^^^^^^^^^^^^^^
| this parameter and the return type are declared with different lifetimes...
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/must_outlive_least_region_or_bound.rs:47:51
+ --> $DIR/must_outlive_least_region_or_bound.rs:37:51
|
LL | fn ty_param_wont_outlive_static<T:Debug>(x: T) -> impl Debug + 'static {
| -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
| |
| help: consider adding an explicit lifetime bound...: `T: 'static +`
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:18:50
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:14:50
|
LL | fn elided3(x: &i32) -> Box<dyn Debug> { Box::new(x) }
| ---- ^ ...is captured here, requiring it to live as long as `'static`
LL | fn elided3(x: &i32) -> Box<dyn Debug + '_> { Box::new(x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:21:59
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:16:59
|
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug> { Box::new(x) }
| ------- ^ ...is captured here, requiring it to live as long as `'static`
LL | fn explicit3<'a>(x: &'a i32) -> Box<dyn Debug + 'a> { Box::new(x) }
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:24:60
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:18:60
|
LL | fn elided4(x: &i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ---- ^ ...is captured here, requiring it to live as long as `'static`
LL | fn elided4(x: &'static i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/must_outlive_least_region_or_bound.rs:27:69
+error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/must_outlive_least_region_or_bound.rs:20:69
|
LL | fn explicit4<'a>(x: &'a i32) -> Box<dyn Debug + 'static> { Box::new(x) }
| ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lifetime may not live long enough
- --> $DIR/static-return-lifetime-infered.rs:10:37
+ --> $DIR/static-return-lifetime-infered.rs:9:37
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| -- ^^^^^^^^^^^^^^^^^^^^^^^ opaque type requires that `'a` must outlive `'static`
impl A {
fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
- self.x.iter().map(|a| a.0)
+ self.x.iter().map(|a| a.0) //~ ERROR E0759
}
- //~^^ ERROR cannot infer an appropriate lifetime
fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
- self.x.iter().map(|a| a.0)
+ self.x.iter().map(|a| a.0) //~ ERROR E0759
}
- //~^^ ERROR cannot infer an appropriate lifetime
}
fn main() {}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/static-return-lifetime-infered.rs:7:16
|
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> {
LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + '_ {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
- --> $DIR/static-return-lifetime-infered.rs:11:16
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/static-return-lifetime-infered.rs:10:16
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| -------- this data with lifetime `'a`...
| ...is captured here...
|
note: ...and is required to live as long as `'static` here
- --> $DIR/static-return-lifetime-infered.rs:10:37
+ --> $DIR/static-return-lifetime-infered.rs:9:37
|
LL | fn iter_values<'a>(&'a self) -> impl Iterator<Item=u32> {
| ^^^^^^^^^^^^^^^^^^^^^^^
--- /dev/null
+// edition:2018
+
+use std::convert::{TryFrom, TryInto};
+use std::io;
+
+pub struct MyStream;
+pub struct OtherStream;
+
+pub async fn connect() -> io::Result<MyStream> {
+ let stream: MyStream = OtherStream.try_into()?;
+ Ok(stream)
+}
+
+impl TryFrom<OtherStream> for MyStream {}
+//~^ ERROR: missing
+
+fn main() {}
--- /dev/null
+error[E0046]: not all trait items implemented, missing: `Error`, `try_from`
+ --> $DIR/issue-74047.rs:14:1
+ |
+LL | impl TryFrom<OtherStream> for MyStream {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation
+ |
+ = help: implement the missing item: `type Error = Type;`
+ = help: implement the missing item: `fn try_from(_: T) -> std::result::Result<Self, <Self as std::convert::TryFrom<T>>::Error> { todo!() }`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
use std::any::Any;
fn foo<T: Any>(value: &T) -> Box<dyn Any> {
- Box::new(value) as Box<dyn Any>
- //~^ ERROR cannot infer an appropriate lifetime
+ Box::new(value) as Box<dyn Any> //~ ERROR E0759
}
fn main() {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/issue-16922.rs:4:14
|
LL | fn foo<T: Any>(value: &T) -> Box<dyn Any> {
error[E0277]: the trait bound `T: Bound` is not satisfied
- --> $DIR/issue-21837.rs:8:9
+ --> $DIR/issue-21837.rs:8:20
|
LL | pub struct Foo<T: Bound>(T);
| ----- required by this bound in `Foo`
...
LL | impl<T> Trait2 for Foo<T> {}
- | ^^^^^^ the trait `Bound` is not implemented for `T`
+ | ^^^^^^ the trait `Bound` is not implemented for `T`
|
help: consider restricting type parameter `T`
|
| ^^^ expected an `Fn<()>` closure, found `()`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `()`
- = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }`
= note: required for the cast to the object type `dyn std::ops::Fn()`
error: aborting due to previous error
--- /dev/null
+enum E {
+ A(u8, u8),
+}
+
+fn main() {
+ let e = E::A(2, 3);
+ match e {
+ E::A(x @ ..) => { //~ ERROR `x @` is not allowed in a tuple
+ x //~ ERROR cannot find value `x` in this scope
+ }
+ };
+}
--- /dev/null
+error[E0425]: cannot find value `x` in this scope
+ --> $DIR/issue-74539.rs:9:13
+ |
+LL | x
+ | ^ help: a local variable with a similar name exists: `e`
+
+error: `x @` is not allowed in a tuple struct
+ --> $DIR/issue-74539.rs:8:14
+ |
+LL | E::A(x @ ..) => {
+ | ^^^^^^ this is only allowed in slice patterns
+ |
+ = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of x, discard the tuple's remaining fields
+ |
+LL | E::A(..) => {
+ | ^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+// build-pass
+// ignore-tidy-filelength
+#![crate_type = "rlib"]
+
+fn banana(v: &str) -> u32 {
+ if v == "1" {
+ 1
+ } else if v == "2" {
+ 2
+ } else if v == "3" {
+ 3
+ } else if v == "4" {
+ 4
+ } else if v == "5" {
+ 5
+ } else if v == "6" {
+ 6
+ } else if v == "7" {
+ 7
+ } else if v == "8" {
+ 8
+ } else if v == "9" {
+ 9
+ } else if v == "10" {
+ 10
+ } else if v == "11" {
+ 11
+ } else if v == "12" {
+ 12
+ } else if v == "13" {
+ 13
+ } else if v == "14" {
+ 14
+ } else if v == "15" {
+ 15
+ } else if v == "16" {
+ 16
+ } else if v == "17" {
+ 17
+ } else if v == "18" {
+ 18
+ } else if v == "19" {
+ 19
+ } else if v == "20" {
+ 20
+ } else if v == "21" {
+ 21
+ } else if v == "22" {
+ 22
+ } else if v == "23" {
+ 23
+ } else if v == "24" {
+ 24
+ } else if v == "25" {
+ 25
+ } else if v == "26" {
+ 26
+ } else if v == "27" {
+ 27
+ } else if v == "28" {
+ 28
+ } else if v == "29" {
+ 29
+ } else if v == "30" {
+ 30
+ } else if v == "31" {
+ 31
+ } else if v == "32" {
+ 32
+ } else if v == "33" {
+ 33
+ } else if v == "34" {
+ 34
+ } else if v == "35" {
+ 35
+ } else if v == "36" {
+ 36
+ } else if v == "37" {
+ 37
+ } else if v == "38" {
+ 38
+ } else if v == "39" {
+ 39
+ } else if v == "40" {
+ 40
+ } else if v == "41" {
+ 41
+ } else if v == "42" {
+ 42
+ } else if v == "43" {
+ 43
+ } else if v == "44" {
+ 44
+ } else if v == "45" {
+ 45
+ } else if v == "46" {
+ 46
+ } else if v == "47" {
+ 47
+ } else if v == "48" {
+ 48
+ } else if v == "49" {
+ 49
+ } else if v == "50" {
+ 50
+ } else if v == "51" {
+ 51
+ } else if v == "52" {
+ 52
+ } else if v == "53" {
+ 53
+ } else if v == "54" {
+ 54
+ } else if v == "55" {
+ 55
+ } else if v == "56" {
+ 56
+ } else if v == "57" {
+ 57
+ } else if v == "58" {
+ 58
+ } else if v == "59" {
+ 59
+ } else if v == "60" {
+ 60
+ } else if v == "61" {
+ 61
+ } else if v == "62" {
+ 62
+ } else if v == "63" {
+ 63
+ } else if v == "64" {
+ 64
+ } else if v == "65" {
+ 65
+ } else if v == "66" {
+ 66
+ } else if v == "67" {
+ 67
+ } else if v == "68" {
+ 68
+ } else if v == "69" {
+ 69
+ } else if v == "70" {
+ 70
+ } else if v == "71" {
+ 71
+ } else if v == "72" {
+ 72
+ } else if v == "73" {
+ 73
+ } else if v == "74" {
+ 74
+ } else if v == "75" {
+ 75
+ } else if v == "76" {
+ 76
+ } else if v == "77" {
+ 77
+ } else if v == "78" {
+ 78
+ } else if v == "79" {
+ 79
+ } else if v == "80" {
+ 80
+ } else if v == "81" {
+ 81
+ } else if v == "82" {
+ 82
+ } else if v == "83" {
+ 83
+ } else if v == "84" {
+ 84
+ } else if v == "85" {
+ 85
+ } else if v == "86" {
+ 86
+ } else if v == "87" {
+ 87
+ } else if v == "88" {
+ 88
+ } else if v == "89" {
+ 89
+ } else if v == "90" {
+ 90
+ } else if v == "91" {
+ 91
+ } else if v == "92" {
+ 92
+ } else if v == "93" {
+ 93
+ } else if v == "94" {
+ 94
+ } else if v == "95" {
+ 95
+ } else if v == "96" {
+ 96
+ } else if v == "97" {
+ 97
+ } else if v == "98" {
+ 98
+ } else if v == "99" {
+ 99
+ } else if v == "100" {
+ 100
+ } else if v == "101" {
+ 101
+ } else if v == "102" {
+ 102
+ } else if v == "103" {
+ 103
+ } else if v == "104" {
+ 104
+ } else if v == "105" {
+ 105
+ } else if v == "106" {
+ 106
+ } else if v == "107" {
+ 107
+ } else if v == "108" {
+ 108
+ } else if v == "109" {
+ 109
+ } else if v == "110" {
+ 110
+ } else if v == "111" {
+ 111
+ } else if v == "112" {
+ 112
+ } else if v == "113" {
+ 113
+ } else if v == "114" {
+ 114
+ } else if v == "115" {
+ 115
+ } else if v == "116" {
+ 116
+ } else if v == "117" {
+ 117
+ } else if v == "118" {
+ 118
+ } else if v == "119" {
+ 119
+ } else if v == "120" {
+ 120
+ } else if v == "121" {
+ 121
+ } else if v == "122" {
+ 122
+ } else if v == "123" {
+ 123
+ } else if v == "124" {
+ 124
+ } else if v == "125" {
+ 125
+ } else if v == "126" {
+ 126
+ } else if v == "127" {
+ 127
+ } else if v == "128" {
+ 128
+ } else if v == "129" {
+ 129
+ } else if v == "130" {
+ 130
+ } else if v == "131" {
+ 131
+ } else if v == "132" {
+ 132
+ } else if v == "133" {
+ 133
+ } else if v == "134" {
+ 134
+ } else if v == "135" {
+ 135
+ } else if v == "136" {
+ 136
+ } else if v == "137" {
+ 137
+ } else if v == "138" {
+ 138
+ } else if v == "139" {
+ 139
+ } else if v == "140" {
+ 140
+ } else if v == "141" {
+ 141
+ } else if v == "142" {
+ 142
+ } else if v == "143" {
+ 143
+ } else if v == "144" {
+ 144
+ } else if v == "145" {
+ 145
+ } else if v == "146" {
+ 146
+ } else if v == "147" {
+ 147
+ } else if v == "148" {
+ 148
+ } else if v == "149" {
+ 149
+ } else if v == "150" {
+ 150
+ } else if v == "151" {
+ 151
+ } else if v == "152" {
+ 152
+ } else if v == "153" {
+ 153
+ } else if v == "154" {
+ 154
+ } else if v == "155" {
+ 155
+ } else if v == "156" {
+ 156
+ } else if v == "157" {
+ 157
+ } else if v == "158" {
+ 158
+ } else if v == "159" {
+ 159
+ } else if v == "160" {
+ 160
+ } else if v == "161" {
+ 161
+ } else if v == "162" {
+ 162
+ } else if v == "163" {
+ 163
+ } else if v == "164" {
+ 164
+ } else if v == "165" {
+ 165
+ } else if v == "166" {
+ 166
+ } else if v == "167" {
+ 167
+ } else if v == "168" {
+ 168
+ } else if v == "169" {
+ 169
+ } else if v == "170" {
+ 170
+ } else if v == "171" {
+ 171
+ } else if v == "172" {
+ 172
+ } else if v == "173" {
+ 173
+ } else if v == "174" {
+ 174
+ } else if v == "175" {
+ 175
+ } else if v == "176" {
+ 176
+ } else if v == "177" {
+ 177
+ } else if v == "178" {
+ 178
+ } else if v == "179" {
+ 179
+ } else if v == "180" {
+ 180
+ } else if v == "181" {
+ 181
+ } else if v == "182" {
+ 182
+ } else if v == "183" {
+ 183
+ } else if v == "184" {
+ 184
+ } else if v == "185" {
+ 185
+ } else if v == "186" {
+ 186
+ } else if v == "187" {
+ 187
+ } else if v == "188" {
+ 188
+ } else if v == "189" {
+ 189
+ } else if v == "190" {
+ 190
+ } else if v == "191" {
+ 191
+ } else if v == "192" {
+ 192
+ } else if v == "193" {
+ 193
+ } else if v == "194" {
+ 194
+ } else if v == "195" {
+ 195
+ } else if v == "196" {
+ 196
+ } else if v == "197" {
+ 197
+ } else if v == "198" {
+ 198
+ } else if v == "199" {
+ 199
+ } else if v == "200" {
+ 200
+ } else if v == "201" {
+ 201
+ } else if v == "202" {
+ 202
+ } else if v == "203" {
+ 203
+ } else if v == "204" {
+ 204
+ } else if v == "205" {
+ 205
+ } else if v == "206" {
+ 206
+ } else if v == "207" {
+ 207
+ } else if v == "208" {
+ 208
+ } else if v == "209" {
+ 209
+ } else if v == "210" {
+ 210
+ } else if v == "211" {
+ 211
+ } else if v == "212" {
+ 212
+ } else if v == "213" {
+ 213
+ } else if v == "214" {
+ 214
+ } else if v == "215" {
+ 215
+ } else if v == "216" {
+ 216
+ } else if v == "217" {
+ 217
+ } else if v == "218" {
+ 218
+ } else if v == "219" {
+ 219
+ } else if v == "220" {
+ 220
+ } else if v == "221" {
+ 221
+ } else if v == "222" {
+ 222
+ } else if v == "223" {
+ 223
+ } else if v == "224" {
+ 224
+ } else if v == "225" {
+ 225
+ } else if v == "226" {
+ 226
+ } else if v == "227" {
+ 227
+ } else if v == "228" {
+ 228
+ } else if v == "229" {
+ 229
+ } else if v == "230" {
+ 230
+ } else if v == "231" {
+ 231
+ } else if v == "232" {
+ 232
+ } else if v == "233" {
+ 233
+ } else if v == "234" {
+ 234
+ } else if v == "235" {
+ 235
+ } else if v == "236" {
+ 236
+ } else if v == "237" {
+ 237
+ } else if v == "238" {
+ 238
+ } else if v == "239" {
+ 239
+ } else if v == "240" {
+ 240
+ } else if v == "241" {
+ 241
+ } else if v == "242" {
+ 242
+ } else if v == "243" {
+ 243
+ } else if v == "244" {
+ 244
+ } else if v == "245" {
+ 245
+ } else if v == "246" {
+ 246
+ } else if v == "247" {
+ 247
+ } else if v == "248" {
+ 248
+ } else if v == "249" {
+ 249
+ } else if v == "250" {
+ 250
+ } else if v == "251" {
+ 251
+ } else if v == "252" {
+ 252
+ } else if v == "253" {
+ 253
+ } else if v == "254" {
+ 254
+ } else if v == "255" {
+ 255
+ } else if v == "256" {
+ 256
+ } else if v == "257" {
+ 257
+ } else if v == "258" {
+ 258
+ } else if v == "259" {
+ 259
+ } else if v == "260" {
+ 260
+ } else if v == "261" {
+ 261
+ } else if v == "262" {
+ 262
+ } else if v == "263" {
+ 263
+ } else if v == "264" {
+ 264
+ } else if v == "265" {
+ 265
+ } else if v == "266" {
+ 266
+ } else if v == "267" {
+ 267
+ } else if v == "268" {
+ 268
+ } else if v == "269" {
+ 269
+ } else if v == "270" {
+ 270
+ } else if v == "271" {
+ 271
+ } else if v == "272" {
+ 272
+ } else if v == "273" {
+ 273
+ } else if v == "274" {
+ 274
+ } else if v == "275" {
+ 275
+ } else if v == "276" {
+ 276
+ } else if v == "277" {
+ 277
+ } else if v == "278" {
+ 278
+ } else if v == "279" {
+ 279
+ } else if v == "280" {
+ 280
+ } else if v == "281" {
+ 281
+ } else if v == "282" {
+ 282
+ } else if v == "283" {
+ 283
+ } else if v == "284" {
+ 284
+ } else if v == "285" {
+ 285
+ } else if v == "286" {
+ 286
+ } else if v == "287" {
+ 287
+ } else if v == "288" {
+ 288
+ } else if v == "289" {
+ 289
+ } else if v == "290" {
+ 290
+ } else if v == "291" {
+ 291
+ } else if v == "292" {
+ 292
+ } else if v == "293" {
+ 293
+ } else if v == "294" {
+ 294
+ } else if v == "295" {
+ 295
+ } else if v == "296" {
+ 296
+ } else if v == "297" {
+ 297
+ } else if v == "298" {
+ 298
+ } else if v == "299" {
+ 299
+ } else if v == "300" {
+ 300
+ } else if v == "301" {
+ 301
+ } else if v == "302" {
+ 302
+ } else if v == "303" {
+ 303
+ } else if v == "304" {
+ 304
+ } else if v == "305" {
+ 305
+ } else if v == "306" {
+ 306
+ } else if v == "307" {
+ 307
+ } else if v == "308" {
+ 308
+ } else if v == "309" {
+ 309
+ } else if v == "310" {
+ 310
+ } else if v == "311" {
+ 311
+ } else if v == "312" {
+ 312
+ } else if v == "313" {
+ 313
+ } else if v == "314" {
+ 314
+ } else if v == "315" {
+ 315
+ } else if v == "316" {
+ 316
+ } else if v == "317" {
+ 317
+ } else if v == "318" {
+ 318
+ } else if v == "319" {
+ 319
+ } else if v == "320" {
+ 320
+ } else if v == "321" {
+ 321
+ } else if v == "322" {
+ 322
+ } else if v == "323" {
+ 323
+ } else if v == "324" {
+ 324
+ } else if v == "325" {
+ 325
+ } else if v == "326" {
+ 326
+ } else if v == "327" {
+ 327
+ } else if v == "328" {
+ 328
+ } else if v == "329" {
+ 329
+ } else if v == "330" {
+ 330
+ } else if v == "331" {
+ 331
+ } else if v == "332" {
+ 332
+ } else if v == "333" {
+ 333
+ } else if v == "334" {
+ 334
+ } else if v == "335" {
+ 335
+ } else if v == "336" {
+ 336
+ } else if v == "337" {
+ 337
+ } else if v == "338" {
+ 338
+ } else if v == "339" {
+ 339
+ } else if v == "340" {
+ 340
+ } else if v == "341" {
+ 341
+ } else if v == "342" {
+ 342
+ } else if v == "343" {
+ 343
+ } else if v == "344" {
+ 344
+ } else if v == "345" {
+ 345
+ } else if v == "346" {
+ 346
+ } else if v == "347" {
+ 347
+ } else if v == "348" {
+ 348
+ } else if v == "349" {
+ 349
+ } else if v == "350" {
+ 350
+ } else if v == "351" {
+ 351
+ } else if v == "352" {
+ 352
+ } else if v == "353" {
+ 353
+ } else if v == "354" {
+ 354
+ } else if v == "355" {
+ 355
+ } else if v == "356" {
+ 356
+ } else if v == "357" {
+ 357
+ } else if v == "358" {
+ 358
+ } else if v == "359" {
+ 359
+ } else if v == "360" {
+ 360
+ } else if v == "361" {
+ 361
+ } else if v == "362" {
+ 362
+ } else if v == "363" {
+ 363
+ } else if v == "364" {
+ 364
+ } else if v == "365" {
+ 365
+ } else if v == "366" {
+ 366
+ } else if v == "367" {
+ 367
+ } else if v == "368" {
+ 368
+ } else if v == "369" {
+ 369
+ } else if v == "370" {
+ 370
+ } else if v == "371" {
+ 371
+ } else if v == "372" {
+ 372
+ } else if v == "373" {
+ 373
+ } else if v == "374" {
+ 374
+ } else if v == "375" {
+ 375
+ } else if v == "376" {
+ 376
+ } else if v == "377" {
+ 377
+ } else if v == "378" {
+ 378
+ } else if v == "379" {
+ 379
+ } else if v == "380" {
+ 380
+ } else if v == "381" {
+ 381
+ } else if v == "382" {
+ 382
+ } else if v == "383" {
+ 383
+ } else if v == "384" {
+ 384
+ } else if v == "385" {
+ 385
+ } else if v == "386" {
+ 386
+ } else if v == "387" {
+ 387
+ } else if v == "388" {
+ 388
+ } else if v == "389" {
+ 389
+ } else if v == "390" {
+ 390
+ } else if v == "391" {
+ 391
+ } else if v == "392" {
+ 392
+ } else if v == "393" {
+ 393
+ } else if v == "394" {
+ 394
+ } else if v == "395" {
+ 395
+ } else if v == "396" {
+ 396
+ } else if v == "397" {
+ 397
+ } else if v == "398" {
+ 398
+ } else if v == "399" {
+ 399
+ } else if v == "400" {
+ 400
+ } else if v == "401" {
+ 401
+ } else if v == "402" {
+ 402
+ } else if v == "403" {
+ 403
+ } else if v == "404" {
+ 404
+ } else if v == "405" {
+ 405
+ } else if v == "406" {
+ 406
+ } else if v == "407" {
+ 407
+ } else if v == "408" {
+ 408
+ } else if v == "409" {
+ 409
+ } else if v == "410" {
+ 410
+ } else if v == "411" {
+ 411
+ } else if v == "412" {
+ 412
+ } else if v == "413" {
+ 413
+ } else if v == "414" {
+ 414
+ } else if v == "415" {
+ 415
+ } else if v == "416" {
+ 416
+ } else if v == "417" {
+ 417
+ } else if v == "418" {
+ 418
+ } else if v == "419" {
+ 419
+ } else if v == "420" {
+ 420
+ } else if v == "421" {
+ 421
+ } else if v == "422" {
+ 422
+ } else if v == "423" {
+ 423
+ } else if v == "424" {
+ 424
+ } else if v == "425" {
+ 425
+ } else if v == "426" {
+ 426
+ } else if v == "427" {
+ 427
+ } else if v == "428" {
+ 428
+ } else if v == "429" {
+ 429
+ } else if v == "430" {
+ 430
+ } else if v == "431" {
+ 431
+ } else if v == "432" {
+ 432
+ } else if v == "433" {
+ 433
+ } else if v == "434" {
+ 434
+ } else if v == "435" {
+ 435
+ } else if v == "436" {
+ 436
+ } else if v == "437" {
+ 437
+ } else if v == "438" {
+ 438
+ } else if v == "439" {
+ 439
+ } else if v == "440" {
+ 440
+ } else if v == "441" {
+ 441
+ } else if v == "442" {
+ 442
+ } else if v == "443" {
+ 443
+ } else if v == "444" {
+ 444
+ } else if v == "445" {
+ 445
+ } else if v == "446" {
+ 446
+ } else if v == "447" {
+ 447
+ } else if v == "448" {
+ 448
+ } else if v == "449" {
+ 449
+ } else if v == "450" {
+ 450
+ } else if v == "451" {
+ 451
+ } else if v == "452" {
+ 452
+ } else if v == "453" {
+ 453
+ } else if v == "454" {
+ 454
+ } else if v == "455" {
+ 455
+ } else if v == "456" {
+ 456
+ } else if v == "457" {
+ 457
+ } else if v == "458" {
+ 458
+ } else if v == "459" {
+ 459
+ } else if v == "460" {
+ 460
+ } else if v == "461" {
+ 461
+ } else if v == "462" {
+ 462
+ } else if v == "463" {
+ 463
+ } else if v == "464" {
+ 464
+ } else if v == "465" {
+ 465
+ } else if v == "466" {
+ 466
+ } else if v == "467" {
+ 467
+ } else if v == "468" {
+ 468
+ } else if v == "469" {
+ 469
+ } else if v == "470" {
+ 470
+ } else if v == "471" {
+ 471
+ } else if v == "472" {
+ 472
+ } else if v == "473" {
+ 473
+ } else if v == "474" {
+ 474
+ } else if v == "475" {
+ 475
+ } else if v == "476" {
+ 476
+ } else if v == "477" {
+ 477
+ } else if v == "478" {
+ 478
+ } else if v == "479" {
+ 479
+ } else if v == "480" {
+ 480
+ } else if v == "481" {
+ 481
+ } else if v == "482" {
+ 482
+ } else if v == "483" {
+ 483
+ } else if v == "484" {
+ 484
+ } else if v == "485" {
+ 485
+ } else if v == "486" {
+ 486
+ } else if v == "487" {
+ 487
+ } else if v == "488" {
+ 488
+ } else if v == "489" {
+ 489
+ } else if v == "490" {
+ 490
+ } else if v == "491" {
+ 491
+ } else if v == "492" {
+ 492
+ } else if v == "493" {
+ 493
+ } else if v == "494" {
+ 494
+ } else if v == "495" {
+ 495
+ } else if v == "496" {
+ 496
+ } else if v == "497" {
+ 497
+ } else if v == "498" {
+ 498
+ } else if v == "499" {
+ 499
+ } else if v == "500" {
+ 500
+ } else if v == "501" {
+ 501
+ } else if v == "502" {
+ 502
+ } else if v == "503" {
+ 503
+ } else if v == "504" {
+ 504
+ } else if v == "505" {
+ 505
+ } else if v == "506" {
+ 506
+ } else if v == "507" {
+ 507
+ } else if v == "508" {
+ 508
+ } else if v == "509" {
+ 509
+ } else if v == "510" {
+ 510
+ } else if v == "511" {
+ 511
+ } else if v == "512" {
+ 512
+ } else if v == "513" {
+ 513
+ } else if v == "514" {
+ 514
+ } else if v == "515" {
+ 515
+ } else if v == "516" {
+ 516
+ } else if v == "517" {
+ 517
+ } else if v == "518" {
+ 518
+ } else if v == "519" {
+ 519
+ } else if v == "520" {
+ 520
+ } else if v == "521" {
+ 521
+ } else if v == "522" {
+ 522
+ } else if v == "523" {
+ 523
+ } else if v == "524" {
+ 524
+ } else if v == "525" {
+ 525
+ } else if v == "526" {
+ 526
+ } else if v == "527" {
+ 527
+ } else if v == "528" {
+ 528
+ } else if v == "529" {
+ 529
+ } else if v == "530" {
+ 530
+ } else if v == "531" {
+ 531
+ } else if v == "532" {
+ 532
+ } else if v == "533" {
+ 533
+ } else if v == "534" {
+ 534
+ } else if v == "535" {
+ 535
+ } else if v == "536" {
+ 536
+ } else if v == "537" {
+ 537
+ } else if v == "538" {
+ 538
+ } else if v == "539" {
+ 539
+ } else if v == "540" {
+ 540
+ } else if v == "541" {
+ 541
+ } else if v == "542" {
+ 542
+ } else if v == "543" {
+ 543
+ } else if v == "544" {
+ 544
+ } else if v == "545" {
+ 545
+ } else if v == "546" {
+ 546
+ } else if v == "547" {
+ 547
+ } else if v == "548" {
+ 548
+ } else if v == "549" {
+ 549
+ } else if v == "550" {
+ 550
+ } else if v == "551" {
+ 551
+ } else if v == "552" {
+ 552
+ } else if v == "553" {
+ 553
+ } else if v == "554" {
+ 554
+ } else if v == "555" {
+ 555
+ } else if v == "556" {
+ 556
+ } else if v == "557" {
+ 557
+ } else if v == "558" {
+ 558
+ } else if v == "559" {
+ 559
+ } else if v == "560" {
+ 560
+ } else if v == "561" {
+ 561
+ } else if v == "562" {
+ 562
+ } else if v == "563" {
+ 563
+ } else if v == "564" {
+ 564
+ } else if v == "565" {
+ 565
+ } else if v == "566" {
+ 566
+ } else if v == "567" {
+ 567
+ } else if v == "568" {
+ 568
+ } else if v == "569" {
+ 569
+ } else if v == "570" {
+ 570
+ } else if v == "571" {
+ 571
+ } else if v == "572" {
+ 572
+ } else if v == "573" {
+ 573
+ } else if v == "574" {
+ 574
+ } else if v == "575" {
+ 575
+ } else if v == "576" {
+ 576
+ } else if v == "577" {
+ 577
+ } else if v == "578" {
+ 578
+ } else if v == "579" {
+ 579
+ } else if v == "580" {
+ 580
+ } else if v == "581" {
+ 581
+ } else if v == "582" {
+ 582
+ } else if v == "583" {
+ 583
+ } else if v == "584" {
+ 584
+ } else if v == "585" {
+ 585
+ } else if v == "586" {
+ 586
+ } else if v == "587" {
+ 587
+ } else if v == "588" {
+ 588
+ } else if v == "589" {
+ 589
+ } else if v == "590" {
+ 590
+ } else if v == "591" {
+ 591
+ } else if v == "592" {
+ 592
+ } else if v == "593" {
+ 593
+ } else if v == "594" {
+ 594
+ } else if v == "595" {
+ 595
+ } else if v == "596" {
+ 596
+ } else if v == "597" {
+ 597
+ } else if v == "598" {
+ 598
+ } else if v == "599" {
+ 599
+ } else if v == "600" {
+ 600
+ } else if v == "601" {
+ 601
+ } else if v == "602" {
+ 602
+ } else if v == "603" {
+ 603
+ } else if v == "604" {
+ 604
+ } else if v == "605" {
+ 605
+ } else if v == "606" {
+ 606
+ } else if v == "607" {
+ 607
+ } else if v == "608" {
+ 608
+ } else if v == "609" {
+ 609
+ } else if v == "610" {
+ 610
+ } else if v == "611" {
+ 611
+ } else if v == "612" {
+ 612
+ } else if v == "613" {
+ 613
+ } else if v == "614" {
+ 614
+ } else if v == "615" {
+ 615
+ } else if v == "616" {
+ 616
+ } else if v == "617" {
+ 617
+ } else if v == "618" {
+ 618
+ } else if v == "619" {
+ 619
+ } else if v == "620" {
+ 620
+ } else if v == "621" {
+ 621
+ } else if v == "622" {
+ 622
+ } else if v == "623" {
+ 623
+ } else if v == "624" {
+ 624
+ } else if v == "625" {
+ 625
+ } else if v == "626" {
+ 626
+ } else if v == "627" {
+ 627
+ } else if v == "628" {
+ 628
+ } else if v == "629" {
+ 629
+ } else if v == "630" {
+ 630
+ } else if v == "631" {
+ 631
+ } else if v == "632" {
+ 632
+ } else if v == "633" {
+ 633
+ } else if v == "634" {
+ 634
+ } else if v == "635" {
+ 635
+ } else if v == "636" {
+ 636
+ } else if v == "637" {
+ 637
+ } else if v == "638" {
+ 638
+ } else if v == "639" {
+ 639
+ } else if v == "640" {
+ 640
+ } else if v == "641" {
+ 641
+ } else if v == "642" {
+ 642
+ } else if v == "643" {
+ 643
+ } else if v == "644" {
+ 644
+ } else if v == "645" {
+ 645
+ } else if v == "646" {
+ 646
+ } else if v == "647" {
+ 647
+ } else if v == "648" {
+ 648
+ } else if v == "649" {
+ 649
+ } else if v == "650" {
+ 650
+ } else if v == "651" {
+ 651
+ } else if v == "652" {
+ 652
+ } else if v == "653" {
+ 653
+ } else if v == "654" {
+ 654
+ } else if v == "655" {
+ 655
+ } else if v == "656" {
+ 656
+ } else if v == "657" {
+ 657
+ } else if v == "658" {
+ 658
+ } else if v == "659" {
+ 659
+ } else if v == "660" {
+ 660
+ } else if v == "661" {
+ 661
+ } else if v == "662" {
+ 662
+ } else if v == "663" {
+ 663
+ } else if v == "664" {
+ 664
+ } else if v == "665" {
+ 665
+ } else if v == "666" {
+ 666
+ } else if v == "667" {
+ 667
+ } else if v == "668" {
+ 668
+ } else if v == "669" {
+ 669
+ } else if v == "670" {
+ 670
+ } else if v == "671" {
+ 671
+ } else if v == "672" {
+ 672
+ } else if v == "673" {
+ 673
+ } else if v == "674" {
+ 674
+ } else if v == "675" {
+ 675
+ } else if v == "676" {
+ 676
+ } else if v == "677" {
+ 677
+ } else if v == "678" {
+ 678
+ } else if v == "679" {
+ 679
+ } else if v == "680" {
+ 680
+ } else if v == "681" {
+ 681
+ } else if v == "682" {
+ 682
+ } else if v == "683" {
+ 683
+ } else if v == "684" {
+ 684
+ } else if v == "685" {
+ 685
+ } else if v == "686" {
+ 686
+ } else if v == "687" {
+ 687
+ } else if v == "688" {
+ 688
+ } else if v == "689" {
+ 689
+ } else if v == "690" {
+ 690
+ } else if v == "691" {
+ 691
+ } else if v == "692" {
+ 692
+ } else if v == "693" {
+ 693
+ } else if v == "694" {
+ 694
+ } else if v == "695" {
+ 695
+ } else if v == "696" {
+ 696
+ } else if v == "697" {
+ 697
+ } else if v == "698" {
+ 698
+ } else if v == "699" {
+ 699
+ } else if v == "700" {
+ 700
+ } else if v == "701" {
+ 701
+ } else if v == "702" {
+ 702
+ } else if v == "703" {
+ 703
+ } else if v == "704" {
+ 704
+ } else if v == "705" {
+ 705
+ } else if v == "706" {
+ 706
+ } else if v == "707" {
+ 707
+ } else if v == "708" {
+ 708
+ } else if v == "709" {
+ 709
+ } else if v == "710" {
+ 710
+ } else if v == "711" {
+ 711
+ } else if v == "712" {
+ 712
+ } else if v == "713" {
+ 713
+ } else if v == "714" {
+ 714
+ } else if v == "715" {
+ 715
+ } else if v == "716" {
+ 716
+ } else if v == "717" {
+ 717
+ } else if v == "718" {
+ 718
+ } else if v == "719" {
+ 719
+ } else if v == "720" {
+ 720
+ } else if v == "721" {
+ 721
+ } else if v == "722" {
+ 722
+ } else if v == "723" {
+ 723
+ } else if v == "724" {
+ 724
+ } else if v == "725" {
+ 725
+ } else if v == "726" {
+ 726
+ } else if v == "727" {
+ 727
+ } else if v == "728" {
+ 728
+ } else if v == "729" {
+ 729
+ } else if v == "730" {
+ 730
+ } else if v == "731" {
+ 731
+ } else if v == "732" {
+ 732
+ } else if v == "733" {
+ 733
+ } else if v == "734" {
+ 734
+ } else if v == "735" {
+ 735
+ } else if v == "736" {
+ 736
+ } else if v == "737" {
+ 737
+ } else if v == "738" {
+ 738
+ } else if v == "739" {
+ 739
+ } else if v == "740" {
+ 740
+ } else if v == "741" {
+ 741
+ } else if v == "742" {
+ 742
+ } else if v == "743" {
+ 743
+ } else if v == "744" {
+ 744
+ } else if v == "745" {
+ 745
+ } else if v == "746" {
+ 746
+ } else if v == "747" {
+ 747
+ } else if v == "748" {
+ 748
+ } else if v == "749" {
+ 749
+ } else if v == "750" {
+ 750
+ } else if v == "751" {
+ 751
+ } else if v == "752" {
+ 752
+ } else if v == "753" {
+ 753
+ } else if v == "754" {
+ 754
+ } else if v == "755" {
+ 755
+ } else if v == "756" {
+ 756
+ } else if v == "757" {
+ 757
+ } else if v == "758" {
+ 758
+ } else if v == "759" {
+ 759
+ } else if v == "760" {
+ 760
+ } else if v == "761" {
+ 761
+ } else if v == "762" {
+ 762
+ } else if v == "763" {
+ 763
+ } else if v == "764" {
+ 764
+ } else if v == "765" {
+ 765
+ } else if v == "766" {
+ 766
+ } else if v == "767" {
+ 767
+ } else if v == "768" {
+ 768
+ } else if v == "769" {
+ 769
+ } else if v == "770" {
+ 770
+ } else if v == "771" {
+ 771
+ } else if v == "772" {
+ 772
+ } else if v == "773" {
+ 773
+ } else if v == "774" {
+ 774
+ } else if v == "775" {
+ 775
+ } else if v == "776" {
+ 776
+ } else if v == "777" {
+ 777
+ } else if v == "778" {
+ 778
+ } else if v == "779" {
+ 779
+ } else if v == "780" {
+ 780
+ } else if v == "781" {
+ 781
+ } else if v == "782" {
+ 782
+ } else if v == "783" {
+ 783
+ } else if v == "784" {
+ 784
+ } else if v == "785" {
+ 785
+ } else if v == "786" {
+ 786
+ } else if v == "787" {
+ 787
+ } else if v == "788" {
+ 788
+ } else if v == "789" {
+ 789
+ } else if v == "790" {
+ 790
+ } else if v == "791" {
+ 791
+ } else if v == "792" {
+ 792
+ } else if v == "793" {
+ 793
+ } else if v == "794" {
+ 794
+ } else if v == "795" {
+ 795
+ } else if v == "796" {
+ 796
+ } else if v == "797" {
+ 797
+ } else if v == "798" {
+ 798
+ } else if v == "799" {
+ 799
+ } else if v == "800" {
+ 800
+ } else if v == "801" {
+ 801
+ } else if v == "802" {
+ 802
+ } else if v == "803" {
+ 803
+ } else if v == "804" {
+ 804
+ } else if v == "805" {
+ 805
+ } else if v == "806" {
+ 806
+ } else if v == "807" {
+ 807
+ } else if v == "808" {
+ 808
+ } else if v == "809" {
+ 809
+ } else if v == "810" {
+ 810
+ } else if v == "811" {
+ 811
+ } else if v == "812" {
+ 812
+ } else if v == "813" {
+ 813
+ } else if v == "814" {
+ 814
+ } else if v == "815" {
+ 815
+ } else if v == "816" {
+ 816
+ } else if v == "817" {
+ 817
+ } else if v == "818" {
+ 818
+ } else if v == "819" {
+ 819
+ } else if v == "820" {
+ 820
+ } else if v == "821" {
+ 821
+ } else if v == "822" {
+ 822
+ } else if v == "823" {
+ 823
+ } else if v == "824" {
+ 824
+ } else if v == "825" {
+ 825
+ } else if v == "826" {
+ 826
+ } else if v == "827" {
+ 827
+ } else if v == "828" {
+ 828
+ } else if v == "829" {
+ 829
+ } else if v == "830" {
+ 830
+ } else if v == "831" {
+ 831
+ } else if v == "832" {
+ 832
+ } else if v == "833" {
+ 833
+ } else if v == "834" {
+ 834
+ } else if v == "835" {
+ 835
+ } else if v == "836" {
+ 836
+ } else if v == "837" {
+ 837
+ } else if v == "838" {
+ 838
+ } else if v == "839" {
+ 839
+ } else if v == "840" {
+ 840
+ } else if v == "841" {
+ 841
+ } else if v == "842" {
+ 842
+ } else if v == "843" {
+ 843
+ } else if v == "844" {
+ 844
+ } else if v == "845" {
+ 845
+ } else if v == "846" {
+ 846
+ } else if v == "847" {
+ 847
+ } else if v == "848" {
+ 848
+ } else if v == "849" {
+ 849
+ } else if v == "850" {
+ 850
+ } else if v == "851" {
+ 851
+ } else if v == "852" {
+ 852
+ } else if v == "853" {
+ 853
+ } else if v == "854" {
+ 854
+ } else if v == "855" {
+ 855
+ } else if v == "856" {
+ 856
+ } else if v == "857" {
+ 857
+ } else if v == "858" {
+ 858
+ } else if v == "859" {
+ 859
+ } else if v == "860" {
+ 860
+ } else if v == "861" {
+ 861
+ } else if v == "862" {
+ 862
+ } else if v == "863" {
+ 863
+ } else if v == "864" {
+ 864
+ } else if v == "865" {
+ 865
+ } else if v == "866" {
+ 866
+ } else if v == "867" {
+ 867
+ } else if v == "868" {
+ 868
+ } else if v == "869" {
+ 869
+ } else if v == "870" {
+ 870
+ } else if v == "871" {
+ 871
+ } else if v == "872" {
+ 872
+ } else if v == "873" {
+ 873
+ } else if v == "874" {
+ 874
+ } else if v == "875" {
+ 875
+ } else if v == "876" {
+ 876
+ } else if v == "877" {
+ 877
+ } else if v == "878" {
+ 878
+ } else if v == "879" {
+ 879
+ } else if v == "880" {
+ 880
+ } else if v == "881" {
+ 881
+ } else if v == "882" {
+ 882
+ } else if v == "883" {
+ 883
+ } else if v == "884" {
+ 884
+ } else if v == "885" {
+ 885
+ } else if v == "886" {
+ 886
+ } else if v == "887" {
+ 887
+ } else if v == "888" {
+ 888
+ } else if v == "889" {
+ 889
+ } else if v == "890" {
+ 890
+ } else if v == "891" {
+ 891
+ } else if v == "892" {
+ 892
+ } else if v == "893" {
+ 893
+ } else if v == "894" {
+ 894
+ } else if v == "895" {
+ 895
+ } else if v == "896" {
+ 896
+ } else if v == "897" {
+ 897
+ } else if v == "898" {
+ 898
+ } else if v == "899" {
+ 899
+ } else if v == "900" {
+ 900
+ } else if v == "901" {
+ 901
+ } else if v == "902" {
+ 902
+ } else if v == "903" {
+ 903
+ } else if v == "904" {
+ 904
+ } else if v == "905" {
+ 905
+ } else if v == "906" {
+ 906
+ } else if v == "907" {
+ 907
+ } else if v == "908" {
+ 908
+ } else if v == "909" {
+ 909
+ } else if v == "910" {
+ 910
+ } else if v == "911" {
+ 911
+ } else if v == "912" {
+ 912
+ } else if v == "913" {
+ 913
+ } else if v == "914" {
+ 914
+ } else if v == "915" {
+ 915
+ } else if v == "916" {
+ 916
+ } else if v == "917" {
+ 917
+ } else if v == "918" {
+ 918
+ } else if v == "919" {
+ 919
+ } else if v == "920" {
+ 920
+ } else if v == "921" {
+ 921
+ } else if v == "922" {
+ 922
+ } else if v == "923" {
+ 923
+ } else if v == "924" {
+ 924
+ } else if v == "925" {
+ 925
+ } else if v == "926" {
+ 926
+ } else if v == "927" {
+ 927
+ } else if v == "928" {
+ 928
+ } else if v == "929" {
+ 929
+ } else if v == "930" {
+ 930
+ } else if v == "931" {
+ 931
+ } else if v == "932" {
+ 932
+ } else if v == "933" {
+ 933
+ } else if v == "934" {
+ 934
+ } else if v == "935" {
+ 935
+ } else if v == "936" {
+ 936
+ } else if v == "937" {
+ 937
+ } else if v == "938" {
+ 938
+ } else if v == "939" {
+ 939
+ } else if v == "940" {
+ 940
+ } else if v == "941" {
+ 941
+ } else if v == "942" {
+ 942
+ } else if v == "943" {
+ 943
+ } else if v == "944" {
+ 944
+ } else if v == "945" {
+ 945
+ } else if v == "946" {
+ 946
+ } else if v == "947" {
+ 947
+ } else if v == "948" {
+ 948
+ } else if v == "949" {
+ 949
+ } else if v == "950" {
+ 950
+ } else if v == "951" {
+ 951
+ } else if v == "952" {
+ 952
+ } else if v == "953" {
+ 953
+ } else if v == "954" {
+ 954
+ } else if v == "955" {
+ 955
+ } else if v == "956" {
+ 956
+ } else if v == "957" {
+ 957
+ } else if v == "958" {
+ 958
+ } else if v == "959" {
+ 959
+ } else if v == "960" {
+ 960
+ } else if v == "961" {
+ 961
+ } else if v == "962" {
+ 962
+ } else if v == "963" {
+ 963
+ } else if v == "964" {
+ 964
+ } else if v == "965" {
+ 965
+ } else if v == "966" {
+ 966
+ } else if v == "967" {
+ 967
+ } else if v == "968" {
+ 968
+ } else if v == "969" {
+ 969
+ } else if v == "970" {
+ 970
+ } else if v == "971" {
+ 971
+ } else if v == "972" {
+ 972
+ } else if v == "973" {
+ 973
+ } else if v == "974" {
+ 974
+ } else if v == "975" {
+ 975
+ } else if v == "976" {
+ 976
+ } else if v == "977" {
+ 977
+ } else if v == "978" {
+ 978
+ } else if v == "979" {
+ 979
+ } else if v == "980" {
+ 980
+ } else if v == "981" {
+ 981
+ } else if v == "982" {
+ 982
+ } else if v == "983" {
+ 983
+ } else if v == "984" {
+ 984
+ } else if v == "985" {
+ 985
+ } else if v == "986" {
+ 986
+ } else if v == "987" {
+ 987
+ } else if v == "988" {
+ 988
+ } else if v == "989" {
+ 989
+ } else if v == "990" {
+ 990
+ } else if v == "991" {
+ 991
+ } else if v == "992" {
+ 992
+ } else if v == "993" {
+ 993
+ } else if v == "994" {
+ 994
+ } else if v == "995" {
+ 995
+ } else if v == "996" {
+ 996
+ } else if v == "997" {
+ 997
+ } else if v == "998" {
+ 998
+ } else if v == "999" {
+ 999
+ } else if v == "1000" {
+ 1000
+ } else if v == "1001" {
+ 1001
+ } else if v == "1002" {
+ 1002
+ } else if v == "1003" {
+ 1003
+ } else if v == "1004" {
+ 1004
+ } else if v == "1005" {
+ 1005
+ } else if v == "1006" {
+ 1006
+ } else if v == "1007" {
+ 1007
+ } else if v == "1008" {
+ 1008
+ } else if v == "1009" {
+ 1009
+ } else if v == "1010" {
+ 1010
+ } else if v == "1011" {
+ 1011
+ } else if v == "1012" {
+ 1012
+ } else if v == "1013" {
+ 1013
+ } else if v == "1014" {
+ 1014
+ } else if v == "1015" {
+ 1015
+ } else if v == "1016" {
+ 1016
+ } else if v == "1017" {
+ 1017
+ } else if v == "1018" {
+ 1018
+ } else if v == "1019" {
+ 1019
+ } else if v == "1020" {
+ 1020
+ } else if v == "1021" {
+ 1021
+ } else if v == "1022" {
+ 1022
+ } else if v == "1023" {
+ 1023
+ } else if v == "1024" {
+ 1024
+ } else if v == "1025" {
+ 1025
+ } else if v == "1026" {
+ 1026
+ } else if v == "1027" {
+ 1027
+ } else if v == "1028" {
+ 1028
+ } else if v == "1029" {
+ 1029
+ } else if v == "1030" {
+ 1030
+ } else if v == "1031" {
+ 1031
+ } else if v == "1032" {
+ 1032
+ } else if v == "1033" {
+ 1033
+ } else if v == "1034" {
+ 1034
+ } else if v == "1035" {
+ 1035
+ } else if v == "1036" {
+ 1036
+ } else if v == "1037" {
+ 1037
+ } else if v == "1038" {
+ 1038
+ } else if v == "1039" {
+ 1039
+ } else if v == "1040" {
+ 1040
+ } else if v == "1041" {
+ 1041
+ } else if v == "1042" {
+ 1042
+ } else if v == "1043" {
+ 1043
+ } else if v == "1044" {
+ 1044
+ } else if v == "1045" {
+ 1045
+ } else if v == "1046" {
+ 1046
+ } else if v == "1047" {
+ 1047
+ } else if v == "1048" {
+ 1048
+ } else if v == "1049" {
+ 1049
+ } else if v == "1050" {
+ 1050
+ } else if v == "1051" {
+ 1051
+ } else if v == "1052" {
+ 1052
+ } else if v == "1053" {
+ 1053
+ } else if v == "1054" {
+ 1054
+ } else if v == "1055" {
+ 1055
+ } else if v == "1056" {
+ 1056
+ } else if v == "1057" {
+ 1057
+ } else if v == "1058" {
+ 1058
+ } else if v == "1059" {
+ 1059
+ } else if v == "1060" {
+ 1060
+ } else if v == "1061" {
+ 1061
+ } else if v == "1062" {
+ 1062
+ } else if v == "1063" {
+ 1063
+ } else if v == "1064" {
+ 1064
+ } else if v == "1065" {
+ 1065
+ } else if v == "1066" {
+ 1066
+ } else if v == "1067" {
+ 1067
+ } else if v == "1068" {
+ 1068
+ } else if v == "1069" {
+ 1069
+ } else if v == "1070" {
+ 1070
+ } else if v == "1071" {
+ 1071
+ } else if v == "1072" {
+ 1072
+ } else if v == "1073" {
+ 1073
+ } else if v == "1074" {
+ 1074
+ } else if v == "1075" {
+ 1075
+ } else if v == "1076" {
+ 1076
+ } else if v == "1077" {
+ 1077
+ } else if v == "1078" {
+ 1078
+ } else if v == "1079" {
+ 1079
+ } else if v == "1080" {
+ 1080
+ } else if v == "1081" {
+ 1081
+ } else if v == "1082" {
+ 1082
+ } else if v == "1083" {
+ 1083
+ } else if v == "1084" {
+ 1084
+ } else if v == "1085" {
+ 1085
+ } else if v == "1086" {
+ 1086
+ } else if v == "1087" {
+ 1087
+ } else if v == "1088" {
+ 1088
+ } else if v == "1089" {
+ 1089
+ } else if v == "1090" {
+ 1090
+ } else if v == "1091" {
+ 1091
+ } else if v == "1092" {
+ 1092
+ } else if v == "1093" {
+ 1093
+ } else if v == "1094" {
+ 1094
+ } else if v == "1095" {
+ 1095
+ } else if v == "1096" {
+ 1096
+ } else if v == "1097" {
+ 1097
+ } else if v == "1098" {
+ 1098
+ } else if v == "1099" {
+ 1099
+ } else if v == "1100" {
+ 1100
+ } else if v == "1101" {
+ 1101
+ } else if v == "1102" {
+ 1102
+ } else if v == "1103" {
+ 1103
+ } else if v == "1104" {
+ 1104
+ } else if v == "1105" {
+ 1105
+ } else if v == "1106" {
+ 1106
+ } else if v == "1107" {
+ 1107
+ } else if v == "1108" {
+ 1108
+ } else if v == "1109" {
+ 1109
+ } else if v == "1110" {
+ 1110
+ } else if v == "1111" {
+ 1111
+ } else if v == "1112" {
+ 1112
+ } else if v == "1113" {
+ 1113
+ } else if v == "1114" {
+ 1114
+ } else if v == "1115" {
+ 1115
+ } else if v == "1116" {
+ 1116
+ } else if v == "1117" {
+ 1117
+ } else if v == "1118" {
+ 1118
+ } else if v == "1119" {
+ 1119
+ } else if v == "1120" {
+ 1120
+ } else if v == "1121" {
+ 1121
+ } else if v == "1122" {
+ 1122
+ } else if v == "1123" {
+ 1123
+ } else if v == "1124" {
+ 1124
+ } else if v == "1125" {
+ 1125
+ } else if v == "1126" {
+ 1126
+ } else if v == "1127" {
+ 1127
+ } else if v == "1128" {
+ 1128
+ } else if v == "1129" {
+ 1129
+ } else if v == "1130" {
+ 1130
+ } else if v == "1131" {
+ 1131
+ } else if v == "1132" {
+ 1132
+ } else if v == "1133" {
+ 1133
+ } else if v == "1134" {
+ 1134
+ } else if v == "1135" {
+ 1135
+ } else if v == "1136" {
+ 1136
+ } else if v == "1137" {
+ 1137
+ } else if v == "1138" {
+ 1138
+ } else if v == "1139" {
+ 1139
+ } else if v == "1140" {
+ 1140
+ } else if v == "1141" {
+ 1141
+ } else if v == "1142" {
+ 1142
+ } else if v == "1143" {
+ 1143
+ } else if v == "1144" {
+ 1144
+ } else if v == "1145" {
+ 1145
+ } else if v == "1146" {
+ 1146
+ } else if v == "1147" {
+ 1147
+ } else if v == "1148" {
+ 1148
+ } else if v == "1149" {
+ 1149
+ } else if v == "1150" {
+ 1150
+ } else if v == "1151" {
+ 1151
+ } else if v == "1152" {
+ 1152
+ } else if v == "1153" {
+ 1153
+ } else if v == "1154" {
+ 1154
+ } else if v == "1155" {
+ 1155
+ } else if v == "1156" {
+ 1156
+ } else if v == "1157" {
+ 1157
+ } else if v == "1158" {
+ 1158
+ } else if v == "1159" {
+ 1159
+ } else if v == "1160" {
+ 1160
+ } else if v == "1161" {
+ 1161
+ } else if v == "1162" {
+ 1162
+ } else if v == "1163" {
+ 1163
+ } else if v == "1164" {
+ 1164
+ } else if v == "1165" {
+ 1165
+ } else if v == "1166" {
+ 1166
+ } else if v == "1167" {
+ 1167
+ } else if v == "1168" {
+ 1168
+ } else if v == "1169" {
+ 1169
+ } else if v == "1170" {
+ 1170
+ } else if v == "1171" {
+ 1171
+ } else if v == "1172" {
+ 1172
+ } else if v == "1173" {
+ 1173
+ } else if v == "1174" {
+ 1174
+ } else if v == "1175" {
+ 1175
+ } else if v == "1176" {
+ 1176
+ } else if v == "1177" {
+ 1177
+ } else if v == "1178" {
+ 1178
+ } else if v == "1179" {
+ 1179
+ } else if v == "1180" {
+ 1180
+ } else if v == "1181" {
+ 1181
+ } else if v == "1182" {
+ 1182
+ } else if v == "1183" {
+ 1183
+ } else if v == "1184" {
+ 1184
+ } else if v == "1185" {
+ 1185
+ } else if v == "1186" {
+ 1186
+ } else if v == "1187" {
+ 1187
+ } else if v == "1188" {
+ 1188
+ } else if v == "1189" {
+ 1189
+ } else if v == "1190" {
+ 1190
+ } else if v == "1191" {
+ 1191
+ } else if v == "1192" {
+ 1192
+ } else if v == "1193" {
+ 1193
+ } else if v == "1194" {
+ 1194
+ } else if v == "1195" {
+ 1195
+ } else if v == "1196" {
+ 1196
+ } else if v == "1197" {
+ 1197
+ } else if v == "1198" {
+ 1198
+ } else if v == "1199" {
+ 1199
+ } else if v == "1200" {
+ 1200
+ } else if v == "1201" {
+ 1201
+ } else if v == "1202" {
+ 1202
+ } else if v == "1203" {
+ 1203
+ } else if v == "1204" {
+ 1204
+ } else if v == "1205" {
+ 1205
+ } else if v == "1206" {
+ 1206
+ } else if v == "1207" {
+ 1207
+ } else if v == "1208" {
+ 1208
+ } else if v == "1209" {
+ 1209
+ } else if v == "1210" {
+ 1210
+ } else if v == "1211" {
+ 1211
+ } else if v == "1212" {
+ 1212
+ } else if v == "1213" {
+ 1213
+ } else if v == "1214" {
+ 1214
+ } else if v == "1215" {
+ 1215
+ } else if v == "1216" {
+ 1216
+ } else if v == "1217" {
+ 1217
+ } else if v == "1218" {
+ 1218
+ } else if v == "1219" {
+ 1219
+ } else if v == "1220" {
+ 1220
+ } else if v == "1221" {
+ 1221
+ } else if v == "1222" {
+ 1222
+ } else if v == "1223" {
+ 1223
+ } else if v == "1224" {
+ 1224
+ } else if v == "1225" {
+ 1225
+ } else if v == "1226" {
+ 1226
+ } else if v == "1227" {
+ 1227
+ } else if v == "1228" {
+ 1228
+ } else if v == "1229" {
+ 1229
+ } else if v == "1230" {
+ 1230
+ } else if v == "1231" {
+ 1231
+ } else if v == "1232" {
+ 1232
+ } else if v == "1233" {
+ 1233
+ } else if v == "1234" {
+ 1234
+ } else if v == "1235" {
+ 1235
+ } else if v == "1236" {
+ 1236
+ } else if v == "1237" {
+ 1237
+ } else if v == "1238" {
+ 1238
+ } else if v == "1239" {
+ 1239
+ } else if v == "1240" {
+ 1240
+ } else if v == "1241" {
+ 1241
+ } else if v == "1242" {
+ 1242
+ } else if v == "1243" {
+ 1243
+ } else if v == "1244" {
+ 1244
+ } else if v == "1245" {
+ 1245
+ } else if v == "1246" {
+ 1246
+ } else if v == "1247" {
+ 1247
+ } else if v == "1248" {
+ 1248
+ } else if v == "1249" {
+ 1249
+ } else if v == "1250" {
+ 1250
+ } else if v == "1251" {
+ 1251
+ } else if v == "1252" {
+ 1252
+ } else if v == "1253" {
+ 1253
+ } else if v == "1254" {
+ 1254
+ } else if v == "1255" {
+ 1255
+ } else if v == "1256" {
+ 1256
+ } else if v == "1257" {
+ 1257
+ } else if v == "1258" {
+ 1258
+ } else if v == "1259" {
+ 1259
+ } else if v == "1260" {
+ 1260
+ } else if v == "1261" {
+ 1261
+ } else if v == "1262" {
+ 1262
+ } else if v == "1263" {
+ 1263
+ } else if v == "1264" {
+ 1264
+ } else if v == "1265" {
+ 1265
+ } else if v == "1266" {
+ 1266
+ } else if v == "1267" {
+ 1267
+ } else if v == "1268" {
+ 1268
+ } else if v == "1269" {
+ 1269
+ } else if v == "1270" {
+ 1270
+ } else if v == "1271" {
+ 1271
+ } else if v == "1272" {
+ 1272
+ } else if v == "1273" {
+ 1273
+ } else if v == "1274" {
+ 1274
+ } else if v == "1275" {
+ 1275
+ } else if v == "1276" {
+ 1276
+ } else if v == "1277" {
+ 1277
+ } else if v == "1278" {
+ 1278
+ } else if v == "1279" {
+ 1279
+ } else if v == "1280" {
+ 1280
+ } else if v == "1281" {
+ 1281
+ } else if v == "1282" {
+ 1282
+ } else if v == "1283" {
+ 1283
+ } else if v == "1284" {
+ 1284
+ } else if v == "1285" {
+ 1285
+ } else if v == "1286" {
+ 1286
+ } else if v == "1287" {
+ 1287
+ } else if v == "1288" {
+ 1288
+ } else if v == "1289" {
+ 1289
+ } else if v == "1290" {
+ 1290
+ } else if v == "1291" {
+ 1291
+ } else if v == "1292" {
+ 1292
+ } else if v == "1293" {
+ 1293
+ } else if v == "1294" {
+ 1294
+ } else if v == "1295" {
+ 1295
+ } else if v == "1296" {
+ 1296
+ } else if v == "1297" {
+ 1297
+ } else if v == "1298" {
+ 1298
+ } else if v == "1299" {
+ 1299
+ } else if v == "1300" {
+ 1300
+ } else if v == "1301" {
+ 1301
+ } else if v == "1302" {
+ 1302
+ } else if v == "1303" {
+ 1303
+ } else if v == "1304" {
+ 1304
+ } else if v == "1305" {
+ 1305
+ } else if v == "1306" {
+ 1306
+ } else if v == "1307" {
+ 1307
+ } else if v == "1308" {
+ 1308
+ } else if v == "1309" {
+ 1309
+ } else if v == "1310" {
+ 1310
+ } else if v == "1311" {
+ 1311
+ } else if v == "1312" {
+ 1312
+ } else if v == "1313" {
+ 1313
+ } else if v == "1314" {
+ 1314
+ } else if v == "1315" {
+ 1315
+ } else if v == "1316" {
+ 1316
+ } else if v == "1317" {
+ 1317
+ } else if v == "1318" {
+ 1318
+ } else if v == "1319" {
+ 1319
+ } else if v == "1320" {
+ 1320
+ } else if v == "1321" {
+ 1321
+ } else if v == "1322" {
+ 1322
+ } else if v == "1323" {
+ 1323
+ } else if v == "1324" {
+ 1324
+ } else if v == "1325" {
+ 1325
+ } else if v == "1326" {
+ 1326
+ } else if v == "1327" {
+ 1327
+ } else if v == "1328" {
+ 1328
+ } else if v == "1329" {
+ 1329
+ } else if v == "1330" {
+ 1330
+ } else if v == "1331" {
+ 1331
+ } else if v == "1332" {
+ 1332
+ } else if v == "1333" {
+ 1333
+ } else if v == "1334" {
+ 1334
+ } else if v == "1335" {
+ 1335
+ } else if v == "1336" {
+ 1336
+ } else if v == "1337" {
+ 1337
+ } else if v == "1338" {
+ 1338
+ } else if v == "1339" {
+ 1339
+ } else if v == "1340" {
+ 1340
+ } else if v == "1341" {
+ 1341
+ } else if v == "1342" {
+ 1342
+ } else if v == "1343" {
+ 1343
+ } else if v == "1344" {
+ 1344
+ } else if v == "1345" {
+ 1345
+ } else if v == "1346" {
+ 1346
+ } else if v == "1347" {
+ 1347
+ } else if v == "1348" {
+ 1348
+ } else if v == "1349" {
+ 1349
+ } else if v == "1350" {
+ 1350
+ } else if v == "1351" {
+ 1351
+ } else if v == "1352" {
+ 1352
+ } else if v == "1353" {
+ 1353
+ } else if v == "1354" {
+ 1354
+ } else if v == "1355" {
+ 1355
+ } else if v == "1356" {
+ 1356
+ } else if v == "1357" {
+ 1357
+ } else if v == "1358" {
+ 1358
+ } else if v == "1359" {
+ 1359
+ } else if v == "1360" {
+ 1360
+ } else if v == "1361" {
+ 1361
+ } else if v == "1362" {
+ 1362
+ } else if v == "1363" {
+ 1363
+ } else if v == "1364" {
+ 1364
+ } else if v == "1365" {
+ 1365
+ } else if v == "1366" {
+ 1366
+ } else if v == "1367" {
+ 1367
+ } else if v == "1368" {
+ 1368
+ } else if v == "1369" {
+ 1369
+ } else if v == "1370" {
+ 1370
+ } else if v == "1371" {
+ 1371
+ } else if v == "1372" {
+ 1372
+ } else if v == "1373" {
+ 1373
+ } else if v == "1374" {
+ 1374
+ } else if v == "1375" {
+ 1375
+ } else if v == "1376" {
+ 1376
+ } else if v == "1377" {
+ 1377
+ } else if v == "1378" {
+ 1378
+ } else if v == "1379" {
+ 1379
+ } else if v == "1380" {
+ 1380
+ } else if v == "1381" {
+ 1381
+ } else if v == "1382" {
+ 1382
+ } else if v == "1383" {
+ 1383
+ } else if v == "1384" {
+ 1384
+ } else if v == "1385" {
+ 1385
+ } else if v == "1386" {
+ 1386
+ } else if v == "1387" {
+ 1387
+ } else if v == "1388" {
+ 1388
+ } else if v == "1389" {
+ 1389
+ } else if v == "1390" {
+ 1390
+ } else if v == "1391" {
+ 1391
+ } else if v == "1392" {
+ 1392
+ } else if v == "1393" {
+ 1393
+ } else if v == "1394" {
+ 1394
+ } else if v == "1395" {
+ 1395
+ } else if v == "1396" {
+ 1396
+ } else if v == "1397" {
+ 1397
+ } else if v == "1398" {
+ 1398
+ } else if v == "1399" {
+ 1399
+ } else if v == "1400" {
+ 1400
+ } else if v == "1401" {
+ 1401
+ } else if v == "1402" {
+ 1402
+ } else if v == "1403" {
+ 1403
+ } else if v == "1404" {
+ 1404
+ } else if v == "1405" {
+ 1405
+ } else if v == "1406" {
+ 1406
+ } else if v == "1407" {
+ 1407
+ } else if v == "1408" {
+ 1408
+ } else if v == "1409" {
+ 1409
+ } else if v == "1410" {
+ 1410
+ } else if v == "1411" {
+ 1411
+ } else if v == "1412" {
+ 1412
+ } else if v == "1413" {
+ 1413
+ } else if v == "1414" {
+ 1414
+ } else if v == "1415" {
+ 1415
+ } else if v == "1416" {
+ 1416
+ } else if v == "1417" {
+ 1417
+ } else if v == "1418" {
+ 1418
+ } else if v == "1419" {
+ 1419
+ } else if v == "1420" {
+ 1420
+ } else if v == "1421" {
+ 1421
+ } else if v == "1422" {
+ 1422
+ } else if v == "1423" {
+ 1423
+ } else if v == "1424" {
+ 1424
+ } else if v == "1425" {
+ 1425
+ } else if v == "1426" {
+ 1426
+ } else if v == "1427" {
+ 1427
+ } else if v == "1428" {
+ 1428
+ } else if v == "1429" {
+ 1429
+ } else if v == "1430" {
+ 1430
+ } else if v == "1431" {
+ 1431
+ } else if v == "1432" {
+ 1432
+ } else if v == "1433" {
+ 1433
+ } else if v == "1434" {
+ 1434
+ } else if v == "1435" {
+ 1435
+ } else if v == "1436" {
+ 1436
+ } else if v == "1437" {
+ 1437
+ } else if v == "1438" {
+ 1438
+ } else if v == "1439" {
+ 1439
+ } else if v == "1440" {
+ 1440
+ } else if v == "1441" {
+ 1441
+ } else if v == "1442" {
+ 1442
+ } else if v == "1443" {
+ 1443
+ } else if v == "1444" {
+ 1444
+ } else if v == "1445" {
+ 1445
+ } else if v == "1446" {
+ 1446
+ } else if v == "1447" {
+ 1447
+ } else if v == "1448" {
+ 1448
+ } else if v == "1449" {
+ 1449
+ } else if v == "1450" {
+ 1450
+ } else if v == "1451" {
+ 1451
+ } else if v == "1452" {
+ 1452
+ } else if v == "1453" {
+ 1453
+ } else if v == "1454" {
+ 1454
+ } else if v == "1455" {
+ 1455
+ } else if v == "1456" {
+ 1456
+ } else if v == "1457" {
+ 1457
+ } else if v == "1458" {
+ 1458
+ } else if v == "1459" {
+ 1459
+ } else if v == "1460" {
+ 1460
+ } else if v == "1461" {
+ 1461
+ } else if v == "1462" {
+ 1462
+ } else if v == "1463" {
+ 1463
+ } else if v == "1464" {
+ 1464
+ } else if v == "1465" {
+ 1465
+ } else if v == "1466" {
+ 1466
+ } else if v == "1467" {
+ 1467
+ } else if v == "1468" {
+ 1468
+ } else if v == "1469" {
+ 1469
+ } else if v == "1470" {
+ 1470
+ } else if v == "1471" {
+ 1471
+ } else if v == "1472" {
+ 1472
+ } else if v == "1473" {
+ 1473
+ } else if v == "1474" {
+ 1474
+ } else if v == "1475" {
+ 1475
+ } else if v == "1476" {
+ 1476
+ } else if v == "1477" {
+ 1477
+ } else if v == "1478" {
+ 1478
+ } else if v == "1479" {
+ 1479
+ } else if v == "1480" {
+ 1480
+ } else if v == "1481" {
+ 1481
+ } else if v == "1482" {
+ 1482
+ } else if v == "1483" {
+ 1483
+ } else if v == "1484" {
+ 1484
+ } else if v == "1485" {
+ 1485
+ } else if v == "1486" {
+ 1486
+ } else if v == "1487" {
+ 1487
+ } else if v == "1488" {
+ 1488
+ } else if v == "1489" {
+ 1489
+ } else if v == "1490" {
+ 1490
+ } else if v == "1491" {
+ 1491
+ } else if v == "1492" {
+ 1492
+ } else if v == "1493" {
+ 1493
+ } else if v == "1494" {
+ 1494
+ } else if v == "1495" {
+ 1495
+ } else if v == "1496" {
+ 1496
+ } else if v == "1497" {
+ 1497
+ } else if v == "1498" {
+ 1498
+ } else if v == "1499" {
+ 1499
+ } else if v == "1500" {
+ 1500
+ } else if v == "1501" {
+ 1501
+ } else if v == "1502" {
+ 1502
+ } else if v == "1503" {
+ 1503
+ } else if v == "1504" {
+ 1504
+ } else if v == "1505" {
+ 1505
+ } else if v == "1506" {
+ 1506
+ } else if v == "1507" {
+ 1507
+ } else if v == "1508" {
+ 1508
+ } else if v == "1509" {
+ 1509
+ } else if v == "1510" {
+ 1510
+ } else if v == "1511" {
+ 1511
+ } else if v == "1512" {
+ 1512
+ } else if v == "1513" {
+ 1513
+ } else if v == "1514" {
+ 1514
+ } else if v == "1515" {
+ 1515
+ } else if v == "1516" {
+ 1516
+ } else if v == "1517" {
+ 1517
+ } else if v == "1518" {
+ 1518
+ } else if v == "1519" {
+ 1519
+ } else if v == "1520" {
+ 1520
+ } else if v == "1521" {
+ 1521
+ } else if v == "1522" {
+ 1522
+ } else if v == "1523" {
+ 1523
+ } else if v == "1524" {
+ 1524
+ } else if v == "1525" {
+ 1525
+ } else if v == "1526" {
+ 1526
+ } else if v == "1527" {
+ 1527
+ } else if v == "1528" {
+ 1528
+ } else if v == "1529" {
+ 1529
+ } else if v == "1530" {
+ 1530
+ } else if v == "1531" {
+ 1531
+ } else if v == "1532" {
+ 1532
+ } else if v == "1533" {
+ 1533
+ } else if v == "1534" {
+ 1534
+ } else if v == "1535" {
+ 1535
+ } else if v == "1536" {
+ 1536
+ } else if v == "1537" {
+ 1537
+ } else if v == "1538" {
+ 1538
+ } else if v == "1539" {
+ 1539
+ } else if v == "1540" {
+ 1540
+ } else if v == "1541" {
+ 1541
+ } else if v == "1542" {
+ 1542
+ } else if v == "1543" {
+ 1543
+ } else if v == "1544" {
+ 1544
+ } else if v == "1545" {
+ 1545
+ } else if v == "1546" {
+ 1546
+ } else if v == "1547" {
+ 1547
+ } else if v == "1548" {
+ 1548
+ } else if v == "1549" {
+ 1549
+ } else if v == "1550" {
+ 1550
+ } else if v == "1551" {
+ 1551
+ } else if v == "1552" {
+ 1552
+ } else if v == "1553" {
+ 1553
+ } else if v == "1554" {
+ 1554
+ } else if v == "1555" {
+ 1555
+ } else if v == "1556" {
+ 1556
+ } else if v == "1557" {
+ 1557
+ } else if v == "1558" {
+ 1558
+ } else if v == "1559" {
+ 1559
+ } else if v == "1560" {
+ 1560
+ } else if v == "1561" {
+ 1561
+ } else if v == "1562" {
+ 1562
+ } else if v == "1563" {
+ 1563
+ } else if v == "1564" {
+ 1564
+ } else if v == "1565" {
+ 1565
+ } else if v == "1566" {
+ 1566
+ } else if v == "1567" {
+ 1567
+ } else if v == "1568" {
+ 1568
+ } else if v == "1569" {
+ 1569
+ } else if v == "1570" {
+ 1570
+ } else if v == "1571" {
+ 1571
+ } else if v == "1572" {
+ 1572
+ } else if v == "1573" {
+ 1573
+ } else if v == "1574" {
+ 1574
+ } else if v == "1575" {
+ 1575
+ } else if v == "1576" {
+ 1576
+ } else if v == "1577" {
+ 1577
+ } else if v == "1578" {
+ 1578
+ } else if v == "1579" {
+ 1579
+ } else if v == "1580" {
+ 1580
+ } else if v == "1581" {
+ 1581
+ } else if v == "1582" {
+ 1582
+ } else if v == "1583" {
+ 1583
+ } else if v == "1584" {
+ 1584
+ } else if v == "1585" {
+ 1585
+ } else if v == "1586" {
+ 1586
+ } else if v == "1587" {
+ 1587
+ } else if v == "1588" {
+ 1588
+ } else if v == "1589" {
+ 1589
+ } else if v == "1590" {
+ 1590
+ } else if v == "1591" {
+ 1591
+ } else if v == "1592" {
+ 1592
+ } else if v == "1593" {
+ 1593
+ } else if v == "1594" {
+ 1594
+ } else if v == "1595" {
+ 1595
+ } else if v == "1596" {
+ 1596
+ } else if v == "1597" {
+ 1597
+ } else if v == "1598" {
+ 1598
+ } else if v == "1599" {
+ 1599
+ } else if v == "1600" {
+ 1600
+ } else if v == "1601" {
+ 1601
+ } else if v == "1602" {
+ 1602
+ } else if v == "1603" {
+ 1603
+ } else if v == "1604" {
+ 1604
+ } else if v == "1605" {
+ 1605
+ } else if v == "1606" {
+ 1606
+ } else if v == "1607" {
+ 1607
+ } else if v == "1608" {
+ 1608
+ } else if v == "1609" {
+ 1609
+ } else if v == "1610" {
+ 1610
+ } else if v == "1611" {
+ 1611
+ } else if v == "1612" {
+ 1612
+ } else if v == "1613" {
+ 1613
+ } else if v == "1614" {
+ 1614
+ } else if v == "1615" {
+ 1615
+ } else if v == "1616" {
+ 1616
+ } else if v == "1617" {
+ 1617
+ } else if v == "1618" {
+ 1618
+ } else if v == "1619" {
+ 1619
+ } else if v == "1620" {
+ 1620
+ } else if v == "1621" {
+ 1621
+ } else if v == "1622" {
+ 1622
+ } else if v == "1623" {
+ 1623
+ } else if v == "1624" {
+ 1624
+ } else if v == "1625" {
+ 1625
+ } else if v == "1626" {
+ 1626
+ } else if v == "1627" {
+ 1627
+ } else if v == "1628" {
+ 1628
+ } else if v == "1629" {
+ 1629
+ } else if v == "1630" {
+ 1630
+ } else if v == "1631" {
+ 1631
+ } else if v == "1632" {
+ 1632
+ } else if v == "1633" {
+ 1633
+ } else if v == "1634" {
+ 1634
+ } else if v == "1635" {
+ 1635
+ } else if v == "1636" {
+ 1636
+ } else if v == "1637" {
+ 1637
+ } else if v == "1638" {
+ 1638
+ } else if v == "1639" {
+ 1639
+ } else if v == "1640" {
+ 1640
+ } else if v == "1641" {
+ 1641
+ } else if v == "1642" {
+ 1642
+ } else if v == "1643" {
+ 1643
+ } else if v == "1644" {
+ 1644
+ } else if v == "1645" {
+ 1645
+ } else if v == "1646" {
+ 1646
+ } else if v == "1647" {
+ 1647
+ } else if v == "1648" {
+ 1648
+ } else if v == "1649" {
+ 1649
+ } else if v == "1650" {
+ 1650
+ } else if v == "1651" {
+ 1651
+ } else if v == "1652" {
+ 1652
+ } else if v == "1653" {
+ 1653
+ } else if v == "1654" {
+ 1654
+ } else if v == "1655" {
+ 1655
+ } else if v == "1656" {
+ 1656
+ } else if v == "1657" {
+ 1657
+ } else if v == "1658" {
+ 1658
+ } else if v == "1659" {
+ 1659
+ } else if v == "1660" {
+ 1660
+ } else if v == "1661" {
+ 1661
+ } else if v == "1662" {
+ 1662
+ } else if v == "1663" {
+ 1663
+ } else if v == "1664" {
+ 1664
+ } else if v == "1665" {
+ 1665
+ } else if v == "1666" {
+ 1666
+ } else if v == "1667" {
+ 1667
+ } else if v == "1668" {
+ 1668
+ } else if v == "1669" {
+ 1669
+ } else if v == "1670" {
+ 1670
+ } else if v == "1671" {
+ 1671
+ } else if v == "1672" {
+ 1672
+ } else if v == "1673" {
+ 1673
+ } else if v == "1674" {
+ 1674
+ } else if v == "1675" {
+ 1675
+ } else if v == "1676" {
+ 1676
+ } else if v == "1677" {
+ 1677
+ } else if v == "1678" {
+ 1678
+ } else if v == "1679" {
+ 1679
+ } else if v == "1680" {
+ 1680
+ } else if v == "1681" {
+ 1681
+ } else if v == "1682" {
+ 1682
+ } else if v == "1683" {
+ 1683
+ } else if v == "1684" {
+ 1684
+ } else if v == "1685" {
+ 1685
+ } else if v == "1686" {
+ 1686
+ } else if v == "1687" {
+ 1687
+ } else if v == "1688" {
+ 1688
+ } else if v == "1689" {
+ 1689
+ } else if v == "1690" {
+ 1690
+ } else if v == "1691" {
+ 1691
+ } else if v == "1692" {
+ 1692
+ } else if v == "1693" {
+ 1693
+ } else if v == "1694" {
+ 1694
+ } else if v == "1695" {
+ 1695
+ } else if v == "1696" {
+ 1696
+ } else if v == "1697" {
+ 1697
+ } else if v == "1698" {
+ 1698
+ } else if v == "1699" {
+ 1699
+ } else if v == "1700" {
+ 1700
+ } else if v == "1701" {
+ 1701
+ } else if v == "1702" {
+ 1702
+ } else if v == "1703" {
+ 1703
+ } else if v == "1704" {
+ 1704
+ } else if v == "1705" {
+ 1705
+ } else if v == "1706" {
+ 1706
+ } else if v == "1707" {
+ 1707
+ } else if v == "1708" {
+ 1708
+ } else if v == "1709" {
+ 1709
+ } else if v == "1710" {
+ 1710
+ } else if v == "1711" {
+ 1711
+ } else if v == "1712" {
+ 1712
+ } else if v == "1713" {
+ 1713
+ } else if v == "1714" {
+ 1714
+ } else if v == "1715" {
+ 1715
+ } else if v == "1716" {
+ 1716
+ } else if v == "1717" {
+ 1717
+ } else if v == "1718" {
+ 1718
+ } else if v == "1719" {
+ 1719
+ } else if v == "1720" {
+ 1720
+ } else if v == "1721" {
+ 1721
+ } else if v == "1722" {
+ 1722
+ } else if v == "1723" {
+ 1723
+ } else if v == "1724" {
+ 1724
+ } else if v == "1725" {
+ 1725
+ } else if v == "1726" {
+ 1726
+ } else if v == "1727" {
+ 1727
+ } else if v == "1728" {
+ 1728
+ } else if v == "1729" {
+ 1729
+ } else if v == "1730" {
+ 1730
+ } else if v == "1731" {
+ 1731
+ } else if v == "1732" {
+ 1732
+ } else if v == "1733" {
+ 1733
+ } else if v == "1734" {
+ 1734
+ } else if v == "1735" {
+ 1735
+ } else if v == "1736" {
+ 1736
+ } else if v == "1737" {
+ 1737
+ } else if v == "1738" {
+ 1738
+ } else if v == "1739" {
+ 1739
+ } else if v == "1740" {
+ 1740
+ } else if v == "1741" {
+ 1741
+ } else if v == "1742" {
+ 1742
+ } else if v == "1743" {
+ 1743
+ } else if v == "1744" {
+ 1744
+ } else if v == "1745" {
+ 1745
+ } else if v == "1746" {
+ 1746
+ } else if v == "1747" {
+ 1747
+ } else if v == "1748" {
+ 1748
+ } else if v == "1749" {
+ 1749
+ } else if v == "1750" {
+ 1750
+ } else if v == "1751" {
+ 1751
+ } else if v == "1752" {
+ 1752
+ } else if v == "1753" {
+ 1753
+ } else if v == "1754" {
+ 1754
+ } else if v == "1755" {
+ 1755
+ } else if v == "1756" {
+ 1756
+ } else if v == "1757" {
+ 1757
+ } else if v == "1758" {
+ 1758
+ } else if v == "1759" {
+ 1759
+ } else if v == "1760" {
+ 1760
+ } else if v == "1761" {
+ 1761
+ } else if v == "1762" {
+ 1762
+ } else if v == "1763" {
+ 1763
+ } else if v == "1764" {
+ 1764
+ } else if v == "1765" {
+ 1765
+ } else if v == "1766" {
+ 1766
+ } else if v == "1767" {
+ 1767
+ } else if v == "1768" {
+ 1768
+ } else if v == "1769" {
+ 1769
+ } else if v == "1770" {
+ 1770
+ } else if v == "1771" {
+ 1771
+ } else if v == "1772" {
+ 1772
+ } else if v == "1773" {
+ 1773
+ } else if v == "1774" {
+ 1774
+ } else if v == "1775" {
+ 1775
+ } else if v == "1776" {
+ 1776
+ } else if v == "1777" {
+ 1777
+ } else if v == "1778" {
+ 1778
+ } else if v == "1779" {
+ 1779
+ } else if v == "1780" {
+ 1780
+ } else if v == "1781" {
+ 1781
+ } else if v == "1782" {
+ 1782
+ } else if v == "1783" {
+ 1783
+ } else if v == "1784" {
+ 1784
+ } else if v == "1785" {
+ 1785
+ } else if v == "1786" {
+ 1786
+ } else if v == "1787" {
+ 1787
+ } else if v == "1788" {
+ 1788
+ } else if v == "1789" {
+ 1789
+ } else if v == "1790" {
+ 1790
+ } else if v == "1791" {
+ 1791
+ } else if v == "1792" {
+ 1792
+ } else if v == "1793" {
+ 1793
+ } else if v == "1794" {
+ 1794
+ } else if v == "1795" {
+ 1795
+ } else if v == "1796" {
+ 1796
+ } else if v == "1797" {
+ 1797
+ } else if v == "1798" {
+ 1798
+ } else if v == "1799" {
+ 1799
+ } else if v == "1800" {
+ 1800
+ } else if v == "1801" {
+ 1801
+ } else if v == "1802" {
+ 1802
+ } else if v == "1803" {
+ 1803
+ } else if v == "1804" {
+ 1804
+ } else if v == "1805" {
+ 1805
+ } else if v == "1806" {
+ 1806
+ } else if v == "1807" {
+ 1807
+ } else if v == "1808" {
+ 1808
+ } else if v == "1809" {
+ 1809
+ } else if v == "1810" {
+ 1810
+ } else if v == "1811" {
+ 1811
+ } else if v == "1812" {
+ 1812
+ } else if v == "1813" {
+ 1813
+ } else if v == "1814" {
+ 1814
+ } else if v == "1815" {
+ 1815
+ } else if v == "1816" {
+ 1816
+ } else if v == "1817" {
+ 1817
+ } else if v == "1818" {
+ 1818
+ } else if v == "1819" {
+ 1819
+ } else if v == "1820" {
+ 1820
+ } else if v == "1821" {
+ 1821
+ } else if v == "1822" {
+ 1822
+ } else if v == "1823" {
+ 1823
+ } else if v == "1824" {
+ 1824
+ } else if v == "1825" {
+ 1825
+ } else if v == "1826" {
+ 1826
+ } else if v == "1827" {
+ 1827
+ } else if v == "1828" {
+ 1828
+ } else if v == "1829" {
+ 1829
+ } else if v == "1830" {
+ 1830
+ } else if v == "1831" {
+ 1831
+ } else if v == "1832" {
+ 1832
+ } else if v == "1833" {
+ 1833
+ } else if v == "1834" {
+ 1834
+ } else if v == "1835" {
+ 1835
+ } else if v == "1836" {
+ 1836
+ } else if v == "1837" {
+ 1837
+ } else if v == "1838" {
+ 1838
+ } else if v == "1839" {
+ 1839
+ } else if v == "1840" {
+ 1840
+ } else if v == "1841" {
+ 1841
+ } else if v == "1842" {
+ 1842
+ } else if v == "1843" {
+ 1843
+ } else if v == "1844" {
+ 1844
+ } else if v == "1845" {
+ 1845
+ } else if v == "1846" {
+ 1846
+ } else if v == "1847" {
+ 1847
+ } else if v == "1848" {
+ 1848
+ } else if v == "1849" {
+ 1849
+ } else if v == "1850" {
+ 1850
+ } else if v == "1851" {
+ 1851
+ } else if v == "1852" {
+ 1852
+ } else if v == "1853" {
+ 1853
+ } else if v == "1854" {
+ 1854
+ } else if v == "1855" {
+ 1855
+ } else if v == "1856" {
+ 1856
+ } else if v == "1857" {
+ 1857
+ } else if v == "1858" {
+ 1858
+ } else if v == "1859" {
+ 1859
+ } else if v == "1860" {
+ 1860
+ } else if v == "1861" {
+ 1861
+ } else if v == "1862" {
+ 1862
+ } else if v == "1863" {
+ 1863
+ } else if v == "1864" {
+ 1864
+ } else if v == "1865" {
+ 1865
+ } else if v == "1866" {
+ 1866
+ } else if v == "1867" {
+ 1867
+ } else if v == "1868" {
+ 1868
+ } else if v == "1869" {
+ 1869
+ } else if v == "1870" {
+ 1870
+ } else if v == "1871" {
+ 1871
+ } else if v == "1872" {
+ 1872
+ } else if v == "1873" {
+ 1873
+ } else if v == "1874" {
+ 1874
+ } else if v == "1875" {
+ 1875
+ } else if v == "1876" {
+ 1876
+ } else if v == "1877" {
+ 1877
+ } else if v == "1878" {
+ 1878
+ } else if v == "1879" {
+ 1879
+ } else if v == "1880" {
+ 1880
+ } else if v == "1881" {
+ 1881
+ } else if v == "1882" {
+ 1882
+ } else if v == "1883" {
+ 1883
+ } else if v == "1884" {
+ 1884
+ } else if v == "1885" {
+ 1885
+ } else if v == "1886" {
+ 1886
+ } else if v == "1887" {
+ 1887
+ } else if v == "1888" {
+ 1888
+ } else if v == "1889" {
+ 1889
+ } else if v == "1890" {
+ 1890
+ } else if v == "1891" {
+ 1891
+ } else if v == "1892" {
+ 1892
+ } else if v == "1893" {
+ 1893
+ } else if v == "1894" {
+ 1894
+ } else if v == "1895" {
+ 1895
+ } else if v == "1896" {
+ 1896
+ } else if v == "1897" {
+ 1897
+ } else if v == "1898" {
+ 1898
+ } else if v == "1899" {
+ 1899
+ } else if v == "1900" {
+ 1900
+ } else if v == "1901" {
+ 1901
+ } else if v == "1902" {
+ 1902
+ } else if v == "1903" {
+ 1903
+ } else if v == "1904" {
+ 1904
+ } else if v == "1905" {
+ 1905
+ } else if v == "1906" {
+ 1906
+ } else if v == "1907" {
+ 1907
+ } else if v == "1908" {
+ 1908
+ } else if v == "1909" {
+ 1909
+ } else if v == "1910" {
+ 1910
+ } else if v == "1911" {
+ 1911
+ } else if v == "1912" {
+ 1912
+ } else if v == "1913" {
+ 1913
+ } else if v == "1914" {
+ 1914
+ } else if v == "1915" {
+ 1915
+ } else if v == "1916" {
+ 1916
+ } else if v == "1917" {
+ 1917
+ } else if v == "1918" {
+ 1918
+ } else if v == "1919" {
+ 1919
+ } else if v == "1920" {
+ 1920
+ } else if v == "1921" {
+ 1921
+ } else if v == "1922" {
+ 1922
+ } else if v == "1923" {
+ 1923
+ } else if v == "1924" {
+ 1924
+ } else if v == "1925" {
+ 1925
+ } else if v == "1926" {
+ 1926
+ } else if v == "1927" {
+ 1927
+ } else if v == "1928" {
+ 1928
+ } else if v == "1929" {
+ 1929
+ } else if v == "1930" {
+ 1930
+ } else if v == "1931" {
+ 1931
+ } else if v == "1932" {
+ 1932
+ } else if v == "1933" {
+ 1933
+ } else if v == "1934" {
+ 1934
+ } else if v == "1935" {
+ 1935
+ } else if v == "1936" {
+ 1936
+ } else if v == "1937" {
+ 1937
+ } else if v == "1938" {
+ 1938
+ } else if v == "1939" {
+ 1939
+ } else if v == "1940" {
+ 1940
+ } else if v == "1941" {
+ 1941
+ } else if v == "1942" {
+ 1942
+ } else if v == "1943" {
+ 1943
+ } else if v == "1944" {
+ 1944
+ } else if v == "1945" {
+ 1945
+ } else if v == "1946" {
+ 1946
+ } else if v == "1947" {
+ 1947
+ } else if v == "1948" {
+ 1948
+ } else if v == "1949" {
+ 1949
+ } else if v == "1950" {
+ 1950
+ } else if v == "1951" {
+ 1951
+ } else if v == "1952" {
+ 1952
+ } else if v == "1953" {
+ 1953
+ } else if v == "1954" {
+ 1954
+ } else if v == "1955" {
+ 1955
+ } else if v == "1956" {
+ 1956
+ } else if v == "1957" {
+ 1957
+ } else if v == "1958" {
+ 1958
+ } else if v == "1959" {
+ 1959
+ } else if v == "1960" {
+ 1960
+ } else if v == "1961" {
+ 1961
+ } else if v == "1962" {
+ 1962
+ } else if v == "1963" {
+ 1963
+ } else if v == "1964" {
+ 1964
+ } else if v == "1965" {
+ 1965
+ } else if v == "1966" {
+ 1966
+ } else if v == "1967" {
+ 1967
+ } else if v == "1968" {
+ 1968
+ } else if v == "1969" {
+ 1969
+ } else if v == "1970" {
+ 1970
+ } else if v == "1971" {
+ 1971
+ } else if v == "1972" {
+ 1972
+ } else if v == "1973" {
+ 1973
+ } else if v == "1974" {
+ 1974
+ } else if v == "1975" {
+ 1975
+ } else if v == "1976" {
+ 1976
+ } else if v == "1977" {
+ 1977
+ } else if v == "1978" {
+ 1978
+ } else if v == "1979" {
+ 1979
+ } else if v == "1980" {
+ 1980
+ } else if v == "1981" {
+ 1981
+ } else if v == "1982" {
+ 1982
+ } else if v == "1983" {
+ 1983
+ } else if v == "1984" {
+ 1984
+ } else if v == "1985" {
+ 1985
+ } else if v == "1986" {
+ 1986
+ } else if v == "1987" {
+ 1987
+ } else if v == "1988" {
+ 1988
+ } else if v == "1989" {
+ 1989
+ } else if v == "1990" {
+ 1990
+ } else if v == "1991" {
+ 1991
+ } else if v == "1992" {
+ 1992
+ } else if v == "1993" {
+ 1993
+ } else if v == "1994" {
+ 1994
+ } else if v == "1995" {
+ 1995
+ } else if v == "1996" {
+ 1996
+ } else if v == "1997" {
+ 1997
+ } else if v == "1998" {
+ 1998
+ } else if v == "1999" {
+ 1999
+ } else if v == "2000" {
+ 2000
+ } else if v == "2001" {
+ 2001
+ } else if v == "2002" {
+ 2002
+ } else if v == "2003" {
+ 2003
+ } else if v == "2004" {
+ 2004
+ } else if v == "2005" {
+ 2005
+ } else if v == "2006" {
+ 2006
+ } else if v == "2007" {
+ 2007
+ } else if v == "2008" {
+ 2008
+ } else if v == "2009" {
+ 2009
+ } else if v == "2010" {
+ 2010
+ } else if v == "2011" {
+ 2011
+ } else if v == "2012" {
+ 2012
+ } else if v == "2013" {
+ 2013
+ } else if v == "2014" {
+ 2014
+ } else if v == "2015" {
+ 2015
+ } else if v == "2016" {
+ 2016
+ } else if v == "2017" {
+ 2017
+ } else if v == "2018" {
+ 2018
+ } else if v == "2019" {
+ 2019
+ } else if v == "2020" {
+ 2020
+ } else if v == "2021" {
+ 2021
+ } else if v == "2022" {
+ 2022
+ } else if v == "2023" {
+ 2023
+ } else if v == "2024" {
+ 2024
+ } else if v == "2025" {
+ 2025
+ } else if v == "2026" {
+ 2026
+ } else if v == "2027" {
+ 2027
+ } else if v == "2028" {
+ 2028
+ } else if v == "2029" {
+ 2029
+ } else if v == "2030" {
+ 2030
+ } else if v == "2031" {
+ 2031
+ } else if v == "2032" {
+ 2032
+ } else if v == "2033" {
+ 2033
+ } else if v == "2034" {
+ 2034
+ } else if v == "2035" {
+ 2035
+ } else if v == "2036" {
+ 2036
+ } else if v == "2037" {
+ 2037
+ } else if v == "2038" {
+ 2038
+ } else if v == "2039" {
+ 2039
+ } else if v == "2040" {
+ 2040
+ } else if v == "2041" {
+ 2041
+ } else if v == "2042" {
+ 2042
+ } else if v == "2043" {
+ 2043
+ } else if v == "2044" {
+ 2044
+ } else if v == "2045" {
+ 2045
+ } else if v == "2046" {
+ 2046
+ } else if v == "2047" {
+ 2047
+ } else if v == "2048" {
+ 2048
+ } else if v == "2049" {
+ 2049
+ } else if v == "2050" {
+ 2050
+ } else if v == "2051" {
+ 2051
+ } else if v == "2052" {
+ 2052
+ } else if v == "2053" {
+ 2053
+ } else if v == "2054" {
+ 2054
+ } else if v == "2055" {
+ 2055
+ } else if v == "2056" {
+ 2056
+ } else if v == "2057" {
+ 2057
+ } else if v == "2058" {
+ 2058
+ } else if v == "2059" {
+ 2059
+ } else if v == "2060" {
+ 2060
+ } else if v == "2061" {
+ 2061
+ } else if v == "2062" {
+ 2062
+ } else if v == "2063" {
+ 2063
+ } else if v == "2064" {
+ 2064
+ } else if v == "2065" {
+ 2065
+ } else if v == "2066" {
+ 2066
+ } else if v == "2067" {
+ 2067
+ } else if v == "2068" {
+ 2068
+ } else if v == "2069" {
+ 2069
+ } else if v == "2070" {
+ 2070
+ } else if v == "2071" {
+ 2071
+ } else if v == "2072" {
+ 2072
+ } else if v == "2073" {
+ 2073
+ } else if v == "2074" {
+ 2074
+ } else if v == "2075" {
+ 2075
+ } else if v == "2076" {
+ 2076
+ } else if v == "2077" {
+ 2077
+ } else if v == "2078" {
+ 2078
+ } else if v == "2079" {
+ 2079
+ } else if v == "2080" {
+ 2080
+ } else if v == "2081" {
+ 2081
+ } else if v == "2082" {
+ 2082
+ } else if v == "2083" {
+ 2083
+ } else if v == "2084" {
+ 2084
+ } else if v == "2085" {
+ 2085
+ } else if v == "2086" {
+ 2086
+ } else if v == "2087" {
+ 2087
+ } else if v == "2088" {
+ 2088
+ } else if v == "2089" {
+ 2089
+ } else if v == "2090" {
+ 2090
+ } else if v == "2091" {
+ 2091
+ } else if v == "2092" {
+ 2092
+ } else if v == "2093" {
+ 2093
+ } else if v == "2094" {
+ 2094
+ } else if v == "2095" {
+ 2095
+ } else if v == "2096" {
+ 2096
+ } else if v == "2097" {
+ 2097
+ } else if v == "2098" {
+ 2098
+ } else if v == "2099" {
+ 2099
+ } else if v == "2100" {
+ 2100
+ } else if v == "2101" {
+ 2101
+ } else if v == "2102" {
+ 2102
+ } else if v == "2103" {
+ 2103
+ } else if v == "2104" {
+ 2104
+ } else if v == "2105" {
+ 2105
+ } else if v == "2106" {
+ 2106
+ } else if v == "2107" {
+ 2107
+ } else if v == "2108" {
+ 2108
+ } else if v == "2109" {
+ 2109
+ } else if v == "2110" {
+ 2110
+ } else if v == "2111" {
+ 2111
+ } else if v == "2112" {
+ 2112
+ } else if v == "2113" {
+ 2113
+ } else if v == "2114" {
+ 2114
+ } else if v == "2115" {
+ 2115
+ } else if v == "2116" {
+ 2116
+ } else if v == "2117" {
+ 2117
+ } else if v == "2118" {
+ 2118
+ } else if v == "2119" {
+ 2119
+ } else if v == "2120" {
+ 2120
+ } else if v == "2121" {
+ 2121
+ } else if v == "2122" {
+ 2122
+ } else if v == "2123" {
+ 2123
+ } else if v == "2124" {
+ 2124
+ } else if v == "2125" {
+ 2125
+ } else if v == "2126" {
+ 2126
+ } else if v == "2127" {
+ 2127
+ } else if v == "2128" {
+ 2128
+ } else if v == "2129" {
+ 2129
+ } else if v == "2130" {
+ 2130
+ } else if v == "2131" {
+ 2131
+ } else if v == "2132" {
+ 2132
+ } else if v == "2133" {
+ 2133
+ } else if v == "2134" {
+ 2134
+ } else if v == "2135" {
+ 2135
+ } else if v == "2136" {
+ 2136
+ } else if v == "2137" {
+ 2137
+ } else if v == "2138" {
+ 2138
+ } else if v == "2139" {
+ 2139
+ } else if v == "2140" {
+ 2140
+ } else if v == "2141" {
+ 2141
+ } else if v == "2142" {
+ 2142
+ } else if v == "2143" {
+ 2143
+ } else if v == "2144" {
+ 2144
+ } else if v == "2145" {
+ 2145
+ } else if v == "2146" {
+ 2146
+ } else if v == "2147" {
+ 2147
+ } else if v == "2148" {
+ 2148
+ } else if v == "2149" {
+ 2149
+ } else if v == "2150" {
+ 2150
+ } else if v == "2151" {
+ 2151
+ } else if v == "2152" {
+ 2152
+ } else if v == "2153" {
+ 2153
+ } else if v == "2154" {
+ 2154
+ } else if v == "2155" {
+ 2155
+ } else if v == "2156" {
+ 2156
+ } else if v == "2157" {
+ 2157
+ } else if v == "2158" {
+ 2158
+ } else if v == "2159" {
+ 2159
+ } else if v == "2160" {
+ 2160
+ } else if v == "2161" {
+ 2161
+ } else if v == "2162" {
+ 2162
+ } else if v == "2163" {
+ 2163
+ } else if v == "2164" {
+ 2164
+ } else if v == "2165" {
+ 2165
+ } else if v == "2166" {
+ 2166
+ } else if v == "2167" {
+ 2167
+ } else if v == "2168" {
+ 2168
+ } else if v == "2169" {
+ 2169
+ } else if v == "2170" {
+ 2170
+ } else if v == "2171" {
+ 2171
+ } else if v == "2172" {
+ 2172
+ } else if v == "2173" {
+ 2173
+ } else if v == "2174" {
+ 2174
+ } else if v == "2175" {
+ 2175
+ } else if v == "2176" {
+ 2176
+ } else if v == "2177" {
+ 2177
+ } else if v == "2178" {
+ 2178
+ } else if v == "2179" {
+ 2179
+ } else if v == "2180" {
+ 2180
+ } else if v == "2181" {
+ 2181
+ } else if v == "2182" {
+ 2182
+ } else if v == "2183" {
+ 2183
+ } else if v == "2184" {
+ 2184
+ } else if v == "2185" {
+ 2185
+ } else if v == "2186" {
+ 2186
+ } else if v == "2187" {
+ 2187
+ } else if v == "2188" {
+ 2188
+ } else if v == "2189" {
+ 2189
+ } else if v == "2190" {
+ 2190
+ } else if v == "2191" {
+ 2191
+ } else if v == "2192" {
+ 2192
+ } else if v == "2193" {
+ 2193
+ } else if v == "2194" {
+ 2194
+ } else if v == "2195" {
+ 2195
+ } else if v == "2196" {
+ 2196
+ } else if v == "2197" {
+ 2197
+ } else if v == "2198" {
+ 2198
+ } else if v == "2199" {
+ 2199
+ } else if v == "2200" {
+ 2200
+ } else if v == "2201" {
+ 2201
+ } else if v == "2202" {
+ 2202
+ } else if v == "2203" {
+ 2203
+ } else if v == "2204" {
+ 2204
+ } else if v == "2205" {
+ 2205
+ } else if v == "2206" {
+ 2206
+ } else if v == "2207" {
+ 2207
+ } else if v == "2208" {
+ 2208
+ } else if v == "2209" {
+ 2209
+ } else if v == "2210" {
+ 2210
+ } else if v == "2211" {
+ 2211
+ } else if v == "2212" {
+ 2212
+ } else if v == "2213" {
+ 2213
+ } else if v == "2214" {
+ 2214
+ } else if v == "2215" {
+ 2215
+ } else if v == "2216" {
+ 2216
+ } else if v == "2217" {
+ 2217
+ } else if v == "2218" {
+ 2218
+ } else if v == "2219" {
+ 2219
+ } else if v == "2220" {
+ 2220
+ } else if v == "2221" {
+ 2221
+ } else if v == "2222" {
+ 2222
+ } else if v == "2223" {
+ 2223
+ } else if v == "2224" {
+ 2224
+ } else if v == "2225" {
+ 2225
+ } else if v == "2226" {
+ 2226
+ } else if v == "2227" {
+ 2227
+ } else if v == "2228" {
+ 2228
+ } else if v == "2229" {
+ 2229
+ } else if v == "2230" {
+ 2230
+ } else if v == "2231" {
+ 2231
+ } else if v == "2232" {
+ 2232
+ } else if v == "2233" {
+ 2233
+ } else if v == "2234" {
+ 2234
+ } else if v == "2235" {
+ 2235
+ } else if v == "2236" {
+ 2236
+ } else if v == "2237" {
+ 2237
+ } else if v == "2238" {
+ 2238
+ } else if v == "2239" {
+ 2239
+ } else if v == "2240" {
+ 2240
+ } else if v == "2241" {
+ 2241
+ } else if v == "2242" {
+ 2242
+ } else if v == "2243" {
+ 2243
+ } else if v == "2244" {
+ 2244
+ } else if v == "2245" {
+ 2245
+ } else if v == "2246" {
+ 2246
+ } else if v == "2247" {
+ 2247
+ } else if v == "2248" {
+ 2248
+ } else if v == "2249" {
+ 2249
+ } else if v == "2250" {
+ 2250
+ } else if v == "2251" {
+ 2251
+ } else if v == "2252" {
+ 2252
+ } else if v == "2253" {
+ 2253
+ } else if v == "2254" {
+ 2254
+ } else if v == "2255" {
+ 2255
+ } else if v == "2256" {
+ 2256
+ } else if v == "2257" {
+ 2257
+ } else if v == "2258" {
+ 2258
+ } else if v == "2259" {
+ 2259
+ } else if v == "2260" {
+ 2260
+ } else if v == "2261" {
+ 2261
+ } else if v == "2262" {
+ 2262
+ } else if v == "2263" {
+ 2263
+ } else if v == "2264" {
+ 2264
+ } else if v == "2265" {
+ 2265
+ } else if v == "2266" {
+ 2266
+ } else if v == "2267" {
+ 2267
+ } else if v == "2268" {
+ 2268
+ } else if v == "2269" {
+ 2269
+ } else if v == "2270" {
+ 2270
+ } else if v == "2271" {
+ 2271
+ } else if v == "2272" {
+ 2272
+ } else if v == "2273" {
+ 2273
+ } else if v == "2274" {
+ 2274
+ } else if v == "2275" {
+ 2275
+ } else if v == "2276" {
+ 2276
+ } else if v == "2277" {
+ 2277
+ } else if v == "2278" {
+ 2278
+ } else if v == "2279" {
+ 2279
+ } else if v == "2280" {
+ 2280
+ } else if v == "2281" {
+ 2281
+ } else if v == "2282" {
+ 2282
+ } else if v == "2283" {
+ 2283
+ } else if v == "2284" {
+ 2284
+ } else if v == "2285" {
+ 2285
+ } else if v == "2286" {
+ 2286
+ } else if v == "2287" {
+ 2287
+ } else if v == "2288" {
+ 2288
+ } else if v == "2289" {
+ 2289
+ } else if v == "2290" {
+ 2290
+ } else if v == "2291" {
+ 2291
+ } else if v == "2292" {
+ 2292
+ } else if v == "2293" {
+ 2293
+ } else if v == "2294" {
+ 2294
+ } else if v == "2295" {
+ 2295
+ } else if v == "2296" {
+ 2296
+ } else if v == "2297" {
+ 2297
+ } else if v == "2298" {
+ 2298
+ } else if v == "2299" {
+ 2299
+ } else if v == "2300" {
+ 2300
+ } else if v == "2301" {
+ 2301
+ } else if v == "2302" {
+ 2302
+ } else if v == "2303" {
+ 2303
+ } else if v == "2304" {
+ 2304
+ } else if v == "2305" {
+ 2305
+ } else if v == "2306" {
+ 2306
+ } else if v == "2307" {
+ 2307
+ } else if v == "2308" {
+ 2308
+ } else if v == "2309" {
+ 2309
+ } else if v == "2310" {
+ 2310
+ } else if v == "2311" {
+ 2311
+ } else if v == "2312" {
+ 2312
+ } else if v == "2313" {
+ 2313
+ } else if v == "2314" {
+ 2314
+ } else if v == "2315" {
+ 2315
+ } else if v == "2316" {
+ 2316
+ } else if v == "2317" {
+ 2317
+ } else if v == "2318" {
+ 2318
+ } else if v == "2319" {
+ 2319
+ } else if v == "2320" {
+ 2320
+ } else if v == "2321" {
+ 2321
+ } else if v == "2322" {
+ 2322
+ } else if v == "2323" {
+ 2323
+ } else if v == "2324" {
+ 2324
+ } else if v == "2325" {
+ 2325
+ } else if v == "2326" {
+ 2326
+ } else if v == "2327" {
+ 2327
+ } else if v == "2328" {
+ 2328
+ } else if v == "2329" {
+ 2329
+ } else if v == "2330" {
+ 2330
+ } else if v == "2331" {
+ 2331
+ } else if v == "2332" {
+ 2332
+ } else if v == "2333" {
+ 2333
+ } else if v == "2334" {
+ 2334
+ } else if v == "2335" {
+ 2335
+ } else if v == "2336" {
+ 2336
+ } else if v == "2337" {
+ 2337
+ } else if v == "2338" {
+ 2338
+ } else if v == "2339" {
+ 2339
+ } else if v == "2340" {
+ 2340
+ } else if v == "2341" {
+ 2341
+ } else if v == "2342" {
+ 2342
+ } else if v == "2343" {
+ 2343
+ } else if v == "2344" {
+ 2344
+ } else if v == "2345" {
+ 2345
+ } else if v == "2346" {
+ 2346
+ } else if v == "2347" {
+ 2347
+ } else if v == "2348" {
+ 2348
+ } else if v == "2349" {
+ 2349
+ } else if v == "2350" {
+ 2350
+ } else if v == "2351" {
+ 2351
+ } else if v == "2352" {
+ 2352
+ } else if v == "2353" {
+ 2353
+ } else if v == "2354" {
+ 2354
+ } else if v == "2355" {
+ 2355
+ } else if v == "2356" {
+ 2356
+ } else if v == "2357" {
+ 2357
+ } else if v == "2358" {
+ 2358
+ } else if v == "2359" {
+ 2359
+ } else if v == "2360" {
+ 2360
+ } else if v == "2361" {
+ 2361
+ } else if v == "2362" {
+ 2362
+ } else if v == "2363" {
+ 2363
+ } else if v == "2364" {
+ 2364
+ } else if v == "2365" {
+ 2365
+ } else if v == "2366" {
+ 2366
+ } else if v == "2367" {
+ 2367
+ } else if v == "2368" {
+ 2368
+ } else if v == "2369" {
+ 2369
+ } else if v == "2370" {
+ 2370
+ } else if v == "2371" {
+ 2371
+ } else if v == "2372" {
+ 2372
+ } else if v == "2373" {
+ 2373
+ } else if v == "2374" {
+ 2374
+ } else if v == "2375" {
+ 2375
+ } else if v == "2376" {
+ 2376
+ } else if v == "2377" {
+ 2377
+ } else if v == "2378" {
+ 2378
+ } else if v == "2379" {
+ 2379
+ } else if v == "2380" {
+ 2380
+ } else if v == "2381" {
+ 2381
+ } else if v == "2382" {
+ 2382
+ } else if v == "2383" {
+ 2383
+ } else if v == "2384" {
+ 2384
+ } else if v == "2385" {
+ 2385
+ } else if v == "2386" {
+ 2386
+ } else if v == "2387" {
+ 2387
+ } else if v == "2388" {
+ 2388
+ } else if v == "2389" {
+ 2389
+ } else if v == "2390" {
+ 2390
+ } else if v == "2391" {
+ 2391
+ } else if v == "2392" {
+ 2392
+ } else if v == "2393" {
+ 2393
+ } else if v == "2394" {
+ 2394
+ } else if v == "2395" {
+ 2395
+ } else if v == "2396" {
+ 2396
+ } else if v == "2397" {
+ 2397
+ } else if v == "2398" {
+ 2398
+ } else if v == "2399" {
+ 2399
+ } else if v == "2400" {
+ 2400
+ } else if v == "2401" {
+ 2401
+ } else if v == "2402" {
+ 2402
+ } else if v == "2403" {
+ 2403
+ } else if v == "2404" {
+ 2404
+ } else if v == "2405" {
+ 2405
+ } else if v == "2406" {
+ 2406
+ } else if v == "2407" {
+ 2407
+ } else if v == "2408" {
+ 2408
+ } else if v == "2409" {
+ 2409
+ } else if v == "2410" {
+ 2410
+ } else if v == "2411" {
+ 2411
+ } else if v == "2412" {
+ 2412
+ } else if v == "2413" {
+ 2413
+ } else if v == "2414" {
+ 2414
+ } else if v == "2415" {
+ 2415
+ } else if v == "2416" {
+ 2416
+ } else if v == "2417" {
+ 2417
+ } else if v == "2418" {
+ 2418
+ } else if v == "2419" {
+ 2419
+ } else if v == "2420" {
+ 2420
+ } else if v == "2421" {
+ 2421
+ } else if v == "2422" {
+ 2422
+ } else if v == "2423" {
+ 2423
+ } else if v == "2424" {
+ 2424
+ } else if v == "2425" {
+ 2425
+ } else if v == "2426" {
+ 2426
+ } else if v == "2427" {
+ 2427
+ } else if v == "2428" {
+ 2428
+ } else if v == "2429" {
+ 2429
+ } else if v == "2430" {
+ 2430
+ } else if v == "2431" {
+ 2431
+ } else if v == "2432" {
+ 2432
+ } else if v == "2433" {
+ 2433
+ } else if v == "2434" {
+ 2434
+ } else if v == "2435" {
+ 2435
+ } else if v == "2436" {
+ 2436
+ } else if v == "2437" {
+ 2437
+ } else if v == "2438" {
+ 2438
+ } else if v == "2439" {
+ 2439
+ } else if v == "2440" {
+ 2440
+ } else if v == "2441" {
+ 2441
+ } else if v == "2442" {
+ 2442
+ } else if v == "2443" {
+ 2443
+ } else if v == "2444" {
+ 2444
+ } else if v == "2445" {
+ 2445
+ } else if v == "2446" {
+ 2446
+ } else if v == "2447" {
+ 2447
+ } else if v == "2448" {
+ 2448
+ } else if v == "2449" {
+ 2449
+ } else if v == "2450" {
+ 2450
+ } else if v == "2451" {
+ 2451
+ } else if v == "2452" {
+ 2452
+ } else if v == "2453" {
+ 2453
+ } else if v == "2454" {
+ 2454
+ } else if v == "2455" {
+ 2455
+ } else if v == "2456" {
+ 2456
+ } else if v == "2457" {
+ 2457
+ } else if v == "2458" {
+ 2458
+ } else if v == "2459" {
+ 2459
+ } else if v == "2460" {
+ 2460
+ } else if v == "2461" {
+ 2461
+ } else if v == "2462" {
+ 2462
+ } else if v == "2463" {
+ 2463
+ } else if v == "2464" {
+ 2464
+ } else if v == "2465" {
+ 2465
+ } else if v == "2466" {
+ 2466
+ } else if v == "2467" {
+ 2467
+ } else if v == "2468" {
+ 2468
+ } else if v == "2469" {
+ 2469
+ } else if v == "2470" {
+ 2470
+ } else if v == "2471" {
+ 2471
+ } else if v == "2472" {
+ 2472
+ } else if v == "2473" {
+ 2473
+ } else if v == "2474" {
+ 2474
+ } else if v == "2475" {
+ 2475
+ } else if v == "2476" {
+ 2476
+ } else if v == "2477" {
+ 2477
+ } else if v == "2478" {
+ 2478
+ } else if v == "2479" {
+ 2479
+ } else if v == "2480" {
+ 2480
+ } else if v == "2481" {
+ 2481
+ } else if v == "2482" {
+ 2482
+ } else if v == "2483" {
+ 2483
+ } else if v == "2484" {
+ 2484
+ } else if v == "2485" {
+ 2485
+ } else if v == "2486" {
+ 2486
+ } else if v == "2487" {
+ 2487
+ } else if v == "2488" {
+ 2488
+ } else if v == "2489" {
+ 2489
+ } else if v == "2490" {
+ 2490
+ } else if v == "2491" {
+ 2491
+ } else if v == "2492" {
+ 2492
+ } else if v == "2493" {
+ 2493
+ } else if v == "2494" {
+ 2494
+ } else if v == "2495" {
+ 2495
+ } else if v == "2496" {
+ 2496
+ } else if v == "2497" {
+ 2497
+ } else if v == "2498" {
+ 2498
+ } else if v == "2499" {
+ 2499
+ } else if v == "2500" {
+ 2500
+ } else if v == "2501" {
+ 2501
+ } else if v == "2502" {
+ 2502
+ } else if v == "2503" {
+ 2503
+ } else if v == "2504" {
+ 2504
+ } else if v == "2505" {
+ 2505
+ } else if v == "2506" {
+ 2506
+ } else if v == "2507" {
+ 2507
+ } else if v == "2508" {
+ 2508
+ } else if v == "2509" {
+ 2509
+ } else if v == "2510" {
+ 2510
+ } else if v == "2511" {
+ 2511
+ } else if v == "2512" {
+ 2512
+ } else if v == "2513" {
+ 2513
+ } else if v == "2514" {
+ 2514
+ } else if v == "2515" {
+ 2515
+ } else if v == "2516" {
+ 2516
+ } else if v == "2517" {
+ 2517
+ } else if v == "2518" {
+ 2518
+ } else if v == "2519" {
+ 2519
+ } else if v == "2520" {
+ 2520
+ } else if v == "2521" {
+ 2521
+ } else if v == "2522" {
+ 2522
+ } else if v == "2523" {
+ 2523
+ } else if v == "2524" {
+ 2524
+ } else if v == "2525" {
+ 2525
+ } else if v == "2526" {
+ 2526
+ } else if v == "2527" {
+ 2527
+ } else if v == "2528" {
+ 2528
+ } else if v == "2529" {
+ 2529
+ } else if v == "2530" {
+ 2530
+ } else if v == "2531" {
+ 2531
+ } else if v == "2532" {
+ 2532
+ } else if v == "2533" {
+ 2533
+ } else if v == "2534" {
+ 2534
+ } else if v == "2535" {
+ 2535
+ } else if v == "2536" {
+ 2536
+ } else if v == "2537" {
+ 2537
+ } else if v == "2538" {
+ 2538
+ } else if v == "2539" {
+ 2539
+ } else if v == "2540" {
+ 2540
+ } else if v == "2541" {
+ 2541
+ } else if v == "2542" {
+ 2542
+ } else if v == "2543" {
+ 2543
+ } else if v == "2544" {
+ 2544
+ } else if v == "2545" {
+ 2545
+ } else if v == "2546" {
+ 2546
+ } else if v == "2547" {
+ 2547
+ } else if v == "2548" {
+ 2548
+ } else if v == "2549" {
+ 2549
+ } else if v == "2550" {
+ 2550
+ } else if v == "2551" {
+ 2551
+ } else if v == "2552" {
+ 2552
+ } else if v == "2553" {
+ 2553
+ } else if v == "2554" {
+ 2554
+ } else if v == "2555" {
+ 2555
+ } else if v == "2556" {
+ 2556
+ } else if v == "2557" {
+ 2557
+ } else if v == "2558" {
+ 2558
+ } else if v == "2559" {
+ 2559
+ } else if v == "2560" {
+ 2560
+ } else if v == "2561" {
+ 2561
+ } else if v == "2562" {
+ 2562
+ } else if v == "2563" {
+ 2563
+ } else if v == "2564" {
+ 2564
+ } else if v == "2565" {
+ 2565
+ } else if v == "2566" {
+ 2566
+ } else if v == "2567" {
+ 2567
+ } else if v == "2568" {
+ 2568
+ } else if v == "2569" {
+ 2569
+ } else if v == "2570" {
+ 2570
+ } else if v == "2571" {
+ 2571
+ } else if v == "2572" {
+ 2572
+ } else if v == "2573" {
+ 2573
+ } else if v == "2574" {
+ 2574
+ } else if v == "2575" {
+ 2575
+ } else if v == "2576" {
+ 2576
+ } else if v == "2577" {
+ 2577
+ } else if v == "2578" {
+ 2578
+ } else if v == "2579" {
+ 2579
+ } else if v == "2580" {
+ 2580
+ } else if v == "2581" {
+ 2581
+ } else if v == "2582" {
+ 2582
+ } else if v == "2583" {
+ 2583
+ } else if v == "2584" {
+ 2584
+ } else if v == "2585" {
+ 2585
+ } else if v == "2586" {
+ 2586
+ } else if v == "2587" {
+ 2587
+ } else if v == "2588" {
+ 2588
+ } else if v == "2589" {
+ 2589
+ } else if v == "2590" {
+ 2590
+ } else if v == "2591" {
+ 2591
+ } else if v == "2592" {
+ 2592
+ } else if v == "2593" {
+ 2593
+ } else if v == "2594" {
+ 2594
+ } else if v == "2595" {
+ 2595
+ } else if v == "2596" {
+ 2596
+ } else if v == "2597" {
+ 2597
+ } else if v == "2598" {
+ 2598
+ } else if v == "2599" {
+ 2599
+ } else if v == "2600" {
+ 2600
+ } else if v == "2601" {
+ 2601
+ } else if v == "2602" {
+ 2602
+ } else if v == "2603" {
+ 2603
+ } else if v == "2604" {
+ 2604
+ } else if v == "2605" {
+ 2605
+ } else if v == "2606" {
+ 2606
+ } else if v == "2607" {
+ 2607
+ } else if v == "2608" {
+ 2608
+ } else if v == "2609" {
+ 2609
+ } else if v == "2610" {
+ 2610
+ } else if v == "2611" {
+ 2611
+ } else if v == "2612" {
+ 2612
+ } else if v == "2613" {
+ 2613
+ } else if v == "2614" {
+ 2614
+ } else if v == "2615" {
+ 2615
+ } else if v == "2616" {
+ 2616
+ } else if v == "2617" {
+ 2617
+ } else if v == "2618" {
+ 2618
+ } else if v == "2619" {
+ 2619
+ } else if v == "2620" {
+ 2620
+ } else if v == "2621" {
+ 2621
+ } else if v == "2622" {
+ 2622
+ } else if v == "2623" {
+ 2623
+ } else if v == "2624" {
+ 2624
+ } else if v == "2625" {
+ 2625
+ } else if v == "2626" {
+ 2626
+ } else if v == "2627" {
+ 2627
+ } else if v == "2628" {
+ 2628
+ } else if v == "2629" {
+ 2629
+ } else if v == "2630" {
+ 2630
+ } else if v == "2631" {
+ 2631
+ } else if v == "2632" {
+ 2632
+ } else if v == "2633" {
+ 2633
+ } else if v == "2634" {
+ 2634
+ } else if v == "2635" {
+ 2635
+ } else if v == "2636" {
+ 2636
+ } else if v == "2637" {
+ 2637
+ } else if v == "2638" {
+ 2638
+ } else if v == "2639" {
+ 2639
+ } else if v == "2640" {
+ 2640
+ } else if v == "2641" {
+ 2641
+ } else if v == "2642" {
+ 2642
+ } else if v == "2643" {
+ 2643
+ } else if v == "2644" {
+ 2644
+ } else if v == "2645" {
+ 2645
+ } else if v == "2646" {
+ 2646
+ } else if v == "2647" {
+ 2647
+ } else if v == "2648" {
+ 2648
+ } else if v == "2649" {
+ 2649
+ } else if v == "2650" {
+ 2650
+ } else if v == "2651" {
+ 2651
+ } else if v == "2652" {
+ 2652
+ } else if v == "2653" {
+ 2653
+ } else if v == "2654" {
+ 2654
+ } else if v == "2655" {
+ 2655
+ } else if v == "2656" {
+ 2656
+ } else if v == "2657" {
+ 2657
+ } else if v == "2658" {
+ 2658
+ } else if v == "2659" {
+ 2659
+ } else if v == "2660" {
+ 2660
+ } else if v == "2661" {
+ 2661
+ } else if v == "2662" {
+ 2662
+ } else if v == "2663" {
+ 2663
+ } else if v == "2664" {
+ 2664
+ } else if v == "2665" {
+ 2665
+ } else if v == "2666" {
+ 2666
+ } else if v == "2667" {
+ 2667
+ } else if v == "2668" {
+ 2668
+ } else if v == "2669" {
+ 2669
+ } else if v == "2670" {
+ 2670
+ } else if v == "2671" {
+ 2671
+ } else if v == "2672" {
+ 2672
+ } else if v == "2673" {
+ 2673
+ } else if v == "2674" {
+ 2674
+ } else if v == "2675" {
+ 2675
+ } else if v == "2676" {
+ 2676
+ } else if v == "2677" {
+ 2677
+ } else if v == "2678" {
+ 2678
+ } else if v == "2679" {
+ 2679
+ } else if v == "2680" {
+ 2680
+ } else if v == "2681" {
+ 2681
+ } else if v == "2682" {
+ 2682
+ } else if v == "2683" {
+ 2683
+ } else if v == "2684" {
+ 2684
+ } else if v == "2685" {
+ 2685
+ } else if v == "2686" {
+ 2686
+ } else if v == "2687" {
+ 2687
+ } else if v == "2688" {
+ 2688
+ } else if v == "2689" {
+ 2689
+ } else if v == "2690" {
+ 2690
+ } else if v == "2691" {
+ 2691
+ } else if v == "2692" {
+ 2692
+ } else if v == "2693" {
+ 2693
+ } else if v == "2694" {
+ 2694
+ } else if v == "2695" {
+ 2695
+ } else if v == "2696" {
+ 2696
+ } else if v == "2697" {
+ 2697
+ } else if v == "2698" {
+ 2698
+ } else if v == "2699" {
+ 2699
+ } else if v == "2700" {
+ 2700
+ } else if v == "2701" {
+ 2701
+ } else if v == "2702" {
+ 2702
+ } else if v == "2703" {
+ 2703
+ } else if v == "2704" {
+ 2704
+ } else if v == "2705" {
+ 2705
+ } else if v == "2706" {
+ 2706
+ } else if v == "2707" {
+ 2707
+ } else if v == "2708" {
+ 2708
+ } else if v == "2709" {
+ 2709
+ } else if v == "2710" {
+ 2710
+ } else if v == "2711" {
+ 2711
+ } else if v == "2712" {
+ 2712
+ } else if v == "2713" {
+ 2713
+ } else if v == "2714" {
+ 2714
+ } else if v == "2715" {
+ 2715
+ } else if v == "2716" {
+ 2716
+ } else if v == "2717" {
+ 2717
+ } else if v == "2718" {
+ 2718
+ } else if v == "2719" {
+ 2719
+ } else if v == "2720" {
+ 2720
+ } else if v == "2721" {
+ 2721
+ } else if v == "2722" {
+ 2722
+ } else if v == "2723" {
+ 2723
+ } else if v == "2724" {
+ 2724
+ } else if v == "2725" {
+ 2725
+ } else if v == "2726" {
+ 2726
+ } else if v == "2727" {
+ 2727
+ } else if v == "2728" {
+ 2728
+ } else if v == "2729" {
+ 2729
+ } else if v == "2730" {
+ 2730
+ } else if v == "2731" {
+ 2731
+ } else if v == "2732" {
+ 2732
+ } else if v == "2733" {
+ 2733
+ } else if v == "2734" {
+ 2734
+ } else if v == "2735" {
+ 2735
+ } else if v == "2736" {
+ 2736
+ } else if v == "2737" {
+ 2737
+ } else if v == "2738" {
+ 2738
+ } else if v == "2739" {
+ 2739
+ } else if v == "2740" {
+ 2740
+ } else if v == "2741" {
+ 2741
+ } else if v == "2742" {
+ 2742
+ } else if v == "2743" {
+ 2743
+ } else if v == "2744" {
+ 2744
+ } else if v == "2745" {
+ 2745
+ } else if v == "2746" {
+ 2746
+ } else if v == "2747" {
+ 2747
+ } else if v == "2748" {
+ 2748
+ } else if v == "2749" {
+ 2749
+ } else if v == "2750" {
+ 2750
+ } else if v == "2751" {
+ 2751
+ } else if v == "2752" {
+ 2752
+ } else if v == "2753" {
+ 2753
+ } else if v == "2754" {
+ 2754
+ } else if v == "2755" {
+ 2755
+ } else if v == "2756" {
+ 2756
+ } else if v == "2757" {
+ 2757
+ } else if v == "2758" {
+ 2758
+ } else if v == "2759" {
+ 2759
+ } else if v == "2760" {
+ 2760
+ } else if v == "2761" {
+ 2761
+ } else if v == "2762" {
+ 2762
+ } else if v == "2763" {
+ 2763
+ } else if v == "2764" {
+ 2764
+ } else if v == "2765" {
+ 2765
+ } else if v == "2766" {
+ 2766
+ } else if v == "2767" {
+ 2767
+ } else if v == "2768" {
+ 2768
+ } else if v == "2769" {
+ 2769
+ } else if v == "2770" {
+ 2770
+ } else if v == "2771" {
+ 2771
+ } else if v == "2772" {
+ 2772
+ } else if v == "2773" {
+ 2773
+ } else if v == "2774" {
+ 2774
+ } else if v == "2775" {
+ 2775
+ } else if v == "2776" {
+ 2776
+ } else if v == "2777" {
+ 2777
+ } else if v == "2778" {
+ 2778
+ } else if v == "2779" {
+ 2779
+ } else if v == "2780" {
+ 2780
+ } else if v == "2781" {
+ 2781
+ } else if v == "2782" {
+ 2782
+ } else if v == "2783" {
+ 2783
+ } else if v == "2784" {
+ 2784
+ } else if v == "2785" {
+ 2785
+ } else if v == "2786" {
+ 2786
+ } else if v == "2787" {
+ 2787
+ } else if v == "2788" {
+ 2788
+ } else if v == "2789" {
+ 2789
+ } else if v == "2790" {
+ 2790
+ } else if v == "2791" {
+ 2791
+ } else if v == "2792" {
+ 2792
+ } else if v == "2793" {
+ 2793
+ } else if v == "2794" {
+ 2794
+ } else if v == "2795" {
+ 2795
+ } else if v == "2796" {
+ 2796
+ } else if v == "2797" {
+ 2797
+ } else if v == "2798" {
+ 2798
+ } else if v == "2799" {
+ 2799
+ } else if v == "2800" {
+ 2800
+ } else if v == "2801" {
+ 2801
+ } else if v == "2802" {
+ 2802
+ } else if v == "2803" {
+ 2803
+ } else if v == "2804" {
+ 2804
+ } else if v == "2805" {
+ 2805
+ } else if v == "2806" {
+ 2806
+ } else if v == "2807" {
+ 2807
+ } else if v == "2808" {
+ 2808
+ } else if v == "2809" {
+ 2809
+ } else if v == "2810" {
+ 2810
+ } else if v == "2811" {
+ 2811
+ } else if v == "2812" {
+ 2812
+ } else if v == "2813" {
+ 2813
+ } else if v == "2814" {
+ 2814
+ } else if v == "2815" {
+ 2815
+ } else if v == "2816" {
+ 2816
+ } else if v == "2817" {
+ 2817
+ } else if v == "2818" {
+ 2818
+ } else if v == "2819" {
+ 2819
+ } else if v == "2820" {
+ 2820
+ } else if v == "2821" {
+ 2821
+ } else if v == "2822" {
+ 2822
+ } else if v == "2823" {
+ 2823
+ } else if v == "2824" {
+ 2824
+ } else if v == "2825" {
+ 2825
+ } else if v == "2826" {
+ 2826
+ } else if v == "2827" {
+ 2827
+ } else if v == "2828" {
+ 2828
+ } else if v == "2829" {
+ 2829
+ } else if v == "2830" {
+ 2830
+ } else if v == "2831" {
+ 2831
+ } else if v == "2832" {
+ 2832
+ } else if v == "2833" {
+ 2833
+ } else if v == "2834" {
+ 2834
+ } else if v == "2835" {
+ 2835
+ } else if v == "2836" {
+ 2836
+ } else if v == "2837" {
+ 2837
+ } else if v == "2838" {
+ 2838
+ } else if v == "2839" {
+ 2839
+ } else if v == "2840" {
+ 2840
+ } else if v == "2841" {
+ 2841
+ } else if v == "2842" {
+ 2842
+ } else if v == "2843" {
+ 2843
+ } else if v == "2844" {
+ 2844
+ } else if v == "2845" {
+ 2845
+ } else if v == "2846" {
+ 2846
+ } else if v == "2847" {
+ 2847
+ } else if v == "2848" {
+ 2848
+ } else if v == "2849" {
+ 2849
+ } else if v == "2850" {
+ 2850
+ } else if v == "2851" {
+ 2851
+ } else if v == "2852" {
+ 2852
+ } else if v == "2853" {
+ 2853
+ } else if v == "2854" {
+ 2854
+ } else if v == "2855" {
+ 2855
+ } else if v == "2856" {
+ 2856
+ } else if v == "2857" {
+ 2857
+ } else if v == "2858" {
+ 2858
+ } else if v == "2859" {
+ 2859
+ } else if v == "2860" {
+ 2860
+ } else if v == "2861" {
+ 2861
+ } else if v == "2862" {
+ 2862
+ } else if v == "2863" {
+ 2863
+ } else if v == "2864" {
+ 2864
+ } else if v == "2865" {
+ 2865
+ } else if v == "2866" {
+ 2866
+ } else if v == "2867" {
+ 2867
+ } else if v == "2868" {
+ 2868
+ } else if v == "2869" {
+ 2869
+ } else if v == "2870" {
+ 2870
+ } else if v == "2871" {
+ 2871
+ } else if v == "2872" {
+ 2872
+ } else if v == "2873" {
+ 2873
+ } else if v == "2874" {
+ 2874
+ } else if v == "2875" {
+ 2875
+ } else if v == "2876" {
+ 2876
+ } else if v == "2877" {
+ 2877
+ } else if v == "2878" {
+ 2878
+ } else if v == "2879" {
+ 2879
+ } else if v == "2880" {
+ 2880
+ } else if v == "2881" {
+ 2881
+ } else if v == "2882" {
+ 2882
+ } else if v == "2883" {
+ 2883
+ } else if v == "2884" {
+ 2884
+ } else if v == "2885" {
+ 2885
+ } else if v == "2886" {
+ 2886
+ } else if v == "2887" {
+ 2887
+ } else if v == "2888" {
+ 2888
+ } else if v == "2889" {
+ 2889
+ } else if v == "2890" {
+ 2890
+ } else if v == "2891" {
+ 2891
+ } else if v == "2892" {
+ 2892
+ } else if v == "2893" {
+ 2893
+ } else if v == "2894" {
+ 2894
+ } else if v == "2895" {
+ 2895
+ } else if v == "2896" {
+ 2896
+ } else if v == "2897" {
+ 2897
+ } else if v == "2898" {
+ 2898
+ } else if v == "2899" {
+ 2899
+ } else if v == "2900" {
+ 2900
+ } else if v == "2901" {
+ 2901
+ } else if v == "2902" {
+ 2902
+ } else if v == "2903" {
+ 2903
+ } else if v == "2904" {
+ 2904
+ } else if v == "2905" {
+ 2905
+ } else if v == "2906" {
+ 2906
+ } else if v == "2907" {
+ 2907
+ } else if v == "2908" {
+ 2908
+ } else if v == "2909" {
+ 2909
+ } else if v == "2910" {
+ 2910
+ } else if v == "2911" {
+ 2911
+ } else if v == "2912" {
+ 2912
+ } else if v == "2913" {
+ 2913
+ } else if v == "2914" {
+ 2914
+ } else if v == "2915" {
+ 2915
+ } else if v == "2916" {
+ 2916
+ } else if v == "2917" {
+ 2917
+ } else if v == "2918" {
+ 2918
+ } else if v == "2919" {
+ 2919
+ } else if v == "2920" {
+ 2920
+ } else if v == "2921" {
+ 2921
+ } else if v == "2922" {
+ 2922
+ } else if v == "2923" {
+ 2923
+ } else if v == "2924" {
+ 2924
+ } else if v == "2925" {
+ 2925
+ } else if v == "2926" {
+ 2926
+ } else if v == "2927" {
+ 2927
+ } else if v == "2928" {
+ 2928
+ } else if v == "2929" {
+ 2929
+ } else if v == "2930" {
+ 2930
+ } else if v == "2931" {
+ 2931
+ } else if v == "2932" {
+ 2932
+ } else if v == "2933" {
+ 2933
+ } else if v == "2934" {
+ 2934
+ } else if v == "2935" {
+ 2935
+ } else if v == "2936" {
+ 2936
+ } else if v == "2937" {
+ 2937
+ } else if v == "2938" {
+ 2938
+ } else if v == "2939" {
+ 2939
+ } else if v == "2940" {
+ 2940
+ } else if v == "2941" {
+ 2941
+ } else if v == "2942" {
+ 2942
+ } else if v == "2943" {
+ 2943
+ } else if v == "2944" {
+ 2944
+ } else if v == "2945" {
+ 2945
+ } else if v == "2946" {
+ 2946
+ } else if v == "2947" {
+ 2947
+ } else if v == "2948" {
+ 2948
+ } else if v == "2949" {
+ 2949
+ } else if v == "2950" {
+ 2950
+ } else if v == "2951" {
+ 2951
+ } else if v == "2952" {
+ 2952
+ } else if v == "2953" {
+ 2953
+ } else if v == "2954" {
+ 2954
+ } else if v == "2955" {
+ 2955
+ } else if v == "2956" {
+ 2956
+ } else if v == "2957" {
+ 2957
+ } else if v == "2958" {
+ 2958
+ } else if v == "2959" {
+ 2959
+ } else if v == "2960" {
+ 2960
+ } else if v == "2961" {
+ 2961
+ } else if v == "2962" {
+ 2962
+ } else if v == "2963" {
+ 2963
+ } else if v == "2964" {
+ 2964
+ } else if v == "2965" {
+ 2965
+ } else if v == "2966" {
+ 2966
+ } else if v == "2967" {
+ 2967
+ } else if v == "2968" {
+ 2968
+ } else if v == "2969" {
+ 2969
+ } else if v == "2970" {
+ 2970
+ } else if v == "2971" {
+ 2971
+ } else if v == "2972" {
+ 2972
+ } else if v == "2973" {
+ 2973
+ } else if v == "2974" {
+ 2974
+ } else if v == "2975" {
+ 2975
+ } else if v == "2976" {
+ 2976
+ } else if v == "2977" {
+ 2977
+ } else if v == "2978" {
+ 2978
+ } else if v == "2979" {
+ 2979
+ } else if v == "2980" {
+ 2980
+ } else if v == "2981" {
+ 2981
+ } else if v == "2982" {
+ 2982
+ } else if v == "2983" {
+ 2983
+ } else if v == "2984" {
+ 2984
+ } else if v == "2985" {
+ 2985
+ } else if v == "2986" {
+ 2986
+ } else if v == "2987" {
+ 2987
+ } else if v == "2988" {
+ 2988
+ } else if v == "2989" {
+ 2989
+ } else if v == "2990" {
+ 2990
+ } else if v == "2991" {
+ 2991
+ } else if v == "2992" {
+ 2992
+ } else if v == "2993" {
+ 2993
+ } else if v == "2994" {
+ 2994
+ } else if v == "2995" {
+ 2995
+ } else if v == "2996" {
+ 2996
+ } else if v == "2997" {
+ 2997
+ } else if v == "2998" {
+ 2998
+ } else if v == "2999" {
+ 2999
+ } else if v == "3000" {
+ 3000
+ } else if v == "3001" {
+ 3001
+ } else if v == "3002" {
+ 3002
+ } else if v == "3003" {
+ 3003
+ } else if v == "3004" {
+ 3004
+ } else if v == "3005" {
+ 3005
+ } else if v == "3006" {
+ 3006
+ } else if v == "3007" {
+ 3007
+ } else if v == "3008" {
+ 3008
+ } else if v == "3009" {
+ 3009
+ } else if v == "3010" {
+ 3010
+ } else if v == "3011" {
+ 3011
+ } else if v == "3012" {
+ 3012
+ } else if v == "3013" {
+ 3013
+ } else if v == "3014" {
+ 3014
+ } else if v == "3015" {
+ 3015
+ } else if v == "3016" {
+ 3016
+ } else if v == "3017" {
+ 3017
+ } else if v == "3018" {
+ 3018
+ } else if v == "3019" {
+ 3019
+ } else if v == "3020" {
+ 3020
+ } else if v == "3021" {
+ 3021
+ } else if v == "3022" {
+ 3022
+ } else if v == "3023" {
+ 3023
+ } else if v == "3024" {
+ 3024
+ } else if v == "3025" {
+ 3025
+ } else if v == "3026" {
+ 3026
+ } else if v == "3027" {
+ 3027
+ } else if v == "3028" {
+ 3028
+ } else if v == "3029" {
+ 3029
+ } else if v == "3030" {
+ 3030
+ } else if v == "3031" {
+ 3031
+ } else if v == "3032" {
+ 3032
+ } else if v == "3033" {
+ 3033
+ } else if v == "3034" {
+ 3034
+ } else if v == "3035" {
+ 3035
+ } else if v == "3036" {
+ 3036
+ } else if v == "3037" {
+ 3037
+ } else if v == "3038" {
+ 3038
+ } else if v == "3039" {
+ 3039
+ } else if v == "3040" {
+ 3040
+ } else if v == "3041" {
+ 3041
+ } else if v == "3042" {
+ 3042
+ } else if v == "3043" {
+ 3043
+ } else if v == "3044" {
+ 3044
+ } else if v == "3045" {
+ 3045
+ } else if v == "3046" {
+ 3046
+ } else if v == "3047" {
+ 3047
+ } else if v == "3048" {
+ 3048
+ } else if v == "3049" {
+ 3049
+ } else if v == "3050" {
+ 3050
+ } else if v == "3051" {
+ 3051
+ } else if v == "3052" {
+ 3052
+ } else if v == "3053" {
+ 3053
+ } else if v == "3054" {
+ 3054
+ } else if v == "3055" {
+ 3055
+ } else if v == "3056" {
+ 3056
+ } else if v == "3057" {
+ 3057
+ } else if v == "3058" {
+ 3058
+ } else if v == "3059" {
+ 3059
+ } else if v == "3060" {
+ 3060
+ } else if v == "3061" {
+ 3061
+ } else if v == "3062" {
+ 3062
+ } else if v == "3063" {
+ 3063
+ } else if v == "3064" {
+ 3064
+ } else if v == "3065" {
+ 3065
+ } else if v == "3066" {
+ 3066
+ } else if v == "3067" {
+ 3067
+ } else if v == "3068" {
+ 3068
+ } else if v == "3069" {
+ 3069
+ } else if v == "3070" {
+ 3070
+ } else if v == "3071" {
+ 3071
+ } else if v == "3072" {
+ 3072
+ } else if v == "3073" {
+ 3073
+ } else if v == "3074" {
+ 3074
+ } else if v == "3075" {
+ 3075
+ } else if v == "3076" {
+ 3076
+ } else if v == "3077" {
+ 3077
+ } else if v == "3078" {
+ 3078
+ } else if v == "3079" {
+ 3079
+ } else if v == "3080" {
+ 3080
+ } else if v == "3081" {
+ 3081
+ } else if v == "3082" {
+ 3082
+ } else if v == "3083" {
+ 3083
+ } else if v == "3084" {
+ 3084
+ } else if v == "3085" {
+ 3085
+ } else if v == "3086" {
+ 3086
+ } else if v == "3087" {
+ 3087
+ } else if v == "3088" {
+ 3088
+ } else if v == "3089" {
+ 3089
+ } else if v == "3090" {
+ 3090
+ } else if v == "3091" {
+ 3091
+ } else if v == "3092" {
+ 3092
+ } else if v == "3093" {
+ 3093
+ } else if v == "3094" {
+ 3094
+ } else if v == "3095" {
+ 3095
+ } else if v == "3096" {
+ 3096
+ } else if v == "3097" {
+ 3097
+ } else if v == "3098" {
+ 3098
+ } else if v == "3099" {
+ 3099
+ } else if v == "3100" {
+ 3100
+ } else if v == "3101" {
+ 3101
+ } else if v == "3102" {
+ 3102
+ } else if v == "3103" {
+ 3103
+ } else if v == "3104" {
+ 3104
+ } else if v == "3105" {
+ 3105
+ } else if v == "3106" {
+ 3106
+ } else if v == "3107" {
+ 3107
+ } else if v == "3108" {
+ 3108
+ } else if v == "3109" {
+ 3109
+ } else if v == "3110" {
+ 3110
+ } else if v == "3111" {
+ 3111
+ } else if v == "3112" {
+ 3112
+ } else if v == "3113" {
+ 3113
+ } else if v == "3114" {
+ 3114
+ } else if v == "3115" {
+ 3115
+ } else if v == "3116" {
+ 3116
+ } else if v == "3117" {
+ 3117
+ } else if v == "3118" {
+ 3118
+ } else if v == "3119" {
+ 3119
+ } else if v == "3120" {
+ 3120
+ } else if v == "3121" {
+ 3121
+ } else if v == "3122" {
+ 3122
+ } else if v == "3123" {
+ 3123
+ } else if v == "3124" {
+ 3124
+ } else if v == "3125" {
+ 3125
+ } else if v == "3126" {
+ 3126
+ } else if v == "3127" {
+ 3127
+ } else if v == "3128" {
+ 3128
+ } else if v == "3129" {
+ 3129
+ } else if v == "3130" {
+ 3130
+ } else if v == "3131" {
+ 3131
+ } else if v == "3132" {
+ 3132
+ } else if v == "3133" {
+ 3133
+ } else if v == "3134" {
+ 3134
+ } else if v == "3135" {
+ 3135
+ } else if v == "3136" {
+ 3136
+ } else if v == "3137" {
+ 3137
+ } else if v == "3138" {
+ 3138
+ } else if v == "3139" {
+ 3139
+ } else if v == "3140" {
+ 3140
+ } else if v == "3141" {
+ 3141
+ } else if v == "3142" {
+ 3142
+ } else if v == "3143" {
+ 3143
+ } else if v == "3144" {
+ 3144
+ } else if v == "3145" {
+ 3145
+ } else if v == "3146" {
+ 3146
+ } else if v == "3147" {
+ 3147
+ } else if v == "3148" {
+ 3148
+ } else if v == "3149" {
+ 3149
+ } else if v == "3150" {
+ 3150
+ } else if v == "3151" {
+ 3151
+ } else if v == "3152" {
+ 3152
+ } else if v == "3153" {
+ 3153
+ } else if v == "3154" {
+ 3154
+ } else if v == "3155" {
+ 3155
+ } else if v == "3156" {
+ 3156
+ } else if v == "3157" {
+ 3157
+ } else if v == "3158" {
+ 3158
+ } else if v == "3159" {
+ 3159
+ } else if v == "3160" {
+ 3160
+ } else if v == "3161" {
+ 3161
+ } else if v == "3162" {
+ 3162
+ } else if v == "3163" {
+ 3163
+ } else if v == "3164" {
+ 3164
+ } else if v == "3165" {
+ 3165
+ } else if v == "3166" {
+ 3166
+ } else if v == "3167" {
+ 3167
+ } else if v == "3168" {
+ 3168
+ } else if v == "3169" {
+ 3169
+ } else if v == "3170" {
+ 3170
+ } else if v == "3171" {
+ 3171
+ } else if v == "3172" {
+ 3172
+ } else if v == "3173" {
+ 3173
+ } else if v == "3174" {
+ 3174
+ } else if v == "3175" {
+ 3175
+ } else if v == "3176" {
+ 3176
+ } else if v == "3177" {
+ 3177
+ } else if v == "3178" {
+ 3178
+ } else if v == "3179" {
+ 3179
+ } else if v == "3180" {
+ 3180
+ } else if v == "3181" {
+ 3181
+ } else if v == "3182" {
+ 3182
+ } else if v == "3183" {
+ 3183
+ } else if v == "3184" {
+ 3184
+ } else if v == "3185" {
+ 3185
+ } else if v == "3186" {
+ 3186
+ } else if v == "3187" {
+ 3187
+ } else if v == "3188" {
+ 3188
+ } else if v == "3189" {
+ 3189
+ } else if v == "3190" {
+ 3190
+ } else if v == "3191" {
+ 3191
+ } else if v == "3192" {
+ 3192
+ } else if v == "3193" {
+ 3193
+ } else if v == "3194" {
+ 3194
+ } else if v == "3195" {
+ 3195
+ } else if v == "3196" {
+ 3196
+ } else if v == "3197" {
+ 3197
+ } else if v == "3198" {
+ 3198
+ } else if v == "3199" {
+ 3199
+ } else if v == "3200" {
+ 3200
+ } else if v == "3201" {
+ 3201
+ } else if v == "3202" {
+ 3202
+ } else if v == "3203" {
+ 3203
+ } else if v == "3204" {
+ 3204
+ } else if v == "3205" {
+ 3205
+ } else if v == "3206" {
+ 3206
+ } else if v == "3207" {
+ 3207
+ } else if v == "3208" {
+ 3208
+ } else if v == "3209" {
+ 3209
+ } else if v == "3210" {
+ 3210
+ } else if v == "3211" {
+ 3211
+ } else if v == "3212" {
+ 3212
+ } else if v == "3213" {
+ 3213
+ } else if v == "3214" {
+ 3214
+ } else if v == "3215" {
+ 3215
+ } else if v == "3216" {
+ 3216
+ } else if v == "3217" {
+ 3217
+ } else if v == "3218" {
+ 3218
+ } else if v == "3219" {
+ 3219
+ } else if v == "3220" {
+ 3220
+ } else if v == "3221" {
+ 3221
+ } else if v == "3222" {
+ 3222
+ } else if v == "3223" {
+ 3223
+ } else if v == "3224" {
+ 3224
+ } else if v == "3225" {
+ 3225
+ } else if v == "3226" {
+ 3226
+ } else if v == "3227" {
+ 3227
+ } else if v == "3228" {
+ 3228
+ } else if v == "3229" {
+ 3229
+ } else if v == "3230" {
+ 3230
+ } else if v == "3231" {
+ 3231
+ } else if v == "3232" {
+ 3232
+ } else if v == "3233" {
+ 3233
+ } else if v == "3234" {
+ 3234
+ } else if v == "3235" {
+ 3235
+ } else if v == "3236" {
+ 3236
+ } else if v == "3237" {
+ 3237
+ } else if v == "3238" {
+ 3238
+ } else if v == "3239" {
+ 3239
+ } else if v == "3240" {
+ 3240
+ } else if v == "3241" {
+ 3241
+ } else if v == "3242" {
+ 3242
+ } else if v == "3243" {
+ 3243
+ } else if v == "3244" {
+ 3244
+ } else if v == "3245" {
+ 3245
+ } else if v == "3246" {
+ 3246
+ } else if v == "3247" {
+ 3247
+ } else if v == "3248" {
+ 3248
+ } else if v == "3249" {
+ 3249
+ } else if v == "3250" {
+ 3250
+ } else if v == "3251" {
+ 3251
+ } else if v == "3252" {
+ 3252
+ } else if v == "3253" {
+ 3253
+ } else if v == "3254" {
+ 3254
+ } else if v == "3255" {
+ 3255
+ } else if v == "3256" {
+ 3256
+ } else if v == "3257" {
+ 3257
+ } else if v == "3258" {
+ 3258
+ } else if v == "3259" {
+ 3259
+ } else if v == "3260" {
+ 3260
+ } else if v == "3261" {
+ 3261
+ } else if v == "3262" {
+ 3262
+ } else if v == "3263" {
+ 3263
+ } else if v == "3264" {
+ 3264
+ } else if v == "3265" {
+ 3265
+ } else if v == "3266" {
+ 3266
+ } else if v == "3267" {
+ 3267
+ } else if v == "3268" {
+ 3268
+ } else if v == "3269" {
+ 3269
+ } else if v == "3270" {
+ 3270
+ } else if v == "3271" {
+ 3271
+ } else if v == "3272" {
+ 3272
+ } else if v == "3273" {
+ 3273
+ } else if v == "3274" {
+ 3274
+ } else if v == "3275" {
+ 3275
+ } else if v == "3276" {
+ 3276
+ } else if v == "3277" {
+ 3277
+ } else if v == "3278" {
+ 3278
+ } else if v == "3279" {
+ 3279
+ } else if v == "3280" {
+ 3280
+ } else if v == "3281" {
+ 3281
+ } else if v == "3282" {
+ 3282
+ } else if v == "3283" {
+ 3283
+ } else if v == "3284" {
+ 3284
+ } else if v == "3285" {
+ 3285
+ } else if v == "3286" {
+ 3286
+ } else if v == "3287" {
+ 3287
+ } else if v == "3288" {
+ 3288
+ } else if v == "3289" {
+ 3289
+ } else if v == "3290" {
+ 3290
+ } else if v == "3291" {
+ 3291
+ } else if v == "3292" {
+ 3292
+ } else if v == "3293" {
+ 3293
+ } else if v == "3294" {
+ 3294
+ } else if v == "3295" {
+ 3295
+ } else if v == "3296" {
+ 3296
+ } else if v == "3297" {
+ 3297
+ } else if v == "3298" {
+ 3298
+ } else if v == "3299" {
+ 3299
+ } else if v == "3300" {
+ 3300
+ } else if v == "3301" {
+ 3301
+ } else if v == "3302" {
+ 3302
+ } else if v == "3303" {
+ 3303
+ } else if v == "3304" {
+ 3304
+ } else if v == "3305" {
+ 3305
+ } else if v == "3306" {
+ 3306
+ } else if v == "3307" {
+ 3307
+ } else if v == "3308" {
+ 3308
+ } else if v == "3309" {
+ 3309
+ } else if v == "3310" {
+ 3310
+ } else if v == "3311" {
+ 3311
+ } else if v == "3312" {
+ 3312
+ } else if v == "3313" {
+ 3313
+ } else if v == "3314" {
+ 3314
+ } else if v == "3315" {
+ 3315
+ } else if v == "3316" {
+ 3316
+ } else if v == "3317" {
+ 3317
+ } else if v == "3318" {
+ 3318
+ } else if v == "3319" {
+ 3319
+ } else if v == "3320" {
+ 3320
+ } else if v == "3321" {
+ 3321
+ } else if v == "3322" {
+ 3322
+ } else if v == "3323" {
+ 3323
+ } else if v == "3324" {
+ 3324
+ } else if v == "3325" {
+ 3325
+ } else if v == "3326" {
+ 3326
+ } else if v == "3327" {
+ 3327
+ } else if v == "3328" {
+ 3328
+ } else if v == "3329" {
+ 3329
+ } else if v == "3330" {
+ 3330
+ } else if v == "3331" {
+ 3331
+ } else if v == "3332" {
+ 3332
+ } else if v == "3333" {
+ 3333
+ } else if v == "3334" {
+ 3334
+ } else if v == "3335" {
+ 3335
+ } else if v == "3336" {
+ 3336
+ } else if v == "3337" {
+ 3337
+ } else if v == "3338" {
+ 3338
+ } else if v == "3339" {
+ 3339
+ } else if v == "3340" {
+ 3340
+ } else if v == "3341" {
+ 3341
+ } else if v == "3342" {
+ 3342
+ } else if v == "3343" {
+ 3343
+ } else if v == "3344" {
+ 3344
+ } else if v == "3345" {
+ 3345
+ } else if v == "3346" {
+ 3346
+ } else if v == "3347" {
+ 3347
+ } else if v == "3348" {
+ 3348
+ } else if v == "3349" {
+ 3349
+ } else if v == "3350" {
+ 3350
+ } else if v == "3351" {
+ 3351
+ } else if v == "3352" {
+ 3352
+ } else if v == "3353" {
+ 3353
+ } else if v == "3354" {
+ 3354
+ } else if v == "3355" {
+ 3355
+ } else if v == "3356" {
+ 3356
+ } else if v == "3357" {
+ 3357
+ } else if v == "3358" {
+ 3358
+ } else if v == "3359" {
+ 3359
+ } else if v == "3360" {
+ 3360
+ } else if v == "3361" {
+ 3361
+ } else if v == "3362" {
+ 3362
+ } else if v == "3363" {
+ 3363
+ } else if v == "3364" {
+ 3364
+ } else if v == "3365" {
+ 3365
+ } else if v == "3366" {
+ 3366
+ } else if v == "3367" {
+ 3367
+ } else if v == "3368" {
+ 3368
+ } else if v == "3369" {
+ 3369
+ } else if v == "3370" {
+ 3370
+ } else if v == "3371" {
+ 3371
+ } else if v == "3372" {
+ 3372
+ } else if v == "3373" {
+ 3373
+ } else if v == "3374" {
+ 3374
+ } else if v == "3375" {
+ 3375
+ } else if v == "3376" {
+ 3376
+ } else if v == "3377" {
+ 3377
+ } else if v == "3378" {
+ 3378
+ } else if v == "3379" {
+ 3379
+ } else if v == "3380" {
+ 3380
+ } else if v == "3381" {
+ 3381
+ } else if v == "3382" {
+ 3382
+ } else if v == "3383" {
+ 3383
+ } else if v == "3384" {
+ 3384
+ } else if v == "3385" {
+ 3385
+ } else if v == "3386" {
+ 3386
+ } else if v == "3387" {
+ 3387
+ } else if v == "3388" {
+ 3388
+ } else if v == "3389" {
+ 3389
+ } else if v == "3390" {
+ 3390
+ } else if v == "3391" {
+ 3391
+ } else if v == "3392" {
+ 3392
+ } else if v == "3393" {
+ 3393
+ } else if v == "3394" {
+ 3394
+ } else if v == "3395" {
+ 3395
+ } else if v == "3396" {
+ 3396
+ } else if v == "3397" {
+ 3397
+ } else if v == "3398" {
+ 3398
+ } else if v == "3399" {
+ 3399
+ } else if v == "3400" {
+ 3400
+ } else if v == "3401" {
+ 3401
+ } else if v == "3402" {
+ 3402
+ } else if v == "3403" {
+ 3403
+ } else if v == "3404" {
+ 3404
+ } else if v == "3405" {
+ 3405
+ } else if v == "3406" {
+ 3406
+ } else if v == "3407" {
+ 3407
+ } else if v == "3408" {
+ 3408
+ } else if v == "3409" {
+ 3409
+ } else if v == "3410" {
+ 3410
+ } else if v == "3411" {
+ 3411
+ } else if v == "3412" {
+ 3412
+ } else if v == "3413" {
+ 3413
+ } else if v == "3414" {
+ 3414
+ } else if v == "3415" {
+ 3415
+ } else if v == "3416" {
+ 3416
+ } else if v == "3417" {
+ 3417
+ } else if v == "3418" {
+ 3418
+ } else if v == "3419" {
+ 3419
+ } else if v == "3420" {
+ 3420
+ } else if v == "3421" {
+ 3421
+ } else if v == "3422" {
+ 3422
+ } else if v == "3423" {
+ 3423
+ } else if v == "3424" {
+ 3424
+ } else if v == "3425" {
+ 3425
+ } else if v == "3426" {
+ 3426
+ } else if v == "3427" {
+ 3427
+ } else if v == "3428" {
+ 3428
+ } else if v == "3429" {
+ 3429
+ } else if v == "3430" {
+ 3430
+ } else if v == "3431" {
+ 3431
+ } else if v == "3432" {
+ 3432
+ } else if v == "3433" {
+ 3433
+ } else if v == "3434" {
+ 3434
+ } else if v == "3435" {
+ 3435
+ } else if v == "3436" {
+ 3436
+ } else if v == "3437" {
+ 3437
+ } else if v == "3438" {
+ 3438
+ } else if v == "3439" {
+ 3439
+ } else if v == "3440" {
+ 3440
+ } else if v == "3441" {
+ 3441
+ } else if v == "3442" {
+ 3442
+ } else if v == "3443" {
+ 3443
+ } else if v == "3444" {
+ 3444
+ } else if v == "3445" {
+ 3445
+ } else if v == "3446" {
+ 3446
+ } else if v == "3447" {
+ 3447
+ } else if v == "3448" {
+ 3448
+ } else if v == "3449" {
+ 3449
+ } else if v == "3450" {
+ 3450
+ } else if v == "3451" {
+ 3451
+ } else if v == "3452" {
+ 3452
+ } else if v == "3453" {
+ 3453
+ } else if v == "3454" {
+ 3454
+ } else if v == "3455" {
+ 3455
+ } else if v == "3456" {
+ 3456
+ } else if v == "3457" {
+ 3457
+ } else if v == "3458" {
+ 3458
+ } else if v == "3459" {
+ 3459
+ } else if v == "3460" {
+ 3460
+ } else if v == "3461" {
+ 3461
+ } else if v == "3462" {
+ 3462
+ } else if v == "3463" {
+ 3463
+ } else if v == "3464" {
+ 3464
+ } else if v == "3465" {
+ 3465
+ } else if v == "3466" {
+ 3466
+ } else if v == "3467" {
+ 3467
+ } else if v == "3468" {
+ 3468
+ } else if v == "3469" {
+ 3469
+ } else if v == "3470" {
+ 3470
+ } else if v == "3471" {
+ 3471
+ } else if v == "3472" {
+ 3472
+ } else if v == "3473" {
+ 3473
+ } else if v == "3474" {
+ 3474
+ } else if v == "3475" {
+ 3475
+ } else if v == "3476" {
+ 3476
+ } else if v == "3477" {
+ 3477
+ } else if v == "3478" {
+ 3478
+ } else if v == "3479" {
+ 3479
+ } else if v == "3480" {
+ 3480
+ } else if v == "3481" {
+ 3481
+ } else if v == "3482" {
+ 3482
+ } else if v == "3483" {
+ 3483
+ } else if v == "3484" {
+ 3484
+ } else if v == "3485" {
+ 3485
+ } else if v == "3486" {
+ 3486
+ } else if v == "3487" {
+ 3487
+ } else if v == "3488" {
+ 3488
+ } else if v == "3489" {
+ 3489
+ } else if v == "3490" {
+ 3490
+ } else if v == "3491" {
+ 3491
+ } else if v == "3492" {
+ 3492
+ } else if v == "3493" {
+ 3493
+ } else if v == "3494" {
+ 3494
+ } else if v == "3495" {
+ 3495
+ } else if v == "3496" {
+ 3496
+ } else if v == "3497" {
+ 3497
+ } else if v == "3498" {
+ 3498
+ } else if v == "3499" {
+ 3499
+ } else if v == "3500" {
+ 3500
+ } else if v == "3501" {
+ 3501
+ } else if v == "3502" {
+ 3502
+ } else if v == "3503" {
+ 3503
+ } else if v == "3504" {
+ 3504
+ } else if v == "3505" {
+ 3505
+ } else if v == "3506" {
+ 3506
+ } else if v == "3507" {
+ 3507
+ } else if v == "3508" {
+ 3508
+ } else if v == "3509" {
+ 3509
+ } else if v == "3510" {
+ 3510
+ } else if v == "3511" {
+ 3511
+ } else if v == "3512" {
+ 3512
+ } else if v == "3513" {
+ 3513
+ } else if v == "3514" {
+ 3514
+ } else if v == "3515" {
+ 3515
+ } else if v == "3516" {
+ 3516
+ } else if v == "3517" {
+ 3517
+ } else if v == "3518" {
+ 3518
+ } else if v == "3519" {
+ 3519
+ } else if v == "3520" {
+ 3520
+ } else if v == "3521" {
+ 3521
+ } else if v == "3522" {
+ 3522
+ } else if v == "3523" {
+ 3523
+ } else if v == "3524" {
+ 3524
+ } else if v == "3525" {
+ 3525
+ } else if v == "3526" {
+ 3526
+ } else if v == "3527" {
+ 3527
+ } else if v == "3528" {
+ 3528
+ } else if v == "3529" {
+ 3529
+ } else if v == "3530" {
+ 3530
+ } else if v == "3531" {
+ 3531
+ } else if v == "3532" {
+ 3532
+ } else if v == "3533" {
+ 3533
+ } else if v == "3534" {
+ 3534
+ } else if v == "3535" {
+ 3535
+ } else if v == "3536" {
+ 3536
+ } else if v == "3537" {
+ 3537
+ } else if v == "3538" {
+ 3538
+ } else if v == "3539" {
+ 3539
+ } else if v == "3540" {
+ 3540
+ } else if v == "3541" {
+ 3541
+ } else if v == "3542" {
+ 3542
+ } else if v == "3543" {
+ 3543
+ } else if v == "3544" {
+ 3544
+ } else if v == "3545" {
+ 3545
+ } else if v == "3546" {
+ 3546
+ } else if v == "3547" {
+ 3547
+ } else if v == "3548" {
+ 3548
+ } else if v == "3549" {
+ 3549
+ } else if v == "3550" {
+ 3550
+ } else if v == "3551" {
+ 3551
+ } else if v == "3552" {
+ 3552
+ } else if v == "3553" {
+ 3553
+ } else if v == "3554" {
+ 3554
+ } else if v == "3555" {
+ 3555
+ } else if v == "3556" {
+ 3556
+ } else if v == "3557" {
+ 3557
+ } else if v == "3558" {
+ 3558
+ } else if v == "3559" {
+ 3559
+ } else if v == "3560" {
+ 3560
+ } else if v == "3561" {
+ 3561
+ } else if v == "3562" {
+ 3562
+ } else if v == "3563" {
+ 3563
+ } else if v == "3564" {
+ 3564
+ } else if v == "3565" {
+ 3565
+ } else if v == "3566" {
+ 3566
+ } else if v == "3567" {
+ 3567
+ } else if v == "3568" {
+ 3568
+ } else if v == "3569" {
+ 3569
+ } else if v == "3570" {
+ 3570
+ } else if v == "3571" {
+ 3571
+ } else if v == "3572" {
+ 3572
+ } else if v == "3573" {
+ 3573
+ } else if v == "3574" {
+ 3574
+ } else if v == "3575" {
+ 3575
+ } else if v == "3576" {
+ 3576
+ } else if v == "3577" {
+ 3577
+ } else if v == "3578" {
+ 3578
+ } else if v == "3579" {
+ 3579
+ } else if v == "3580" {
+ 3580
+ } else if v == "3581" {
+ 3581
+ } else if v == "3582" {
+ 3582
+ } else if v == "3583" {
+ 3583
+ } else if v == "3584" {
+ 3584
+ } else if v == "3585" {
+ 3585
+ } else if v == "3586" {
+ 3586
+ } else if v == "3587" {
+ 3587
+ } else if v == "3588" {
+ 3588
+ } else if v == "3589" {
+ 3589
+ } else if v == "3590" {
+ 3590
+ } else if v == "3591" {
+ 3591
+ } else if v == "3592" {
+ 3592
+ } else if v == "3593" {
+ 3593
+ } else if v == "3594" {
+ 3594
+ } else if v == "3595" {
+ 3595
+ } else if v == "3596" {
+ 3596
+ } else if v == "3597" {
+ 3597
+ } else if v == "3598" {
+ 3598
+ } else if v == "3599" {
+ 3599
+ } else if v == "3600" {
+ 3600
+ } else if v == "3601" {
+ 3601
+ } else if v == "3602" {
+ 3602
+ } else if v == "3603" {
+ 3603
+ } else if v == "3604" {
+ 3604
+ } else if v == "3605" {
+ 3605
+ } else if v == "3606" {
+ 3606
+ } else if v == "3607" {
+ 3607
+ } else if v == "3608" {
+ 3608
+ } else if v == "3609" {
+ 3609
+ } else if v == "3610" {
+ 3610
+ } else if v == "3611" {
+ 3611
+ } else if v == "3612" {
+ 3612
+ } else if v == "3613" {
+ 3613
+ } else if v == "3614" {
+ 3614
+ } else if v == "3615" {
+ 3615
+ } else if v == "3616" {
+ 3616
+ } else if v == "3617" {
+ 3617
+ } else if v == "3618" {
+ 3618
+ } else if v == "3619" {
+ 3619
+ } else if v == "3620" {
+ 3620
+ } else if v == "3621" {
+ 3621
+ } else if v == "3622" {
+ 3622
+ } else if v == "3623" {
+ 3623
+ } else if v == "3624" {
+ 3624
+ } else if v == "3625" {
+ 3625
+ } else if v == "3626" {
+ 3626
+ } else if v == "3627" {
+ 3627
+ } else if v == "3628" {
+ 3628
+ } else if v == "3629" {
+ 3629
+ } else if v == "3630" {
+ 3630
+ } else if v == "3631" {
+ 3631
+ } else if v == "3632" {
+ 3632
+ } else if v == "3633" {
+ 3633
+ } else if v == "3634" {
+ 3634
+ } else if v == "3635" {
+ 3635
+ } else if v == "3636" {
+ 3636
+ } else if v == "3637" {
+ 3637
+ } else if v == "3638" {
+ 3638
+ } else if v == "3639" {
+ 3639
+ } else if v == "3640" {
+ 3640
+ } else if v == "3641" {
+ 3641
+ } else if v == "3642" {
+ 3642
+ } else if v == "3643" {
+ 3643
+ } else if v == "3644" {
+ 3644
+ } else if v == "3645" {
+ 3645
+ } else if v == "3646" {
+ 3646
+ } else if v == "3647" {
+ 3647
+ } else if v == "3648" {
+ 3648
+ } else if v == "3649" {
+ 3649
+ } else if v == "3650" {
+ 3650
+ } else if v == "3651" {
+ 3651
+ } else if v == "3652" {
+ 3652
+ } else if v == "3653" {
+ 3653
+ } else if v == "3654" {
+ 3654
+ } else if v == "3655" {
+ 3655
+ } else if v == "3656" {
+ 3656
+ } else if v == "3657" {
+ 3657
+ } else if v == "3658" {
+ 3658
+ } else if v == "3659" {
+ 3659
+ } else if v == "3660" {
+ 3660
+ } else if v == "3661" {
+ 3661
+ } else if v == "3662" {
+ 3662
+ } else if v == "3663" {
+ 3663
+ } else if v == "3664" {
+ 3664
+ } else if v == "3665" {
+ 3665
+ } else if v == "3666" {
+ 3666
+ } else if v == "3667" {
+ 3667
+ } else if v == "3668" {
+ 3668
+ } else if v == "3669" {
+ 3669
+ } else if v == "3670" {
+ 3670
+ } else if v == "3671" {
+ 3671
+ } else if v == "3672" {
+ 3672
+ } else if v == "3673" {
+ 3673
+ } else if v == "3674" {
+ 3674
+ } else if v == "3675" {
+ 3675
+ } else if v == "3676" {
+ 3676
+ } else if v == "3677" {
+ 3677
+ } else if v == "3678" {
+ 3678
+ } else if v == "3679" {
+ 3679
+ } else if v == "3680" {
+ 3680
+ } else if v == "3681" {
+ 3681
+ } else if v == "3682" {
+ 3682
+ } else if v == "3683" {
+ 3683
+ } else if v == "3684" {
+ 3684
+ } else if v == "3685" {
+ 3685
+ } else if v == "3686" {
+ 3686
+ } else if v == "3687" {
+ 3687
+ } else if v == "3688" {
+ 3688
+ } else if v == "3689" {
+ 3689
+ } else if v == "3690" {
+ 3690
+ } else if v == "3691" {
+ 3691
+ } else if v == "3692" {
+ 3692
+ } else if v == "3693" {
+ 3693
+ } else if v == "3694" {
+ 3694
+ } else if v == "3695" {
+ 3695
+ } else if v == "3696" {
+ 3696
+ } else if v == "3697" {
+ 3697
+ } else if v == "3698" {
+ 3698
+ } else if v == "3699" {
+ 3699
+ } else if v == "3700" {
+ 3700
+ } else if v == "3701" {
+ 3701
+ } else if v == "3702" {
+ 3702
+ } else if v == "3703" {
+ 3703
+ } else if v == "3704" {
+ 3704
+ } else if v == "3705" {
+ 3705
+ } else if v == "3706" {
+ 3706
+ } else if v == "3707" {
+ 3707
+ } else if v == "3708" {
+ 3708
+ } else if v == "3709" {
+ 3709
+ } else if v == "3710" {
+ 3710
+ } else if v == "3711" {
+ 3711
+ } else if v == "3712" {
+ 3712
+ } else if v == "3713" {
+ 3713
+ } else if v == "3714" {
+ 3714
+ } else if v == "3715" {
+ 3715
+ } else if v == "3716" {
+ 3716
+ } else if v == "3717" {
+ 3717
+ } else if v == "3718" {
+ 3718
+ } else if v == "3719" {
+ 3719
+ } else if v == "3720" {
+ 3720
+ } else if v == "3721" {
+ 3721
+ } else if v == "3722" {
+ 3722
+ } else if v == "3723" {
+ 3723
+ } else if v == "3724" {
+ 3724
+ } else if v == "3725" {
+ 3725
+ } else if v == "3726" {
+ 3726
+ } else if v == "3727" {
+ 3727
+ } else if v == "3728" {
+ 3728
+ } else if v == "3729" {
+ 3729
+ } else if v == "3730" {
+ 3730
+ } else if v == "3731" {
+ 3731
+ } else if v == "3732" {
+ 3732
+ } else if v == "3733" {
+ 3733
+ } else if v == "3734" {
+ 3734
+ } else if v == "3735" {
+ 3735
+ } else if v == "3736" {
+ 3736
+ } else if v == "3737" {
+ 3737
+ } else if v == "3738" {
+ 3738
+ } else if v == "3739" {
+ 3739
+ } else if v == "3740" {
+ 3740
+ } else if v == "3741" {
+ 3741
+ } else if v == "3742" {
+ 3742
+ } else if v == "3743" {
+ 3743
+ } else if v == "3744" {
+ 3744
+ } else if v == "3745" {
+ 3745
+ } else if v == "3746" {
+ 3746
+ } else if v == "3747" {
+ 3747
+ } else if v == "3748" {
+ 3748
+ } else if v == "3749" {
+ 3749
+ } else if v == "3750" {
+ 3750
+ } else if v == "3751" {
+ 3751
+ } else if v == "3752" {
+ 3752
+ } else if v == "3753" {
+ 3753
+ } else if v == "3754" {
+ 3754
+ } else if v == "3755" {
+ 3755
+ } else if v == "3756" {
+ 3756
+ } else if v == "3757" {
+ 3757
+ } else if v == "3758" {
+ 3758
+ } else if v == "3759" {
+ 3759
+ } else if v == "3760" {
+ 3760
+ } else if v == "3761" {
+ 3761
+ } else if v == "3762" {
+ 3762
+ } else if v == "3763" {
+ 3763
+ } else if v == "3764" {
+ 3764
+ } else if v == "3765" {
+ 3765
+ } else if v == "3766" {
+ 3766
+ } else if v == "3767" {
+ 3767
+ } else if v == "3768" {
+ 3768
+ } else if v == "3769" {
+ 3769
+ } else if v == "3770" {
+ 3770
+ } else if v == "3771" {
+ 3771
+ } else if v == "3772" {
+ 3772
+ } else if v == "3773" {
+ 3773
+ } else if v == "3774" {
+ 3774
+ } else if v == "3775" {
+ 3775
+ } else if v == "3776" {
+ 3776
+ } else if v == "3777" {
+ 3777
+ } else if v == "3778" {
+ 3778
+ } else if v == "3779" {
+ 3779
+ } else if v == "3780" {
+ 3780
+ } else if v == "3781" {
+ 3781
+ } else if v == "3782" {
+ 3782
+ } else if v == "3783" {
+ 3783
+ } else if v == "3784" {
+ 3784
+ } else if v == "3785" {
+ 3785
+ } else if v == "3786" {
+ 3786
+ } else if v == "3787" {
+ 3787
+ } else if v == "3788" {
+ 3788
+ } else if v == "3789" {
+ 3789
+ } else if v == "3790" {
+ 3790
+ } else if v == "3791" {
+ 3791
+ } else if v == "3792" {
+ 3792
+ } else if v == "3793" {
+ 3793
+ } else if v == "3794" {
+ 3794
+ } else if v == "3795" {
+ 3795
+ } else if v == "3796" {
+ 3796
+ } else if v == "3797" {
+ 3797
+ } else if v == "3798" {
+ 3798
+ } else if v == "3799" {
+ 3799
+ } else if v == "3800" {
+ 3800
+ } else if v == "3801" {
+ 3801
+ } else if v == "3802" {
+ 3802
+ } else if v == "3803" {
+ 3803
+ } else if v == "3804" {
+ 3804
+ } else if v == "3805" {
+ 3805
+ } else if v == "3806" {
+ 3806
+ } else if v == "3807" {
+ 3807
+ } else if v == "3808" {
+ 3808
+ } else if v == "3809" {
+ 3809
+ } else if v == "3810" {
+ 3810
+ } else if v == "3811" {
+ 3811
+ } else if v == "3812" {
+ 3812
+ } else if v == "3813" {
+ 3813
+ } else if v == "3814" {
+ 3814
+ } else if v == "3815" {
+ 3815
+ } else if v == "3816" {
+ 3816
+ } else if v == "3817" {
+ 3817
+ } else if v == "3818" {
+ 3818
+ } else if v == "3819" {
+ 3819
+ } else if v == "3820" {
+ 3820
+ } else if v == "3821" {
+ 3821
+ } else if v == "3822" {
+ 3822
+ } else if v == "3823" {
+ 3823
+ } else if v == "3824" {
+ 3824
+ } else if v == "3825" {
+ 3825
+ } else if v == "3826" {
+ 3826
+ } else if v == "3827" {
+ 3827
+ } else if v == "3828" {
+ 3828
+ } else if v == "3829" {
+ 3829
+ } else if v == "3830" {
+ 3830
+ } else if v == "3831" {
+ 3831
+ } else if v == "3832" {
+ 3832
+ } else if v == "3833" {
+ 3833
+ } else if v == "3834" {
+ 3834
+ } else if v == "3835" {
+ 3835
+ } else if v == "3836" {
+ 3836
+ } else if v == "3837" {
+ 3837
+ } else if v == "3838" {
+ 3838
+ } else if v == "3839" {
+ 3839
+ } else if v == "3840" {
+ 3840
+ } else if v == "3841" {
+ 3841
+ } else if v == "3842" {
+ 3842
+ } else if v == "3843" {
+ 3843
+ } else if v == "3844" {
+ 3844
+ } else if v == "3845" {
+ 3845
+ } else if v == "3846" {
+ 3846
+ } else if v == "3847" {
+ 3847
+ } else if v == "3848" {
+ 3848
+ } else if v == "3849" {
+ 3849
+ } else if v == "3850" {
+ 3850
+ } else if v == "3851" {
+ 3851
+ } else if v == "3852" {
+ 3852
+ } else if v == "3853" {
+ 3853
+ } else if v == "3854" {
+ 3854
+ } else if v == "3855" {
+ 3855
+ } else if v == "3856" {
+ 3856
+ } else if v == "3857" {
+ 3857
+ } else if v == "3858" {
+ 3858
+ } else if v == "3859" {
+ 3859
+ } else if v == "3860" {
+ 3860
+ } else if v == "3861" {
+ 3861
+ } else if v == "3862" {
+ 3862
+ } else if v == "3863" {
+ 3863
+ } else if v == "3864" {
+ 3864
+ } else if v == "3865" {
+ 3865
+ } else if v == "3866" {
+ 3866
+ } else if v == "3867" {
+ 3867
+ } else if v == "3868" {
+ 3868
+ } else if v == "3869" {
+ 3869
+ } else if v == "3870" {
+ 3870
+ } else if v == "3871" {
+ 3871
+ } else if v == "3872" {
+ 3872
+ } else if v == "3873" {
+ 3873
+ } else if v == "3874" {
+ 3874
+ } else if v == "3875" {
+ 3875
+ } else if v == "3876" {
+ 3876
+ } else if v == "3877" {
+ 3877
+ } else if v == "3878" {
+ 3878
+ } else if v == "3879" {
+ 3879
+ } else if v == "3880" {
+ 3880
+ } else if v == "3881" {
+ 3881
+ } else if v == "3882" {
+ 3882
+ } else if v == "3883" {
+ 3883
+ } else if v == "3884" {
+ 3884
+ } else if v == "3885" {
+ 3885
+ } else if v == "3886" {
+ 3886
+ } else if v == "3887" {
+ 3887
+ } else if v == "3888" {
+ 3888
+ } else if v == "3889" {
+ 3889
+ } else if v == "3890" {
+ 3890
+ } else if v == "3891" {
+ 3891
+ } else if v == "3892" {
+ 3892
+ } else if v == "3893" {
+ 3893
+ } else if v == "3894" {
+ 3894
+ } else if v == "3895" {
+ 3895
+ } else if v == "3896" {
+ 3896
+ } else if v == "3897" {
+ 3897
+ } else if v == "3898" {
+ 3898
+ } else if v == "3899" {
+ 3899
+ } else if v == "3900" {
+ 3900
+ } else if v == "3901" {
+ 3901
+ } else if v == "3902" {
+ 3902
+ } else if v == "3903" {
+ 3903
+ } else if v == "3904" {
+ 3904
+ } else if v == "3905" {
+ 3905
+ } else if v == "3906" {
+ 3906
+ } else if v == "3907" {
+ 3907
+ } else if v == "3908" {
+ 3908
+ } else if v == "3909" {
+ 3909
+ } else if v == "3910" {
+ 3910
+ } else if v == "3911" {
+ 3911
+ } else if v == "3912" {
+ 3912
+ } else if v == "3913" {
+ 3913
+ } else if v == "3914" {
+ 3914
+ } else if v == "3915" {
+ 3915
+ } else if v == "3916" {
+ 3916
+ } else if v == "3917" {
+ 3917
+ } else if v == "3918" {
+ 3918
+ } else if v == "3919" {
+ 3919
+ } else if v == "3920" {
+ 3920
+ } else if v == "3921" {
+ 3921
+ } else if v == "3922" {
+ 3922
+ } else if v == "3923" {
+ 3923
+ } else if v == "3924" {
+ 3924
+ } else if v == "3925" {
+ 3925
+ } else if v == "3926" {
+ 3926
+ } else if v == "3927" {
+ 3927
+ } else if v == "3928" {
+ 3928
+ } else if v == "3929" {
+ 3929
+ } else if v == "3930" {
+ 3930
+ } else if v == "3931" {
+ 3931
+ } else if v == "3932" {
+ 3932
+ } else if v == "3933" {
+ 3933
+ } else if v == "3934" {
+ 3934
+ } else if v == "3935" {
+ 3935
+ } else if v == "3936" {
+ 3936
+ } else if v == "3937" {
+ 3937
+ } else if v == "3938" {
+ 3938
+ } else if v == "3939" {
+ 3939
+ } else if v == "3940" {
+ 3940
+ } else if v == "3941" {
+ 3941
+ } else if v == "3942" {
+ 3942
+ } else if v == "3943" {
+ 3943
+ } else if v == "3944" {
+ 3944
+ } else if v == "3945" {
+ 3945
+ } else if v == "3946" {
+ 3946
+ } else if v == "3947" {
+ 3947
+ } else if v == "3948" {
+ 3948
+ } else if v == "3949" {
+ 3949
+ } else if v == "3950" {
+ 3950
+ } else if v == "3951" {
+ 3951
+ } else if v == "3952" {
+ 3952
+ } else if v == "3953" {
+ 3953
+ } else if v == "3954" {
+ 3954
+ } else if v == "3955" {
+ 3955
+ } else if v == "3956" {
+ 3956
+ } else if v == "3957" {
+ 3957
+ } else if v == "3958" {
+ 3958
+ } else if v == "3959" {
+ 3959
+ } else if v == "3960" {
+ 3960
+ } else if v == "3961" {
+ 3961
+ } else if v == "3962" {
+ 3962
+ } else if v == "3963" {
+ 3963
+ } else if v == "3964" {
+ 3964
+ } else if v == "3965" {
+ 3965
+ } else if v == "3966" {
+ 3966
+ } else if v == "3967" {
+ 3967
+ } else if v == "3968" {
+ 3968
+ } else if v == "3969" {
+ 3969
+ } else if v == "3970" {
+ 3970
+ } else if v == "3971" {
+ 3971
+ } else if v == "3972" {
+ 3972
+ } else if v == "3973" {
+ 3973
+ } else if v == "3974" {
+ 3974
+ } else if v == "3975" {
+ 3975
+ } else if v == "3976" {
+ 3976
+ } else if v == "3977" {
+ 3977
+ } else if v == "3978" {
+ 3978
+ } else if v == "3979" {
+ 3979
+ } else if v == "3980" {
+ 3980
+ } else if v == "3981" {
+ 3981
+ } else if v == "3982" {
+ 3982
+ } else if v == "3983" {
+ 3983
+ } else if v == "3984" {
+ 3984
+ } else if v == "3985" {
+ 3985
+ } else if v == "3986" {
+ 3986
+ } else if v == "3987" {
+ 3987
+ } else if v == "3988" {
+ 3988
+ } else if v == "3989" {
+ 3989
+ } else if v == "3990" {
+ 3990
+ } else if v == "3991" {
+ 3991
+ } else if v == "3992" {
+ 3992
+ } else if v == "3993" {
+ 3993
+ } else if v == "3994" {
+ 3994
+ } else if v == "3995" {
+ 3995
+ } else if v == "3996" {
+ 3996
+ } else if v == "3997" {
+ 3997
+ } else if v == "3998" {
+ 3998
+ } else if v == "3999" {
+ 3999
+ } else if v == "4000" {
+ 4000
+ } else if v == "4001" {
+ 4001
+ } else if v == "4002" {
+ 4002
+ } else if v == "4003" {
+ 4003
+ } else if v == "4004" {
+ 4004
+ } else if v == "4005" {
+ 4005
+ } else if v == "4006" {
+ 4006
+ } else if v == "4007" {
+ 4007
+ } else if v == "4008" {
+ 4008
+ } else if v == "4009" {
+ 4009
+ } else if v == "4010" {
+ 4010
+ } else if v == "4011" {
+ 4011
+ } else if v == "4012" {
+ 4012
+ } else if v == "4013" {
+ 4013
+ } else if v == "4014" {
+ 4014
+ } else if v == "4015" {
+ 4015
+ } else if v == "4016" {
+ 4016
+ } else if v == "4017" {
+ 4017
+ } else if v == "4018" {
+ 4018
+ } else if v == "4019" {
+ 4019
+ } else if v == "4020" {
+ 4020
+ } else if v == "4021" {
+ 4021
+ } else if v == "4022" {
+ 4022
+ } else if v == "4023" {
+ 4023
+ } else if v == "4024" {
+ 4024
+ } else if v == "4025" {
+ 4025
+ } else if v == "4026" {
+ 4026
+ } else if v == "4027" {
+ 4027
+ } else if v == "4028" {
+ 4028
+ } else if v == "4029" {
+ 4029
+ } else if v == "4030" {
+ 4030
+ } else if v == "4031" {
+ 4031
+ } else if v == "4032" {
+ 4032
+ } else if v == "4033" {
+ 4033
+ } else if v == "4034" {
+ 4034
+ } else if v == "4035" {
+ 4035
+ } else if v == "4036" {
+ 4036
+ } else if v == "4037" {
+ 4037
+ } else if v == "4038" {
+ 4038
+ } else if v == "4039" {
+ 4039
+ } else if v == "4040" {
+ 4040
+ } else if v == "4041" {
+ 4041
+ } else if v == "4042" {
+ 4042
+ } else if v == "4043" {
+ 4043
+ } else if v == "4044" {
+ 4044
+ } else if v == "4045" {
+ 4045
+ } else if v == "4046" {
+ 4046
+ } else if v == "4047" {
+ 4047
+ } else if v == "4048" {
+ 4048
+ } else if v == "4049" {
+ 4049
+ } else if v == "4050" {
+ 4050
+ } else if v == "4051" {
+ 4051
+ } else if v == "4052" {
+ 4052
+ } else if v == "4053" {
+ 4053
+ } else if v == "4054" {
+ 4054
+ } else if v == "4055" {
+ 4055
+ } else if v == "4056" {
+ 4056
+ } else if v == "4057" {
+ 4057
+ } else if v == "4058" {
+ 4058
+ } else if v == "4059" {
+ 4059
+ } else if v == "4060" {
+ 4060
+ } else if v == "4061" {
+ 4061
+ } else if v == "4062" {
+ 4062
+ } else if v == "4063" {
+ 4063
+ } else if v == "4064" {
+ 4064
+ } else if v == "4065" {
+ 4065
+ } else if v == "4066" {
+ 4066
+ } else if v == "4067" {
+ 4067
+ } else if v == "4068" {
+ 4068
+ } else if v == "4069" {
+ 4069
+ } else if v == "4070" {
+ 4070
+ } else if v == "4071" {
+ 4071
+ } else if v == "4072" {
+ 4072
+ } else if v == "4073" {
+ 4073
+ } else if v == "4074" {
+ 4074
+ } else if v == "4075" {
+ 4075
+ } else if v == "4076" {
+ 4076
+ } else if v == "4077" {
+ 4077
+ } else if v == "4078" {
+ 4078
+ } else if v == "4079" {
+ 4079
+ } else if v == "4080" {
+ 4080
+ } else if v == "4081" {
+ 4081
+ } else if v == "4082" {
+ 4082
+ } else if v == "4083" {
+ 4083
+ } else if v == "4084" {
+ 4084
+ } else if v == "4085" {
+ 4085
+ } else if v == "4086" {
+ 4086
+ } else if v == "4087" {
+ 4087
+ } else if v == "4088" {
+ 4088
+ } else if v == "4089" {
+ 4089
+ } else if v == "4090" {
+ 4090
+ } else if v == "4091" {
+ 4091
+ } else if v == "4092" {
+ 4092
+ } else if v == "4093" {
+ 4093
+ } else if v == "4094" {
+ 4094
+ } else if v == "4095" {
+ 4095
+ } else if v == "4096" {
+ 4096
+ } else if v == "4097" {
+ 4097
+ } else if v == "4098" {
+ 4098
+ } else if v == "4099" {
+ 4099
+ } else if v == "4100" {
+ 4100
+ } else if v == "4101" {
+ 4101
+ } else if v == "4102" {
+ 4102
+ } else if v == "4103" {
+ 4103
+ } else if v == "4104" {
+ 4104
+ } else if v == "4105" {
+ 4105
+ } else if v == "4106" {
+ 4106
+ } else if v == "4107" {
+ 4107
+ } else if v == "4108" {
+ 4108
+ } else if v == "4109" {
+ 4109
+ } else if v == "4110" {
+ 4110
+ } else if v == "4111" {
+ 4111
+ } else if v == "4112" {
+ 4112
+ } else if v == "4113" {
+ 4113
+ } else if v == "4114" {
+ 4114
+ } else if v == "4115" {
+ 4115
+ } else if v == "4116" {
+ 4116
+ } else if v == "4117" {
+ 4117
+ } else if v == "4118" {
+ 4118
+ } else if v == "4119" {
+ 4119
+ } else if v == "4120" {
+ 4120
+ } else if v == "4121" {
+ 4121
+ } else if v == "4122" {
+ 4122
+ } else if v == "4123" {
+ 4123
+ } else if v == "4124" {
+ 4124
+ } else if v == "4125" {
+ 4125
+ } else if v == "4126" {
+ 4126
+ } else if v == "4127" {
+ 4127
+ } else if v == "4128" {
+ 4128
+ } else if v == "4129" {
+ 4129
+ } else if v == "4130" {
+ 4130
+ } else if v == "4131" {
+ 4131
+ } else if v == "4132" {
+ 4132
+ } else if v == "4133" {
+ 4133
+ } else if v == "4134" {
+ 4134
+ } else if v == "4135" {
+ 4135
+ } else if v == "4136" {
+ 4136
+ } else if v == "4137" {
+ 4137
+ } else if v == "4138" {
+ 4138
+ } else if v == "4139" {
+ 4139
+ } else if v == "4140" {
+ 4140
+ } else if v == "4141" {
+ 4141
+ } else if v == "4142" {
+ 4142
+ } else if v == "4143" {
+ 4143
+ } else if v == "4144" {
+ 4144
+ } else if v == "4145" {
+ 4145
+ } else if v == "4146" {
+ 4146
+ } else if v == "4147" {
+ 4147
+ } else if v == "4148" {
+ 4148
+ } else if v == "4149" {
+ 4149
+ } else if v == "4150" {
+ 4150
+ } else if v == "4151" {
+ 4151
+ } else if v == "4152" {
+ 4152
+ } else if v == "4153" {
+ 4153
+ } else if v == "4154" {
+ 4154
+ } else if v == "4155" {
+ 4155
+ } else if v == "4156" {
+ 4156
+ } else if v == "4157" {
+ 4157
+ } else if v == "4158" {
+ 4158
+ } else if v == "4159" {
+ 4159
+ } else if v == "4160" {
+ 4160
+ } else if v == "4161" {
+ 4161
+ } else if v == "4162" {
+ 4162
+ } else if v == "4163" {
+ 4163
+ } else if v == "4164" {
+ 4164
+ } else if v == "4165" {
+ 4165
+ } else if v == "4166" {
+ 4166
+ } else if v == "4167" {
+ 4167
+ } else if v == "4168" {
+ 4168
+ } else if v == "4169" {
+ 4169
+ } else if v == "4170" {
+ 4170
+ } else if v == "4171" {
+ 4171
+ } else if v == "4172" {
+ 4172
+ } else if v == "4173" {
+ 4173
+ } else if v == "4174" {
+ 4174
+ } else if v == "4175" {
+ 4175
+ } else if v == "4176" {
+ 4176
+ } else if v == "4177" {
+ 4177
+ } else if v == "4178" {
+ 4178
+ } else if v == "4179" {
+ 4179
+ } else if v == "4180" {
+ 4180
+ } else if v == "4181" {
+ 4181
+ } else if v == "4182" {
+ 4182
+ } else if v == "4183" {
+ 4183
+ } else if v == "4184" {
+ 4184
+ } else if v == "4185" {
+ 4185
+ } else if v == "4186" {
+ 4186
+ } else if v == "4187" {
+ 4187
+ } else if v == "4188" {
+ 4188
+ } else if v == "4189" {
+ 4189
+ } else if v == "4190" {
+ 4190
+ } else if v == "4191" {
+ 4191
+ } else if v == "4192" {
+ 4192
+ } else if v == "4193" {
+ 4193
+ } else if v == "4194" {
+ 4194
+ } else if v == "4195" {
+ 4195
+ } else if v == "4196" {
+ 4196
+ } else if v == "4197" {
+ 4197
+ } else if v == "4198" {
+ 4198
+ } else if v == "4199" {
+ 4199
+ } else if v == "4200" {
+ 4200
+ } else if v == "4201" {
+ 4201
+ } else if v == "4202" {
+ 4202
+ } else if v == "4203" {
+ 4203
+ } else if v == "4204" {
+ 4204
+ } else if v == "4205" {
+ 4205
+ } else if v == "4206" {
+ 4206
+ } else if v == "4207" {
+ 4207
+ } else if v == "4208" {
+ 4208
+ } else if v == "4209" {
+ 4209
+ } else if v == "4210" {
+ 4210
+ } else if v == "4211" {
+ 4211
+ } else if v == "4212" {
+ 4212
+ } else if v == "4213" {
+ 4213
+ } else if v == "4214" {
+ 4214
+ } else if v == "4215" {
+ 4215
+ } else if v == "4216" {
+ 4216
+ } else if v == "4217" {
+ 4217
+ } else if v == "4218" {
+ 4218
+ } else if v == "4219" {
+ 4219
+ } else if v == "4220" {
+ 4220
+ } else if v == "4221" {
+ 4221
+ } else if v == "4222" {
+ 4222
+ } else if v == "4223" {
+ 4223
+ } else if v == "4224" {
+ 4224
+ } else if v == "4225" {
+ 4225
+ } else if v == "4226" {
+ 4226
+ } else if v == "4227" {
+ 4227
+ } else if v == "4228" {
+ 4228
+ } else if v == "4229" {
+ 4229
+ } else if v == "4230" {
+ 4230
+ } else if v == "4231" {
+ 4231
+ } else if v == "4232" {
+ 4232
+ } else if v == "4233" {
+ 4233
+ } else if v == "4234" {
+ 4234
+ } else if v == "4235" {
+ 4235
+ } else if v == "4236" {
+ 4236
+ } else if v == "4237" {
+ 4237
+ } else if v == "4238" {
+ 4238
+ } else if v == "4239" {
+ 4239
+ } else if v == "4240" {
+ 4240
+ } else if v == "4241" {
+ 4241
+ } else if v == "4242" {
+ 4242
+ } else if v == "4243" {
+ 4243
+ } else if v == "4244" {
+ 4244
+ } else if v == "4245" {
+ 4245
+ } else if v == "4246" {
+ 4246
+ } else if v == "4247" {
+ 4247
+ } else if v == "4248" {
+ 4248
+ } else if v == "4249" {
+ 4249
+ } else if v == "4250" {
+ 4250
+ } else if v == "4251" {
+ 4251
+ } else if v == "4252" {
+ 4252
+ } else if v == "4253" {
+ 4253
+ } else if v == "4254" {
+ 4254
+ } else if v == "4255" {
+ 4255
+ } else if v == "4256" {
+ 4256
+ } else if v == "4257" {
+ 4257
+ } else if v == "4258" {
+ 4258
+ } else if v == "4259" {
+ 4259
+ } else if v == "4260" {
+ 4260
+ } else if v == "4261" {
+ 4261
+ } else if v == "4262" {
+ 4262
+ } else if v == "4263" {
+ 4263
+ } else if v == "4264" {
+ 4264
+ } else if v == "4265" {
+ 4265
+ } else if v == "4266" {
+ 4266
+ } else if v == "4267" {
+ 4267
+ } else if v == "4268" {
+ 4268
+ } else if v == "4269" {
+ 4269
+ } else if v == "4270" {
+ 4270
+ } else if v == "4271" {
+ 4271
+ } else if v == "4272" {
+ 4272
+ } else if v == "4273" {
+ 4273
+ } else if v == "4274" {
+ 4274
+ } else if v == "4275" {
+ 4275
+ } else if v == "4276" {
+ 4276
+ } else if v == "4277" {
+ 4277
+ } else if v == "4278" {
+ 4278
+ } else if v == "4279" {
+ 4279
+ } else if v == "4280" {
+ 4280
+ } else if v == "4281" {
+ 4281
+ } else if v == "4282" {
+ 4282
+ } else if v == "4283" {
+ 4283
+ } else if v == "4284" {
+ 4284
+ } else if v == "4285" {
+ 4285
+ } else if v == "4286" {
+ 4286
+ } else if v == "4287" {
+ 4287
+ } else if v == "4288" {
+ 4288
+ } else if v == "4289" {
+ 4289
+ } else if v == "4290" {
+ 4290
+ } else if v == "4291" {
+ 4291
+ } else if v == "4292" {
+ 4292
+ } else if v == "4293" {
+ 4293
+ } else if v == "4294" {
+ 4294
+ } else if v == "4295" {
+ 4295
+ } else if v == "4296" {
+ 4296
+ } else if v == "4297" {
+ 4297
+ } else if v == "4298" {
+ 4298
+ } else if v == "4299" {
+ 4299
+ } else if v == "4300" {
+ 4300
+ } else if v == "4301" {
+ 4301
+ } else if v == "4302" {
+ 4302
+ } else if v == "4303" {
+ 4303
+ } else if v == "4304" {
+ 4304
+ } else if v == "4305" {
+ 4305
+ } else if v == "4306" {
+ 4306
+ } else if v == "4307" {
+ 4307
+ } else if v == "4308" {
+ 4308
+ } else if v == "4309" {
+ 4309
+ } else if v == "4310" {
+ 4310
+ } else if v == "4311" {
+ 4311
+ } else if v == "4312" {
+ 4312
+ } else if v == "4313" {
+ 4313
+ } else if v == "4314" {
+ 4314
+ } else if v == "4315" {
+ 4315
+ } else if v == "4316" {
+ 4316
+ } else if v == "4317" {
+ 4317
+ } else if v == "4318" {
+ 4318
+ } else if v == "4319" {
+ 4319
+ } else if v == "4320" {
+ 4320
+ } else if v == "4321" {
+ 4321
+ } else if v == "4322" {
+ 4322
+ } else if v == "4323" {
+ 4323
+ } else if v == "4324" {
+ 4324
+ } else if v == "4325" {
+ 4325
+ } else if v == "4326" {
+ 4326
+ } else if v == "4327" {
+ 4327
+ } else if v == "4328" {
+ 4328
+ } else if v == "4329" {
+ 4329
+ } else if v == "4330" {
+ 4330
+ } else if v == "4331" {
+ 4331
+ } else if v == "4332" {
+ 4332
+ } else if v == "4333" {
+ 4333
+ } else if v == "4334" {
+ 4334
+ } else if v == "4335" {
+ 4335
+ } else if v == "4336" {
+ 4336
+ } else if v == "4337" {
+ 4337
+ } else if v == "4338" {
+ 4338
+ } else if v == "4339" {
+ 4339
+ } else if v == "4340" {
+ 4340
+ } else if v == "4341" {
+ 4341
+ } else if v == "4342" {
+ 4342
+ } else if v == "4343" {
+ 4343
+ } else if v == "4344" {
+ 4344
+ } else if v == "4345" {
+ 4345
+ } else if v == "4346" {
+ 4346
+ } else if v == "4347" {
+ 4347
+ } else if v == "4348" {
+ 4348
+ } else if v == "4349" {
+ 4349
+ } else if v == "4350" {
+ 4350
+ } else if v == "4351" {
+ 4351
+ } else if v == "4352" {
+ 4352
+ } else if v == "4353" {
+ 4353
+ } else if v == "4354" {
+ 4354
+ } else if v == "4355" {
+ 4355
+ } else if v == "4356" {
+ 4356
+ } else if v == "4357" {
+ 4357
+ } else if v == "4358" {
+ 4358
+ } else if v == "4359" {
+ 4359
+ } else if v == "4360" {
+ 4360
+ } else if v == "4361" {
+ 4361
+ } else if v == "4362" {
+ 4362
+ } else if v == "4363" {
+ 4363
+ } else if v == "4364" {
+ 4364
+ } else if v == "4365" {
+ 4365
+ } else if v == "4366" {
+ 4366
+ } else if v == "4367" {
+ 4367
+ } else if v == "4368" {
+ 4368
+ } else if v == "4369" {
+ 4369
+ } else if v == "4370" {
+ 4370
+ } else if v == "4371" {
+ 4371
+ } else if v == "4372" {
+ 4372
+ } else if v == "4373" {
+ 4373
+ } else if v == "4374" {
+ 4374
+ } else if v == "4375" {
+ 4375
+ } else if v == "4376" {
+ 4376
+ } else if v == "4377" {
+ 4377
+ } else if v == "4378" {
+ 4378
+ } else if v == "4379" {
+ 4379
+ } else if v == "4380" {
+ 4380
+ } else if v == "4381" {
+ 4381
+ } else if v == "4382" {
+ 4382
+ } else if v == "4383" {
+ 4383
+ } else if v == "4384" {
+ 4384
+ } else if v == "4385" {
+ 4385
+ } else if v == "4386" {
+ 4386
+ } else if v == "4387" {
+ 4387
+ } else if v == "4388" {
+ 4388
+ } else if v == "4389" {
+ 4389
+ } else if v == "4390" {
+ 4390
+ } else if v == "4391" {
+ 4391
+ } else if v == "4392" {
+ 4392
+ } else if v == "4393" {
+ 4393
+ } else if v == "4394" {
+ 4394
+ } else if v == "4395" {
+ 4395
+ } else if v == "4396" {
+ 4396
+ } else if v == "4397" {
+ 4397
+ } else if v == "4398" {
+ 4398
+ } else if v == "4399" {
+ 4399
+ } else if v == "4400" {
+ 4400
+ } else if v == "4401" {
+ 4401
+ } else if v == "4402" {
+ 4402
+ } else if v == "4403" {
+ 4403
+ } else if v == "4404" {
+ 4404
+ } else if v == "4405" {
+ 4405
+ } else if v == "4406" {
+ 4406
+ } else if v == "4407" {
+ 4407
+ } else if v == "4408" {
+ 4408
+ } else if v == "4409" {
+ 4409
+ } else if v == "4410" {
+ 4410
+ } else if v == "4411" {
+ 4411
+ } else if v == "4412" {
+ 4412
+ } else if v == "4413" {
+ 4413
+ } else if v == "4414" {
+ 4414
+ } else if v == "4415" {
+ 4415
+ } else if v == "4416" {
+ 4416
+ } else if v == "4417" {
+ 4417
+ } else if v == "4418" {
+ 4418
+ } else if v == "4419" {
+ 4419
+ } else if v == "4420" {
+ 4420
+ } else if v == "4421" {
+ 4421
+ } else if v == "4422" {
+ 4422
+ } else if v == "4423" {
+ 4423
+ } else if v == "4424" {
+ 4424
+ } else if v == "4425" {
+ 4425
+ } else if v == "4426" {
+ 4426
+ } else if v == "4427" {
+ 4427
+ } else if v == "4428" {
+ 4428
+ } else if v == "4429" {
+ 4429
+ } else if v == "4430" {
+ 4430
+ } else if v == "4431" {
+ 4431
+ } else if v == "4432" {
+ 4432
+ } else if v == "4433" {
+ 4433
+ } else if v == "4434" {
+ 4434
+ } else if v == "4435" {
+ 4435
+ } else if v == "4436" {
+ 4436
+ } else if v == "4437" {
+ 4437
+ } else if v == "4438" {
+ 4438
+ } else if v == "4439" {
+ 4439
+ } else if v == "4440" {
+ 4440
+ } else if v == "4441" {
+ 4441
+ } else if v == "4442" {
+ 4442
+ } else if v == "4443" {
+ 4443
+ } else if v == "4444" {
+ 4444
+ } else if v == "4445" {
+ 4445
+ } else if v == "4446" {
+ 4446
+ } else if v == "4447" {
+ 4447
+ } else if v == "4448" {
+ 4448
+ } else if v == "4449" {
+ 4449
+ } else if v == "4450" {
+ 4450
+ } else if v == "4451" {
+ 4451
+ } else if v == "4452" {
+ 4452
+ } else if v == "4453" {
+ 4453
+ } else if v == "4454" {
+ 4454
+ } else if v == "4455" {
+ 4455
+ } else if v == "4456" {
+ 4456
+ } else if v == "4457" {
+ 4457
+ } else if v == "4458" {
+ 4458
+ } else if v == "4459" {
+ 4459
+ } else if v == "4460" {
+ 4460
+ } else if v == "4461" {
+ 4461
+ } else if v == "4462" {
+ 4462
+ } else if v == "4463" {
+ 4463
+ } else if v == "4464" {
+ 4464
+ } else if v == "4465" {
+ 4465
+ } else if v == "4466" {
+ 4466
+ } else if v == "4467" {
+ 4467
+ } else if v == "4468" {
+ 4468
+ } else if v == "4469" {
+ 4469
+ } else if v == "4470" {
+ 4470
+ } else if v == "4471" {
+ 4471
+ } else if v == "4472" {
+ 4472
+ } else if v == "4473" {
+ 4473
+ } else if v == "4474" {
+ 4474
+ } else if v == "4475" {
+ 4475
+ } else if v == "4476" {
+ 4476
+ } else if v == "4477" {
+ 4477
+ } else if v == "4478" {
+ 4478
+ } else if v == "4479" {
+ 4479
+ } else if v == "4480" {
+ 4480
+ } else if v == "4481" {
+ 4481
+ } else if v == "4482" {
+ 4482
+ } else if v == "4483" {
+ 4483
+ } else if v == "4484" {
+ 4484
+ } else if v == "4485" {
+ 4485
+ } else if v == "4486" {
+ 4486
+ } else if v == "4487" {
+ 4487
+ } else if v == "4488" {
+ 4488
+ } else if v == "4489" {
+ 4489
+ } else if v == "4490" {
+ 4490
+ } else if v == "4491" {
+ 4491
+ } else if v == "4492" {
+ 4492
+ } else if v == "4493" {
+ 4493
+ } else if v == "4494" {
+ 4494
+ } else if v == "4495" {
+ 4495
+ } else if v == "4496" {
+ 4496
+ } else if v == "4497" {
+ 4497
+ } else if v == "4498" {
+ 4498
+ } else if v == "4499" {
+ 4499
+ } else if v == "4500" {
+ 4500
+ } else if v == "4501" {
+ 4501
+ } else if v == "4502" {
+ 4502
+ } else if v == "4503" {
+ 4503
+ } else if v == "4504" {
+ 4504
+ } else if v == "4505" {
+ 4505
+ } else if v == "4506" {
+ 4506
+ } else if v == "4507" {
+ 4507
+ } else if v == "4508" {
+ 4508
+ } else if v == "4509" {
+ 4509
+ } else if v == "4510" {
+ 4510
+ } else if v == "4511" {
+ 4511
+ } else if v == "4512" {
+ 4512
+ } else if v == "4513" {
+ 4513
+ } else if v == "4514" {
+ 4514
+ } else if v == "4515" {
+ 4515
+ } else if v == "4516" {
+ 4516
+ } else if v == "4517" {
+ 4517
+ } else if v == "4518" {
+ 4518
+ } else if v == "4519" {
+ 4519
+ } else if v == "4520" {
+ 4520
+ } else if v == "4521" {
+ 4521
+ } else if v == "4522" {
+ 4522
+ } else if v == "4523" {
+ 4523
+ } else if v == "4524" {
+ 4524
+ } else if v == "4525" {
+ 4525
+ } else if v == "4526" {
+ 4526
+ } else if v == "4527" {
+ 4527
+ } else if v == "4528" {
+ 4528
+ } else if v == "4529" {
+ 4529
+ } else if v == "4530" {
+ 4530
+ } else if v == "4531" {
+ 4531
+ } else if v == "4532" {
+ 4532
+ } else if v == "4533" {
+ 4533
+ } else if v == "4534" {
+ 4534
+ } else if v == "4535" {
+ 4535
+ } else if v == "4536" {
+ 4536
+ } else if v == "4537" {
+ 4537
+ } else if v == "4538" {
+ 4538
+ } else if v == "4539" {
+ 4539
+ } else if v == "4540" {
+ 4540
+ } else if v == "4541" {
+ 4541
+ } else if v == "4542" {
+ 4542
+ } else if v == "4543" {
+ 4543
+ } else if v == "4544" {
+ 4544
+ } else if v == "4545" {
+ 4545
+ } else if v == "4546" {
+ 4546
+ } else if v == "4547" {
+ 4547
+ } else if v == "4548" {
+ 4548
+ } else if v == "4549" {
+ 4549
+ } else if v == "4550" {
+ 4550
+ } else if v == "4551" {
+ 4551
+ } else if v == "4552" {
+ 4552
+ } else if v == "4553" {
+ 4553
+ } else if v == "4554" {
+ 4554
+ } else if v == "4555" {
+ 4555
+ } else if v == "4556" {
+ 4556
+ } else if v == "4557" {
+ 4557
+ } else if v == "4558" {
+ 4558
+ } else if v == "4559" {
+ 4559
+ } else if v == "4560" {
+ 4560
+ } else if v == "4561" {
+ 4561
+ } else if v == "4562" {
+ 4562
+ } else if v == "4563" {
+ 4563
+ } else if v == "4564" {
+ 4564
+ } else if v == "4565" {
+ 4565
+ } else if v == "4566" {
+ 4566
+ } else if v == "4567" {
+ 4567
+ } else if v == "4568" {
+ 4568
+ } else if v == "4569" {
+ 4569
+ } else if v == "4570" {
+ 4570
+ } else if v == "4571" {
+ 4571
+ } else if v == "4572" {
+ 4572
+ } else if v == "4573" {
+ 4573
+ } else if v == "4574" {
+ 4574
+ } else if v == "4575" {
+ 4575
+ } else if v == "4576" {
+ 4576
+ } else if v == "4577" {
+ 4577
+ } else if v == "4578" {
+ 4578
+ } else if v == "4579" {
+ 4579
+ } else if v == "4580" {
+ 4580
+ } else if v == "4581" {
+ 4581
+ } else if v == "4582" {
+ 4582
+ } else if v == "4583" {
+ 4583
+ } else if v == "4584" {
+ 4584
+ } else if v == "4585" {
+ 4585
+ } else if v == "4586" {
+ 4586
+ } else if v == "4587" {
+ 4587
+ } else if v == "4588" {
+ 4588
+ } else if v == "4589" {
+ 4589
+ } else if v == "4590" {
+ 4590
+ } else if v == "4591" {
+ 4591
+ } else if v == "4592" {
+ 4592
+ } else if v == "4593" {
+ 4593
+ } else if v == "4594" {
+ 4594
+ } else if v == "4595" {
+ 4595
+ } else if v == "4596" {
+ 4596
+ } else if v == "4597" {
+ 4597
+ } else if v == "4598" {
+ 4598
+ } else if v == "4599" {
+ 4599
+ } else if v == "4600" {
+ 4600
+ } else if v == "4601" {
+ 4601
+ } else if v == "4602" {
+ 4602
+ } else if v == "4603" {
+ 4603
+ } else if v == "4604" {
+ 4604
+ } else if v == "4605" {
+ 4605
+ } else if v == "4606" {
+ 4606
+ } else if v == "4607" {
+ 4607
+ } else if v == "4608" {
+ 4608
+ } else if v == "4609" {
+ 4609
+ } else if v == "4610" {
+ 4610
+ } else if v == "4611" {
+ 4611
+ } else if v == "4612" {
+ 4612
+ } else if v == "4613" {
+ 4613
+ } else if v == "4614" {
+ 4614
+ } else if v == "4615" {
+ 4615
+ } else if v == "4616" {
+ 4616
+ } else if v == "4617" {
+ 4617
+ } else if v == "4618" {
+ 4618
+ } else if v == "4619" {
+ 4619
+ } else if v == "4620" {
+ 4620
+ } else if v == "4621" {
+ 4621
+ } else if v == "4622" {
+ 4622
+ } else if v == "4623" {
+ 4623
+ } else if v == "4624" {
+ 4624
+ } else if v == "4625" {
+ 4625
+ } else if v == "4626" {
+ 4626
+ } else if v == "4627" {
+ 4627
+ } else if v == "4628" {
+ 4628
+ } else if v == "4629" {
+ 4629
+ } else if v == "4630" {
+ 4630
+ } else if v == "4631" {
+ 4631
+ } else if v == "4632" {
+ 4632
+ } else if v == "4633" {
+ 4633
+ } else if v == "4634" {
+ 4634
+ } else if v == "4635" {
+ 4635
+ } else if v == "4636" {
+ 4636
+ } else if v == "4637" {
+ 4637
+ } else if v == "4638" {
+ 4638
+ } else if v == "4639" {
+ 4639
+ } else if v == "4640" {
+ 4640
+ } else if v == "4641" {
+ 4641
+ } else if v == "4642" {
+ 4642
+ } else if v == "4643" {
+ 4643
+ } else if v == "4644" {
+ 4644
+ } else if v == "4645" {
+ 4645
+ } else if v == "4646" {
+ 4646
+ } else if v == "4647" {
+ 4647
+ } else if v == "4648" {
+ 4648
+ } else if v == "4649" {
+ 4649
+ } else if v == "4650" {
+ 4650
+ } else if v == "4651" {
+ 4651
+ } else if v == "4652" {
+ 4652
+ } else if v == "4653" {
+ 4653
+ } else if v == "4654" {
+ 4654
+ } else if v == "4655" {
+ 4655
+ } else if v == "4656" {
+ 4656
+ } else if v == "4657" {
+ 4657
+ } else if v == "4658" {
+ 4658
+ } else if v == "4659" {
+ 4659
+ } else if v == "4660" {
+ 4660
+ } else if v == "4661" {
+ 4661
+ } else if v == "4662" {
+ 4662
+ } else if v == "4663" {
+ 4663
+ } else if v == "4664" {
+ 4664
+ } else if v == "4665" {
+ 4665
+ } else if v == "4666" {
+ 4666
+ } else if v == "4667" {
+ 4667
+ } else if v == "4668" {
+ 4668
+ } else if v == "4669" {
+ 4669
+ } else if v == "4670" {
+ 4670
+ } else if v == "4671" {
+ 4671
+ } else if v == "4672" {
+ 4672
+ } else if v == "4673" {
+ 4673
+ } else if v == "4674" {
+ 4674
+ } else if v == "4675" {
+ 4675
+ } else if v == "4676" {
+ 4676
+ } else if v == "4677" {
+ 4677
+ } else if v == "4678" {
+ 4678
+ } else if v == "4679" {
+ 4679
+ } else if v == "4680" {
+ 4680
+ } else if v == "4681" {
+ 4681
+ } else if v == "4682" {
+ 4682
+ } else if v == "4683" {
+ 4683
+ } else if v == "4684" {
+ 4684
+ } else if v == "4685" {
+ 4685
+ } else if v == "4686" {
+ 4686
+ } else if v == "4687" {
+ 4687
+ } else if v == "4688" {
+ 4688
+ } else if v == "4689" {
+ 4689
+ } else if v == "4690" {
+ 4690
+ } else if v == "4691" {
+ 4691
+ } else if v == "4692" {
+ 4692
+ } else if v == "4693" {
+ 4693
+ } else if v == "4694" {
+ 4694
+ } else if v == "4695" {
+ 4695
+ } else if v == "4696" {
+ 4696
+ } else if v == "4697" {
+ 4697
+ } else if v == "4698" {
+ 4698
+ } else if v == "4699" {
+ 4699
+ } else if v == "4700" {
+ 4700
+ } else if v == "4701" {
+ 4701
+ } else if v == "4702" {
+ 4702
+ } else if v == "4703" {
+ 4703
+ } else if v == "4704" {
+ 4704
+ } else if v == "4705" {
+ 4705
+ } else if v == "4706" {
+ 4706
+ } else if v == "4707" {
+ 4707
+ } else if v == "4708" {
+ 4708
+ } else if v == "4709" {
+ 4709
+ } else if v == "4710" {
+ 4710
+ } else if v == "4711" {
+ 4711
+ } else if v == "4712" {
+ 4712
+ } else if v == "4713" {
+ 4713
+ } else if v == "4714" {
+ 4714
+ } else if v == "4715" {
+ 4715
+ } else if v == "4716" {
+ 4716
+ } else if v == "4717" {
+ 4717
+ } else if v == "4718" {
+ 4718
+ } else if v == "4719" {
+ 4719
+ } else if v == "4720" {
+ 4720
+ } else if v == "4721" {
+ 4721
+ } else if v == "4722" {
+ 4722
+ } else if v == "4723" {
+ 4723
+ } else if v == "4724" {
+ 4724
+ } else if v == "4725" {
+ 4725
+ } else if v == "4726" {
+ 4726
+ } else if v == "4727" {
+ 4727
+ } else if v == "4728" {
+ 4728
+ } else if v == "4729" {
+ 4729
+ } else if v == "4730" {
+ 4730
+ } else if v == "4731" {
+ 4731
+ } else if v == "4732" {
+ 4732
+ } else if v == "4733" {
+ 4733
+ } else if v == "4734" {
+ 4734
+ } else if v == "4735" {
+ 4735
+ } else if v == "4736" {
+ 4736
+ } else if v == "4737" {
+ 4737
+ } else if v == "4738" {
+ 4738
+ } else if v == "4739" {
+ 4739
+ } else if v == "4740" {
+ 4740
+ } else if v == "4741" {
+ 4741
+ } else if v == "4742" {
+ 4742
+ } else if v == "4743" {
+ 4743
+ } else if v == "4744" {
+ 4744
+ } else if v == "4745" {
+ 4745
+ } else if v == "4746" {
+ 4746
+ } else if v == "4747" {
+ 4747
+ } else if v == "4748" {
+ 4748
+ } else if v == "4749" {
+ 4749
+ } else if v == "4750" {
+ 4750
+ } else if v == "4751" {
+ 4751
+ } else if v == "4752" {
+ 4752
+ } else if v == "4753" {
+ 4753
+ } else if v == "4754" {
+ 4754
+ } else if v == "4755" {
+ 4755
+ } else if v == "4756" {
+ 4756
+ } else if v == "4757" {
+ 4757
+ } else if v == "4758" {
+ 4758
+ } else if v == "4759" {
+ 4759
+ } else if v == "4760" {
+ 4760
+ } else if v == "4761" {
+ 4761
+ } else if v == "4762" {
+ 4762
+ } else if v == "4763" {
+ 4763
+ } else if v == "4764" {
+ 4764
+ } else if v == "4765" {
+ 4765
+ } else if v == "4766" {
+ 4766
+ } else if v == "4767" {
+ 4767
+ } else if v == "4768" {
+ 4768
+ } else if v == "4769" {
+ 4769
+ } else if v == "4770" {
+ 4770
+ } else if v == "4771" {
+ 4771
+ } else if v == "4772" {
+ 4772
+ } else if v == "4773" {
+ 4773
+ } else if v == "4774" {
+ 4774
+ } else if v == "4775" {
+ 4775
+ } else if v == "4776" {
+ 4776
+ } else if v == "4777" {
+ 4777
+ } else if v == "4778" {
+ 4778
+ } else if v == "4779" {
+ 4779
+ } else if v == "4780" {
+ 4780
+ } else if v == "4781" {
+ 4781
+ } else if v == "4782" {
+ 4782
+ } else if v == "4783" {
+ 4783
+ } else if v == "4784" {
+ 4784
+ } else if v == "4785" {
+ 4785
+ } else if v == "4786" {
+ 4786
+ } else if v == "4787" {
+ 4787
+ } else if v == "4788" {
+ 4788
+ } else if v == "4789" {
+ 4789
+ } else if v == "4790" {
+ 4790
+ } else if v == "4791" {
+ 4791
+ } else if v == "4792" {
+ 4792
+ } else if v == "4793" {
+ 4793
+ } else if v == "4794" {
+ 4794
+ } else if v == "4795" {
+ 4795
+ } else if v == "4796" {
+ 4796
+ } else if v == "4797" {
+ 4797
+ } else if v == "4798" {
+ 4798
+ } else if v == "4799" {
+ 4799
+ } else if v == "4800" {
+ 4800
+ } else if v == "4801" {
+ 4801
+ } else if v == "4802" {
+ 4802
+ } else if v == "4803" {
+ 4803
+ } else if v == "4804" {
+ 4804
+ } else if v == "4805" {
+ 4805
+ } else if v == "4806" {
+ 4806
+ } else if v == "4807" {
+ 4807
+ } else if v == "4808" {
+ 4808
+ } else if v == "4809" {
+ 4809
+ } else if v == "4810" {
+ 4810
+ } else if v == "4811" {
+ 4811
+ } else if v == "4812" {
+ 4812
+ } else if v == "4813" {
+ 4813
+ } else if v == "4814" {
+ 4814
+ } else if v == "4815" {
+ 4815
+ } else if v == "4816" {
+ 4816
+ } else if v == "4817" {
+ 4817
+ } else if v == "4818" {
+ 4818
+ } else if v == "4819" {
+ 4819
+ } else if v == "4820" {
+ 4820
+ } else if v == "4821" {
+ 4821
+ } else if v == "4822" {
+ 4822
+ } else if v == "4823" {
+ 4823
+ } else if v == "4824" {
+ 4824
+ } else if v == "4825" {
+ 4825
+ } else if v == "4826" {
+ 4826
+ } else if v == "4827" {
+ 4827
+ } else if v == "4828" {
+ 4828
+ } else if v == "4829" {
+ 4829
+ } else if v == "4830" {
+ 4830
+ } else if v == "4831" {
+ 4831
+ } else if v == "4832" {
+ 4832
+ } else if v == "4833" {
+ 4833
+ } else if v == "4834" {
+ 4834
+ } else if v == "4835" {
+ 4835
+ } else if v == "4836" {
+ 4836
+ } else if v == "4837" {
+ 4837
+ } else if v == "4838" {
+ 4838
+ } else if v == "4839" {
+ 4839
+ } else if v == "4840" {
+ 4840
+ } else if v == "4841" {
+ 4841
+ } else if v == "4842" {
+ 4842
+ } else if v == "4843" {
+ 4843
+ } else if v == "4844" {
+ 4844
+ } else if v == "4845" {
+ 4845
+ } else if v == "4846" {
+ 4846
+ } else if v == "4847" {
+ 4847
+ } else if v == "4848" {
+ 4848
+ } else if v == "4849" {
+ 4849
+ } else if v == "4850" {
+ 4850
+ } else if v == "4851" {
+ 4851
+ } else if v == "4852" {
+ 4852
+ } else if v == "4853" {
+ 4853
+ } else if v == "4854" {
+ 4854
+ } else if v == "4855" {
+ 4855
+ } else if v == "4856" {
+ 4856
+ } else if v == "4857" {
+ 4857
+ } else if v == "4858" {
+ 4858
+ } else if v == "4859" {
+ 4859
+ } else if v == "4860" {
+ 4860
+ } else if v == "4861" {
+ 4861
+ } else if v == "4862" {
+ 4862
+ } else if v == "4863" {
+ 4863
+ } else if v == "4864" {
+ 4864
+ } else if v == "4865" {
+ 4865
+ } else if v == "4866" {
+ 4866
+ } else if v == "4867" {
+ 4867
+ } else if v == "4868" {
+ 4868
+ } else if v == "4869" {
+ 4869
+ } else if v == "4870" {
+ 4870
+ } else if v == "4871" {
+ 4871
+ } else if v == "4872" {
+ 4872
+ } else if v == "4873" {
+ 4873
+ } else if v == "4874" {
+ 4874
+ } else if v == "4875" {
+ 4875
+ } else if v == "4876" {
+ 4876
+ } else if v == "4877" {
+ 4877
+ } else if v == "4878" {
+ 4878
+ } else if v == "4879" {
+ 4879
+ } else if v == "4880" {
+ 4880
+ } else if v == "4881" {
+ 4881
+ } else if v == "4882" {
+ 4882
+ } else if v == "4883" {
+ 4883
+ } else if v == "4884" {
+ 4884
+ } else if v == "4885" {
+ 4885
+ } else if v == "4886" {
+ 4886
+ } else if v == "4887" {
+ 4887
+ } else if v == "4888" {
+ 4888
+ } else if v == "4889" {
+ 4889
+ } else if v == "4890" {
+ 4890
+ } else if v == "4891" {
+ 4891
+ } else if v == "4892" {
+ 4892
+ } else if v == "4893" {
+ 4893
+ } else if v == "4894" {
+ 4894
+ } else if v == "4895" {
+ 4895
+ } else if v == "4896" {
+ 4896
+ } else if v == "4897" {
+ 4897
+ } else if v == "4898" {
+ 4898
+ } else if v == "4899" {
+ 4899
+ } else if v == "4900" {
+ 4900
+ } else if v == "4901" {
+ 4901
+ } else if v == "4902" {
+ 4902
+ } else if v == "4903" {
+ 4903
+ } else if v == "4904" {
+ 4904
+ } else if v == "4905" {
+ 4905
+ } else if v == "4906" {
+ 4906
+ } else if v == "4907" {
+ 4907
+ } else if v == "4908" {
+ 4908
+ } else if v == "4909" {
+ 4909
+ } else if v == "4910" {
+ 4910
+ } else if v == "4911" {
+ 4911
+ } else if v == "4912" {
+ 4912
+ } else if v == "4913" {
+ 4913
+ } else if v == "4914" {
+ 4914
+ } else if v == "4915" {
+ 4915
+ } else if v == "4916" {
+ 4916
+ } else if v == "4917" {
+ 4917
+ } else if v == "4918" {
+ 4918
+ } else if v == "4919" {
+ 4919
+ } else if v == "4920" {
+ 4920
+ } else if v == "4921" {
+ 4921
+ } else if v == "4922" {
+ 4922
+ } else if v == "4923" {
+ 4923
+ } else if v == "4924" {
+ 4924
+ } else if v == "4925" {
+ 4925
+ } else if v == "4926" {
+ 4926
+ } else if v == "4927" {
+ 4927
+ } else if v == "4928" {
+ 4928
+ } else if v == "4929" {
+ 4929
+ } else if v == "4930" {
+ 4930
+ } else if v == "4931" {
+ 4931
+ } else if v == "4932" {
+ 4932
+ } else if v == "4933" {
+ 4933
+ } else if v == "4934" {
+ 4934
+ } else if v == "4935" {
+ 4935
+ } else if v == "4936" {
+ 4936
+ } else if v == "4937" {
+ 4937
+ } else if v == "4938" {
+ 4938
+ } else if v == "4939" {
+ 4939
+ } else if v == "4940" {
+ 4940
+ } else if v == "4941" {
+ 4941
+ } else if v == "4942" {
+ 4942
+ } else if v == "4943" {
+ 4943
+ } else if v == "4944" {
+ 4944
+ } else if v == "4945" {
+ 4945
+ } else if v == "4946" {
+ 4946
+ } else if v == "4947" {
+ 4947
+ } else if v == "4948" {
+ 4948
+ } else if v == "4949" {
+ 4949
+ } else if v == "4950" {
+ 4950
+ } else if v == "4951" {
+ 4951
+ } else if v == "4952" {
+ 4952
+ } else if v == "4953" {
+ 4953
+ } else if v == "4954" {
+ 4954
+ } else if v == "4955" {
+ 4955
+ } else if v == "4956" {
+ 4956
+ } else if v == "4957" {
+ 4957
+ } else if v == "4958" {
+ 4958
+ } else if v == "4959" {
+ 4959
+ } else if v == "4960" {
+ 4960
+ } else if v == "4961" {
+ 4961
+ } else if v == "4962" {
+ 4962
+ } else if v == "4963" {
+ 4963
+ } else if v == "4964" {
+ 4964
+ } else if v == "4965" {
+ 4965
+ } else if v == "4966" {
+ 4966
+ } else if v == "4967" {
+ 4967
+ } else if v == "4968" {
+ 4968
+ } else if v == "4969" {
+ 4969
+ } else if v == "4970" {
+ 4970
+ } else if v == "4971" {
+ 4971
+ } else if v == "4972" {
+ 4972
+ } else if v == "4973" {
+ 4973
+ } else if v == "4974" {
+ 4974
+ } else if v == "4975" {
+ 4975
+ } else if v == "4976" {
+ 4976
+ } else if v == "4977" {
+ 4977
+ } else if v == "4978" {
+ 4978
+ } else if v == "4979" {
+ 4979
+ } else if v == "4980" {
+ 4980
+ } else if v == "4981" {
+ 4981
+ } else if v == "4982" {
+ 4982
+ } else if v == "4983" {
+ 4983
+ } else if v == "4984" {
+ 4984
+ } else if v == "4985" {
+ 4985
+ } else if v == "4986" {
+ 4986
+ } else if v == "4987" {
+ 4987
+ } else if v == "4988" {
+ 4988
+ } else if v == "4989" {
+ 4989
+ } else if v == "4990" {
+ 4990
+ } else if v == "4991" {
+ 4991
+ } else if v == "4992" {
+ 4992
+ } else if v == "4993" {
+ 4993
+ } else if v == "4994" {
+ 4994
+ } else if v == "4995" {
+ 4995
+ } else if v == "4996" {
+ 4996
+ } else if v == "4997" {
+ 4997
+ } else if v == "4998" {
+ 4998
+ } else if v == "4999" {
+ 4999
+ } else if v == "5000" {
+ 5000
+ } else if v == "5001" {
+ 5001
+ } else if v == "5002" {
+ 5002
+ } else if v == "5003" {
+ 5003
+ } else if v == "5004" {
+ 5004
+ } else if v == "5005" {
+ 5005
+ } else if v == "5006" {
+ 5006
+ } else if v == "5007" {
+ 5007
+ } else if v == "5008" {
+ 5008
+ } else if v == "5009" {
+ 5009
+ } else if v == "5010" {
+ 5010
+ } else if v == "5011" {
+ 5011
+ } else if v == "5012" {
+ 5012
+ } else if v == "5013" {
+ 5013
+ } else if v == "5014" {
+ 5014
+ } else if v == "5015" {
+ 5015
+ } else if v == "5016" {
+ 5016
+ } else if v == "5017" {
+ 5017
+ } else if v == "5018" {
+ 5018
+ } else if v == "5019" {
+ 5019
+ } else if v == "5020" {
+ 5020
+ } else if v == "5021" {
+ 5021
+ } else if v == "5022" {
+ 5022
+ } else if v == "5023" {
+ 5023
+ } else if v == "5024" {
+ 5024
+ } else if v == "5025" {
+ 5025
+ } else if v == "5026" {
+ 5026
+ } else if v == "5027" {
+ 5027
+ } else if v == "5028" {
+ 5028
+ } else if v == "5029" {
+ 5029
+ } else if v == "5030" {
+ 5030
+ } else if v == "5031" {
+ 5031
+ } else if v == "5032" {
+ 5032
+ } else if v == "5033" {
+ 5033
+ } else if v == "5034" {
+ 5034
+ } else if v == "5035" {
+ 5035
+ } else if v == "5036" {
+ 5036
+ } else if v == "5037" {
+ 5037
+ } else if v == "5038" {
+ 5038
+ } else if v == "5039" {
+ 5039
+ } else if v == "5040" {
+ 5040
+ } else if v == "5041" {
+ 5041
+ } else if v == "5042" {
+ 5042
+ } else if v == "5043" {
+ 5043
+ } else if v == "5044" {
+ 5044
+ } else if v == "5045" {
+ 5045
+ } else if v == "5046" {
+ 5046
+ } else if v == "5047" {
+ 5047
+ } else if v == "5048" {
+ 5048
+ } else if v == "5049" {
+ 5049
+ } else if v == "5050" {
+ 5050
+ } else if v == "5051" {
+ 5051
+ } else if v == "5052" {
+ 5052
+ } else if v == "5053" {
+ 5053
+ } else if v == "5054" {
+ 5054
+ } else if v == "5055" {
+ 5055
+ } else if v == "5056" {
+ 5056
+ } else if v == "5057" {
+ 5057
+ } else if v == "5058" {
+ 5058
+ } else if v == "5059" {
+ 5059
+ } else if v == "5060" {
+ 5060
+ } else if v == "5061" {
+ 5061
+ } else if v == "5062" {
+ 5062
+ } else if v == "5063" {
+ 5063
+ } else if v == "5064" {
+ 5064
+ } else if v == "5065" {
+ 5065
+ } else if v == "5066" {
+ 5066
+ } else if v == "5067" {
+ 5067
+ } else if v == "5068" {
+ 5068
+ } else if v == "5069" {
+ 5069
+ } else if v == "5070" {
+ 5070
+ } else if v == "5071" {
+ 5071
+ } else if v == "5072" {
+ 5072
+ } else if v == "5073" {
+ 5073
+ } else if v == "5074" {
+ 5074
+ } else if v == "5075" {
+ 5075
+ } else if v == "5076" {
+ 5076
+ } else if v == "5077" {
+ 5077
+ } else if v == "5078" {
+ 5078
+ } else if v == "5079" {
+ 5079
+ } else if v == "5080" {
+ 5080
+ } else if v == "5081" {
+ 5081
+ } else if v == "5082" {
+ 5082
+ } else if v == "5083" {
+ 5083
+ } else if v == "5084" {
+ 5084
+ } else if v == "5085" {
+ 5085
+ } else if v == "5086" {
+ 5086
+ } else if v == "5087" {
+ 5087
+ } else if v == "5088" {
+ 5088
+ } else if v == "5089" {
+ 5089
+ } else if v == "5090" {
+ 5090
+ } else if v == "5091" {
+ 5091
+ } else if v == "5092" {
+ 5092
+ } else if v == "5093" {
+ 5093
+ } else if v == "5094" {
+ 5094
+ } else if v == "5095" {
+ 5095
+ } else if v == "5096" {
+ 5096
+ } else if v == "5097" {
+ 5097
+ } else if v == "5098" {
+ 5098
+ } else if v == "5099" {
+ 5099
+ } else if v == "5100" {
+ 5100
+ } else if v == "5101" {
+ 5101
+ } else if v == "5102" {
+ 5102
+ } else if v == "5103" {
+ 5103
+ } else if v == "5104" {
+ 5104
+ } else if v == "5105" {
+ 5105
+ } else if v == "5106" {
+ 5106
+ } else if v == "5107" {
+ 5107
+ } else if v == "5108" {
+ 5108
+ } else if v == "5109" {
+ 5109
+ } else if v == "5110" {
+ 5110
+ } else if v == "5111" {
+ 5111
+ } else if v == "5112" {
+ 5112
+ } else if v == "5113" {
+ 5113
+ } else if v == "5114" {
+ 5114
+ } else if v == "5115" {
+ 5115
+ } else if v == "5116" {
+ 5116
+ } else if v == "5117" {
+ 5117
+ } else if v == "5118" {
+ 5118
+ } else if v == "5119" {
+ 5119
+ } else if v == "5120" {
+ 5120
+ } else if v == "5121" {
+ 5121
+ } else if v == "5122" {
+ 5122
+ } else if v == "5123" {
+ 5123
+ } else if v == "5124" {
+ 5124
+ } else if v == "5125" {
+ 5125
+ } else if v == "5126" {
+ 5126
+ } else if v == "5127" {
+ 5127
+ } else if v == "5128" {
+ 5128
+ } else if v == "5129" {
+ 5129
+ } else if v == "5130" {
+ 5130
+ } else if v == "5131" {
+ 5131
+ } else if v == "5132" {
+ 5132
+ } else if v == "5133" {
+ 5133
+ } else if v == "5134" {
+ 5134
+ } else if v == "5135" {
+ 5135
+ } else if v == "5136" {
+ 5136
+ } else if v == "5137" {
+ 5137
+ } else if v == "5138" {
+ 5138
+ } else if v == "5139" {
+ 5139
+ } else if v == "5140" {
+ 5140
+ } else if v == "5141" {
+ 5141
+ } else if v == "5142" {
+ 5142
+ } else if v == "5143" {
+ 5143
+ } else if v == "5144" {
+ 5144
+ } else if v == "5145" {
+ 5145
+ } else if v == "5146" {
+ 5146
+ } else if v == "5147" {
+ 5147
+ } else if v == "5148" {
+ 5148
+ } else if v == "5149" {
+ 5149
+ } else if v == "5150" {
+ 5150
+ } else if v == "5151" {
+ 5151
+ } else if v == "5152" {
+ 5152
+ } else if v == "5153" {
+ 5153
+ } else if v == "5154" {
+ 5154
+ } else if v == "5155" {
+ 5155
+ } else if v == "5156" {
+ 5156
+ } else if v == "5157" {
+ 5157
+ } else if v == "5158" {
+ 5158
+ } else if v == "5159" {
+ 5159
+ } else if v == "5160" {
+ 5160
+ } else if v == "5161" {
+ 5161
+ } else if v == "5162" {
+ 5162
+ } else if v == "5163" {
+ 5163
+ } else if v == "5164" {
+ 5164
+ } else if v == "5165" {
+ 5165
+ } else if v == "5166" {
+ 5166
+ } else if v == "5167" {
+ 5167
+ } else if v == "5168" {
+ 5168
+ } else if v == "5169" {
+ 5169
+ } else if v == "5170" {
+ 5170
+ } else if v == "5171" {
+ 5171
+ } else if v == "5172" {
+ 5172
+ } else if v == "5173" {
+ 5173
+ } else if v == "5174" {
+ 5174
+ } else if v == "5175" {
+ 5175
+ } else if v == "5176" {
+ 5176
+ } else if v == "5177" {
+ 5177
+ } else if v == "5178" {
+ 5178
+ } else if v == "5179" {
+ 5179
+ } else if v == "5180" {
+ 5180
+ } else if v == "5181" {
+ 5181
+ } else if v == "5182" {
+ 5182
+ } else if v == "5183" {
+ 5183
+ } else if v == "5184" {
+ 5184
+ } else if v == "5185" {
+ 5185
+ } else if v == "5186" {
+ 5186
+ } else if v == "5187" {
+ 5187
+ } else if v == "5188" {
+ 5188
+ } else if v == "5189" {
+ 5189
+ } else if v == "5190" {
+ 5190
+ } else if v == "5191" {
+ 5191
+ } else if v == "5192" {
+ 5192
+ } else if v == "5193" {
+ 5193
+ } else if v == "5194" {
+ 5194
+ } else if v == "5195" {
+ 5195
+ } else if v == "5196" {
+ 5196
+ } else if v == "5197" {
+ 5197
+ } else if v == "5198" {
+ 5198
+ } else if v == "5199" {
+ 5199
+ } else if v == "5200" {
+ 5200
+ } else if v == "5201" {
+ 5201
+ } else if v == "5202" {
+ 5202
+ } else if v == "5203" {
+ 5203
+ } else if v == "5204" {
+ 5204
+ } else if v == "5205" {
+ 5205
+ } else {
+ 5206
+ }
+}
--- /dev/null
+// build-pass
+
+fn test<T>() {
+ std::mem::size_of::<T>();
+}
+
+pub fn foo<T>(_: T) -> &'static fn() {
+ &(test::<T> as fn())
+}
+
+fn outer<T>() {
+ foo(|| ());
+}
+
+fn main() {
+ outer::<u8>();
+}
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
big.iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
[0u8; 33].iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(small).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(big).iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new([0u8; 33]).iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(Box::new(small)).iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(Box::new(big)).iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(Box::new([0u8; 33])).iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
// Expressions that should not
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
big.into_iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
[0u8; 33].into_iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(small).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(big).into_iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new([0u8; 33]).into_iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(Box::new(small)).into_iter();
//~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(Box::new(big)).into_iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
Box::new(Box::new([0u8; 33])).into_iter();
- //~^ WARNING this method call currently resolves to `<&[T] as IntoIterator>::into_iter`
+ //~^ WARNING this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter`
//~| WARNING this was previously accepted by the compiler but is being phased out
// Expressions that should not
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
-warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
--> $DIR/into-iter-on-arrays-lint.rs:15:9
|
LL | big.into_iter();
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
-warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
--> $DIR/into-iter-on-arrays-lint.rs:18:15
|
LL | [0u8; 33].into_iter();
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
-warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
--> $DIR/into-iter-on-arrays-lint.rs:28:19
|
LL | Box::new(big).into_iter();
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
-warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
--> $DIR/into-iter-on-arrays-lint.rs:31:25
|
LL | Box::new([0u8; 33]).into_iter();
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
-warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
--> $DIR/into-iter-on-arrays-lint.rs:41:29
|
LL | Box::new(Box::new(big)).into_iter();
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #66145 <https://github.com/rust-lang/rust/issues/66145>
-warning: this method call currently resolves to `<&[T] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
+warning: this method call currently resolves to `<&[T; N] as IntoIterator>::into_iter` (due to autoref coercions), but that might change in the future when `IntoIterator` impls for arrays are added.
--> $DIR/into-iter-on-arrays-lint.rs:44:35
|
LL | Box::new(Box::new([0u8; 33])).into_iter();
use std::marker::PhantomData;
+trait Bar { }
trait Mirror { type It: ?Sized; }
impl<T: ?Sized> Mirror for T { type It = Self; }
#[repr(C)]
pub fn char_type(p: char); //~ ERROR uses type `char`
pub fn i128_type(p: i128); //~ ERROR uses type `i128`
pub fn u128_type(p: u128); //~ ERROR uses type `u128`
- pub fn trait_type(p: &dyn Clone); //~ ERROR uses type `dyn std::clone::Clone`
+ pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar`
pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)`
pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)`
pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize`
error: `extern` block uses type `Foo`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:46:28
+ --> $DIR/lint-ctypes.rs:47:28
|
LL | pub fn ptr_type1(size: *const Foo);
| ^^^^^^^^^^ not FFI-safe
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
- --> $DIR/lint-ctypes.rs:24:1
+ --> $DIR/lint-ctypes.rs:25:1
|
LL | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `Foo`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:47:28
+ --> $DIR/lint-ctypes.rs:48:28
|
LL | pub fn ptr_type2(size: *const Foo);
| ^^^^^^^^^^ not FFI-safe
= help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
= note: this struct has unspecified layout
note: the type is defined here
- --> $DIR/lint-ctypes.rs:24:1
+ --> $DIR/lint-ctypes.rs:25:1
|
LL | pub struct Foo;
| ^^^^^^^^^^^^^^^
error: `extern` block uses type `[u32]`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:48:26
+ --> $DIR/lint-ctypes.rs:49:26
|
LL | pub fn slice_type(p: &[u32]);
| ^^^^^^ not FFI-safe
= note: slices have no C equivalent
error: `extern` block uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:49:24
+ --> $DIR/lint-ctypes.rs:50:24
|
LL | pub fn str_type(p: &str);
| ^^^^ not FFI-safe
= note: string slices have no C equivalent
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:50:24
+ --> $DIR/lint-ctypes.rs:51:24
|
LL | pub fn box_type(p: Box<u32>);
| ^^^^^^^^ not FFI-safe
= note: this struct has unspecified layout
error: `extern` block uses type `std::option::Option<std::boxed::Box<u32>>`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:51:28
+ --> $DIR/lint-ctypes.rs:52:28
|
LL | pub fn opt_box_type(p: Option<Box<u32>>);
| ^^^^^^^^^^^^^^^^ not FFI-safe
= note: enum has no representation hint
error: `extern` block uses type `char`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:53:25
+ --> $DIR/lint-ctypes.rs:54:25
|
LL | pub fn char_type(p: char);
| ^^^^ not FFI-safe
= note: the `char` type has no C equivalent
error: `extern` block uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:54:25
+ --> $DIR/lint-ctypes.rs:55:25
|
LL | pub fn i128_type(p: i128);
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` block uses type `u128`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:55:25
+ --> $DIR/lint-ctypes.rs:56:25
|
LL | pub fn u128_type(p: u128);
| ^^^^ not FFI-safe
|
= note: 128-bit integers don't currently have a known stable ABI
-error: `extern` block uses type `dyn std::clone::Clone`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:56:26
+error: `extern` block uses type `dyn Bar`, which is not FFI-safe
+ --> $DIR/lint-ctypes.rs:57:26
|
-LL | pub fn trait_type(p: &dyn Clone);
- | ^^^^^^^^^^ not FFI-safe
+LL | pub fn trait_type(p: &dyn Bar);
+ | ^^^^^^^^ not FFI-safe
|
= note: trait objects have no C equivalent
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:57:26
+ --> $DIR/lint-ctypes.rs:58:26
|
LL | pub fn tuple_type(p: (i32, i32));
| ^^^^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` block uses type `(i32, i32)`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:58:27
+ --> $DIR/lint-ctypes.rs:59:27
|
LL | pub fn tuple_type2(p: I32Pair);
| ^^^^^^^ not FFI-safe
= note: tuples have unspecified layout
error: `extern` block uses type `ZeroSize`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:59:25
+ --> $DIR/lint-ctypes.rs:60:25
|
LL | pub fn zero_size(p: ZeroSize);
| ^^^^^^^^ not FFI-safe
= help: consider adding a member to this struct
= note: this struct has no fields
note: the type is defined here
- --> $DIR/lint-ctypes.rs:20:1
+ --> $DIR/lint-ctypes.rs:21:1
|
LL | pub struct ZeroSize;
| ^^^^^^^^^^^^^^^^^^^^
error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:60:33
+ --> $DIR/lint-ctypes.rs:61:33
|
LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData);
| ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
|
= note: composed only of `PhantomData`
note: the type is defined here
- --> $DIR/lint-ctypes.rs:43:1
+ --> $DIR/lint-ctypes.rs:44:1
|
LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `extern` block uses type `std::marker::PhantomData<bool>`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:63:12
+ --> $DIR/lint-ctypes.rs:64:12
|
LL | -> ::std::marker::PhantomData<bool>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
= note: composed only of `PhantomData`
error: `extern` block uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:64:23
+ --> $DIR/lint-ctypes.rs:65:23
|
LL | pub fn fn_type(p: RustFn);
| ^^^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` block uses type `fn()`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:65:24
+ --> $DIR/lint-ctypes.rs:66:24
|
LL | pub fn fn_type2(p: fn());
| ^^^^ not FFI-safe
= note: this function pointer has Rust-specific calling convention
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:66:28
+ --> $DIR/lint-ctypes.rs:67:28
|
LL | pub fn fn_contained(p: RustBadRet);
| ^^^^^^^^^^ not FFI-safe
= note: this struct has unspecified layout
error: `extern` block uses type `i128`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:67:32
+ --> $DIR/lint-ctypes.rs:68:32
|
LL | pub fn transparent_i128(p: TransparentI128);
| ^^^^^^^^^^^^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` block uses type `str`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:68:31
+ --> $DIR/lint-ctypes.rs:69:31
|
LL | pub fn transparent_str(p: TransparentStr);
| ^^^^^^^^^^^^^^ not FFI-safe
= note: string slices have no C equivalent
error: `extern` block uses type `std::boxed::Box<u32>`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:69:30
+ --> $DIR/lint-ctypes.rs:70:30
|
LL | pub fn transparent_fn(p: TransparentBadFn);
| ^^^^^^^^^^^^^^^^ not FFI-safe
= note: this struct has unspecified layout
error: `extern` block uses type `[u8; 8]`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:70:27
+ --> $DIR/lint-ctypes.rs:71:27
|
LL | pub fn raw_array(arr: [u8; 8]);
| ^^^^^^^ not FFI-safe
= note: passing raw arrays by value is not FFI-safe
error: `extern` block uses type `u128`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:72:34
+ --> $DIR/lint-ctypes.rs:73:34
|
LL | pub static static_u128_type: u128;
| ^^^^ not FFI-safe
= note: 128-bit integers don't currently have a known stable ABI
error: `extern` block uses type `u128`, which is not FFI-safe
- --> $DIR/lint-ctypes.rs:73:40
+ --> $DIR/lint-ctypes.rs:74:40
|
LL | pub static static_u128_array_type: [u128; 16];
| ^^^^^^^^^^ not FFI-safe
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/constant-in-expr-inherent-1.rs:8:5
|
-LL | <Foo<'a>>::C
- | ^^^^^^^^^^^^
- |
-note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 7:8...
- --> $DIR/constant-in-expr-inherent-1.rs:7:8
- |
LL | fn foo<'a>(_: &'a u32) -> &'static u32 {
- | ^^
-note: ...so that the types are compatible
- --> $DIR/constant-in-expr-inherent-1.rs:8:5
- |
-LL | <Foo<'a>>::C
- | ^^^^^^^^^^^^
- = note: expected `Foo<'_>`
- found `Foo<'a>`
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
- --> $DIR/constant-in-expr-inherent-1.rs:8:5
- |
+ | ------- this data with lifetime `'a`...
LL | <Foo<'a>>::C
- | ^^^^^^^^^^^^
+ | ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
// `Box<SomeTrait>` defaults to a `'static` bound, so this return
// is illegal.
- ss.r //~ ERROR cannot infer an appropriate lifetime
+ ss.r //~ ERROR E0759
}
fn store(ss: &mut SomeStruct, b: Box<dyn SomeTrait>) {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `ss` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/object-lifetime-default-from-box-error.rs:18:5
|
LL | fn load(ss: &mut SomeStruct) -> Box<dyn SomeTrait> {
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(const_generics, rustc_attrs)]
+//~^ WARN the feature `const_generics` is incomplete
+
+// This test checks that the polymorphization analysis correctly detects unused const
+// parameters in closures.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {
+ let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+#[rustc_polymorphize_error]
+pub fn unused<const T: usize>() -> usize {
+ //~^ ERROR item has unused generic parameters
+ let add_one = |x: usize| x + 1;
+ //~^ ERROR item has unused generic parameters
+ add_one(3)
+}
+
+// Function has an unused generic parameter in closure, but not in parent.
+#[rustc_polymorphize_error]
+pub fn used_parent<const T: usize>() -> usize {
+ let x: usize = T;
+ let add_one = |x: usize| x + 1;
+ //~^ ERROR item has unused generic parameters
+ x + add_one(3)
+}
+
+// Function uses generic parameter in value of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding<const T: usize>() -> usize {
+ let x = || {
+ let y: usize = T;
+ y
+ };
+
+ x()
+}
+
+// Closure uses a value as an upvar, which used the generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused_upvar<const T: usize>() -> usize {
+ let x: usize = T;
+ let y = || x;
+ //~^ ERROR item has unused generic parameters
+ y()
+}
+
+// Closure uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<const T: usize>() -> usize {
+ let x = || unused::<T>();
+ x()
+}
+
+fn main() {
+ no_parameters();
+ let _ = unused::<1>();
+ let _ = used_parent::<1>();
+ let _ = used_binding::<1>();
+ let _ = unused_upvar::<1>();
+ let _ = used_substs::<1>();
+}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/closures.rs:3:12
+ |
+LL | #![feature(const_generics, rustc_attrs)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:19:19
+ |
+LL | pub fn unused<const T: usize>() -> usize {
+ | - generic parameter `T` is unused
+LL |
+LL | let add_one = |x: usize| x + 1;
+ | ^^^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:17:8
+ |
+LL | pub fn unused<const T: usize>() -> usize {
+ | ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:28:19
+ |
+LL | pub fn used_parent<const T: usize>() -> usize {
+ | - generic parameter `T` is unused
+LL | let x: usize = T;
+LL | let add_one = |x: usize| x + 1;
+ | ^^^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:48:13
+ |
+LL | pub fn unused_upvar<const T: usize>() -> usize {
+ | - generic parameter `T` is unused
+LL | let x: usize = T;
+LL | let y = || x;
+ | ^^^^
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(const_generics, rustc_attrs)]
+//~^ WARN the feature `const_generics` is incomplete
+
+// This test checks that the polymorphization analysis correctly detects unused const
+// parameters in functions.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<const T: usize>() {
+ //~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding<const T: usize>() -> usize {
+ let x: usize = T;
+ x
+}
+
+// Function uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<const T: usize>() {
+ unused::<T>()
+}
+
+fn main() {
+ no_parameters();
+ unused::<1>();
+ used_binding::<1>();
+ used_substs::<1>();
+}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/functions.rs:3:12
+ |
+LL | #![feature(const_generics, rustc_attrs)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+ --> $DIR/functions.rs:15:8
+ |
+LL | pub fn unused<const T: usize>() {
+ | ^^^^^^ - generic parameter `T` is unused
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+// check-pass
+// compile-flags:-Zpolymorphize=on
+
+pub struct OnDrop<F: Fn()>(pub F);
+
+impl<F: Fn()> Drop for OnDrop<F> {
+ fn drop(&mut self) { }
+}
+
+fn foo<R, S: FnOnce()>(
+ _: R,
+ _: S,
+) {
+ let bar = || {
+ let _ = OnDrop(|| ());
+ };
+ let _ = bar();
+}
+
+fn main() {
+ foo(3u32, || {});
+}
--- /dev/null
+// check-pass
+// compile-flags:-Zpolymorphize=on
+
+pub struct OnDrop<F: Fn()>(pub F);
+
+impl<F: Fn()> Drop for OnDrop<F> {
+ fn drop(&mut self) { }
+}
+
+fn bar<F: FnOnce()>(f: F) {
+ let _ = OnDrop(|| ());
+ f()
+}
+
+fn foo<R, S: FnOnce()>(
+ _: R,
+ _: S,
+) {
+ let bar = || {
+ bar(|| {})
+ };
+ let _ = bar();
+}
+
+fn main() {
+ foo(3u32, || {});
+}
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(const_generics, generators, generator_trait, rustc_attrs)]
+//~^ WARN the feature `const_generics` is incomplete
+
+use std::marker::Unpin;
+use std::ops::{Generator, GeneratorState};
+use std::pin::Pin;
+
+enum YieldOrReturn<Y, R> {
+ Yield(Y),
+ Return(R),
+}
+
+fn finish<T, Y, R>(mut t: T) -> Vec<YieldOrReturn<Y, R>>
+where
+ T: Generator<(), Yield = Y, Return = R> + Unpin,
+{
+ let mut results = Vec::new();
+ loop {
+ match Pin::new(&mut t).resume(()) {
+ GeneratorState::Yielded(yielded) => results.push(YieldOrReturn::Yield(yielded)),
+ GeneratorState::Complete(returned) => {
+ results.push(YieldOrReturn::Return(returned));
+ return results;
+ }
+ }
+ }
+}
+
+// This test checks that the polymorphization analysis functions on generators.
+
+#[rustc_polymorphize_error]
+pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+ //~^ ERROR item has unused generic parameters
+ || {
+ //~^ ERROR item has unused generic parameters
+ yield 1;
+ 2
+ }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_type_in_yield<Y: Default>() -> impl Generator<(), Yield = Y, Return = u32> + Unpin {
+ || {
+ yield Y::default();
+ 2
+ }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_type_in_return<R: Default>() -> impl Generator<(), Yield = u32, Return = R> + Unpin {
+ || {
+ yield 3;
+ R::default()
+ }
+}
+
+#[rustc_polymorphize_error]
+pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+ //~^ ERROR item has unused generic parameters
+ || {
+ //~^ ERROR item has unused generic parameters
+ yield 1;
+ 2
+ }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_const_in_yield<const Y: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin
+{
+ || {
+ yield Y;
+ 2
+ }
+}
+
+#[rustc_polymorphize_error]
+pub fn used_const_in_return<const R: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin
+{
+ || {
+ yield 4;
+ R
+ }
+}
+
+fn main() {
+ finish(unused_type::<u32>());
+ finish(used_type_in_yield::<u32>());
+ finish(used_type_in_return::<u32>());
+ finish(unused_const::<1u32>());
+ finish(used_const_in_yield::<1u32>());
+ finish(used_const_in_return::<1u32>());
+}
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/generators.rs:3:12
+ |
+LL | #![feature(const_generics, generators, generator_trait, rustc_attrs)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: item has unused generic parameters
+ --> $DIR/generators.rs:36:5
+ |
+LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+ | - generic parameter `T` is unused
+LL |
+LL | / || {
+LL | |
+LL | | yield 1;
+LL | | 2
+LL | | }
+ | |_____^
+
+error: item has unused generic parameters
+ --> $DIR/generators.rs:34:8
+ |
+LL | pub fn unused_type<T>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+ | ^^^^^^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+ --> $DIR/generators.rs:62:5
+ |
+LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+ | - generic parameter `T` is unused
+LL |
+LL | / || {
+LL | |
+LL | | yield 1;
+LL | | 2
+LL | | }
+ | |_____^
+
+error: item has unused generic parameters
+ --> $DIR/generators.rs:60:8
+ |
+LL | pub fn unused_const<const T: u32>() -> impl Generator<(), Yield = u32, Return = u32> + Unpin {
+ | ^^^^^^^^^^^^ - generic parameter `T` is unused
+
+error: aborting due to 4 previous errors; 1 warning emitted
+
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that the polymorphization analysis doesn't break when the
+// function/closure doesn't just have generic parameters.
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<'a, T>(_: &'a u32) {
+ //~^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
+ let _: T = Default::default();
+ let add_one = |x: u32| x + 1;
+ //~^ ERROR item has unused generic parameters
+ add_one(3)
+}
+
+fn main() {
+ unused::<u32>(&3);
+ used::<u32>(&3);
+}
--- /dev/null
+error: item has unused generic parameters
+ --> $DIR/lifetimes.rs:10:8
+ |
+LL | pub fn unused<'a, T>(_: &'a u32) {
+ | ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+ --> $DIR/lifetimes.rs:17:19
+ |
+LL | pub fn used<'a, T: Default>(_: &'a u32) -> u32 {
+ | - generic parameter `T` is unused
+LL | let _: T = Default::default();
+LL | let add_one = |x: u32| x + 1;
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// build-pass
+// compile-flags:-Zpolymorphize=on
+
+pub trait ParallelIterator: Sized {
+ fn drive<C: Consumer<()>>(_: C) {
+ C::into_folder();
+ }
+}
+
+pub trait Consumer<T>: Sized {
+ type Result;
+ fn into_folder() -> Self::Result;
+}
+
+impl ParallelIterator for () {}
+
+impl<F: Fn(), T> Consumer<T> for F {
+ type Result = ();
+ fn into_folder() -> Self::Result {
+ unimplemented!()
+ }
+}
+
+fn main() {
+ <()>::drive(|| ());
+}
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that `T` is considered used in `foo`, because it is used in a predicate for
+// `I`, which is used.
+
+#[rustc_polymorphize_error]
+fn bar<I>() {
+ //~^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+fn foo<I, T>(_: I)
+where
+ I: Iterator<Item = T>,
+{
+ bar::<I>()
+}
+
+fn main() {
+ let x = &[2u32];
+ foo(x.iter());
+}
--- /dev/null
+error: item has unused generic parameters
+ --> $DIR/predicates.rs:9:4
+ |
+LL | fn bar<I>() {
+ | ^^^ - generic parameter `I` is unused
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+fn fop<T>() {}
+
+fn bar<T>() -> &'static fn() {
+ &(fop::<T> as fn())
+}
+pub const FN: &'static fn() = &(fop::<i32> as fn());
+
+fn main() {
+ bar::<u32>();
+ bar::<i32>();
+ (FN)();
+}
--- /dev/null
+// build-pass
+#![feature(rustc_attrs)]
+
+// This test checks that the analysis doesn't panic when there are >64 generic parameters, but
+// instead considers those parameters used.
+
+#[rustc_polymorphize_error]
+fn bar<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA,
+ AB, AC, AD, AE, AF, AG, AH, AI, AJ, AK, AL, AM, AN, AO, AP, AQ, AR, AS, AT, AU, AV, AW,
+ AX, AY, AZ, BA, BB, BC, BD, BE, BF, BG, BH, BI, BJ, BK, BL, BM>()
+{
+ let _: Option<A> = None;
+ let _: Option<B> = None;
+ let _: Option<C> = None;
+ let _: Option<D> = None;
+ let _: Option<E> = None;
+ let _: Option<F> = None;
+ let _: Option<G> = None;
+ let _: Option<H> = None;
+ let _: Option<I> = None;
+ let _: Option<J> = None;
+ let _: Option<K> = None;
+ let _: Option<L> = None;
+ let _: Option<M> = None;
+ let _: Option<N> = None;
+ let _: Option<O> = None;
+ let _: Option<P> = None;
+ let _: Option<Q> = None;
+ let _: Option<R> = None;
+ let _: Option<S> = None;
+ let _: Option<T> = None;
+ let _: Option<U> = None;
+ let _: Option<V> = None;
+ let _: Option<W> = None;
+ let _: Option<X> = None;
+ let _: Option<Y> = None;
+ let _: Option<Z> = None;
+ let _: Option<AA> = None;
+ let _: Option<AB> = None;
+ let _: Option<AC> = None;
+ let _: Option<AD> = None;
+ let _: Option<AE> = None;
+ let _: Option<AF> = None;
+ let _: Option<AG> = None;
+ let _: Option<AH> = None;
+ let _: Option<AI> = None;
+ let _: Option<AJ> = None;
+ let _: Option<AK> = None;
+ let _: Option<AL> = None;
+ let _: Option<AM> = None;
+ let _: Option<AN> = None;
+ let _: Option<AO> = None;
+ let _: Option<AP> = None;
+ let _: Option<AQ> = None;
+ let _: Option<AR> = None;
+ let _: Option<AS> = None;
+ let _: Option<AT> = None;
+ let _: Option<AU> = None;
+ let _: Option<AV> = None;
+ let _: Option<AW> = None;
+ let _: Option<AX> = None;
+ let _: Option<AY> = None;
+ let _: Option<AZ> = None;
+ let _: Option<BA> = None;
+ let _: Option<BB> = None;
+ let _: Option<BC> = None;
+ let _: Option<BD> = None;
+ let _: Option<BE> = None;
+ let _: Option<BF> = None;
+ let _: Option<BG> = None;
+ let _: Option<BH> = None;
+ let _: Option<BI> = None;
+ let _: Option<BJ> = None;
+ let _: Option<BK> = None;
+ let _: Option<BL> = None;
+ let _: Option<BM> = None;
+}
+
+fn main() {
+ bar::<u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+ u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+ u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+ u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32, u32,
+ u32>();
+}
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(stmt_expr_attributes, rustc_attrs)]
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in closures.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {
+ let _ = || {};
+}
+
+// Function has an unused generic parameter in parent and closure.
+#[rustc_polymorphize_error]
+pub fn unused<T>() -> u32 {
+ //~^ ERROR item has unused generic parameters
+
+ let add_one = |x: u32| x + 1;
+ //~^ ERROR item has unused generic parameters
+ add_one(3)
+}
+
+// Function has an unused generic parameter in closure, but not in parent.
+#[rustc_polymorphize_error]
+pub fn used_parent<T: Default>() -> u32 {
+ let _: T = Default::default();
+ let add_one = |x: u32| x + 1;
+ //~^ ERROR item has unused generic parameters
+ add_one(3)
+}
+
+// Function uses generic parameter in value of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding_value<T: Default>() -> T {
+ let x = || {
+ let y: T = Default::default();
+ y
+ };
+
+ x()
+}
+
+// Function uses generic parameter in generic of a binding in closure.
+#[rustc_polymorphize_error]
+pub fn used_binding_generic<T>() -> Option<T> {
+ let x = || {
+ let y: Option<T> = None;
+ y
+ };
+
+ x()
+}
+
+// Function and closure uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument<T>(t: T) -> u32 {
+ let x = |_: T| 3;
+ x(t)
+}
+
+// Closure uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument_closure<T: Default>() -> u32 {
+ let t: T = Default::default();
+
+ let x = |_: T| 3;
+ x(t)
+}
+
+// Closure uses generic parameter as upvar.
+#[rustc_polymorphize_error]
+pub fn used_upvar<T: Default>() -> T {
+ let x: T = Default::default();
+
+ let y = || x;
+ y()
+}
+
+// Closure uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<T>() -> u32 {
+ let x = || unused::<T>();
+ x()
+}
+
+struct Foo<F>(F);
+
+impl<F: Default> Foo<F> {
+ // Function has an unused generic parameter from impl and fn.
+ #[rustc_polymorphize_error]
+ pub fn unused_all<G: Default>() -> u32 {
+ //~^ ERROR item has unused generic parameters
+ let add_one = |x: u32| x + 1;
+ //~^ ERROR item has unused generic parameters
+ add_one(3)
+ }
+
+ // Function uses generic parameter from impl and fn in closure.
+ #[rustc_polymorphize_error]
+ pub fn used_both<G: Default>() -> u32 {
+ let add_one = |x: u32| {
+ let _: F = Default::default();
+ let _: G = Default::default();
+ x + 1
+ };
+
+ add_one(3)
+ }
+
+ // Function uses generic parameter from fn in closure.
+ #[rustc_polymorphize_error]
+ pub fn used_fn<G: Default>() -> u32 {
+ //~^ ERROR item has unused generic parameters
+ let add_one = |x: u32| {
+ //~^ ERROR item has unused generic parameters
+ let _: G = Default::default();
+ x + 1
+ };
+
+ add_one(3)
+ }
+
+ // Function uses generic parameter from impl in closure.
+ #[rustc_polymorphize_error]
+ pub fn used_impl<G: Default>() -> u32 {
+ //~^ ERROR item has unused generic parameters
+ let add_one = |x: u32| {
+ //~^ ERROR item has unused generic parameters
+ let _: F = Default::default();
+ x + 1
+ };
+
+ add_one(3)
+ }
+
+ // Closure uses generic parameter in substitutions to another function.
+ #[rustc_polymorphize_error]
+ pub fn used_substs() -> u32 {
+ let x = || unused::<F>();
+ x()
+ }
+}
+
+fn main() {
+ no_parameters();
+ let _ = unused::<u32>();
+ let _ = used_parent::<u32>();
+ let _ = used_binding_value::<u32>();
+ let _ = used_binding_generic::<u32>();
+ let _ = used_argument(3u32);
+ let _ = used_argument_closure::<u32>();
+ let _ = used_upvar::<u32>();
+ let _ = used_substs::<u32>();
+
+ let _ = Foo::<u32>::unused_all::<u32>();
+ let _ = Foo::<u32>::used_both::<u32>();
+ let _ = Foo::<u32>::used_impl::<u32>();
+ let _ = Foo::<u32>::used_fn::<u32>();
+ let _ = Foo::<u32>::used_substs();
+}
--- /dev/null
+error: item has unused generic parameters
+ --> $DIR/closures.rs:19:19
+ |
+LL | pub fn unused<T>() -> u32 {
+ | - generic parameter `T` is unused
+...
+LL | let add_one = |x: u32| x + 1;
+ | ^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:16:8
+ |
+LL | pub fn unused<T>() -> u32 {
+ | ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:28:19
+ |
+LL | pub fn used_parent<T: Default>() -> u32 {
+ | - generic parameter `T` is unused
+LL | let _: T = Default::default();
+LL | let add_one = |x: u32| x + 1;
+ | ^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:94:23
+ |
+LL | impl<F: Default> Foo<F> {
+ | - generic parameter `F` is unused
+...
+LL | pub fn unused_all<G: Default>() -> u32 {
+ | - generic parameter `G` is unused
+LL |
+LL | let add_one = |x: u32| x + 1;
+ | ^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:92:12
+ |
+LL | impl<F: Default> Foo<F> {
+ | - generic parameter `F` is unused
+...
+LL | pub fn unused_all<G: Default>() -> u32 {
+ | ^^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:128:23
+ |
+LL | pub fn used_impl<G: Default>() -> u32 {
+ | - generic parameter `G` is unused
+LL |
+LL | let add_one = |x: u32| {
+ | _______________________^
+LL | |
+LL | | let _: F = Default::default();
+LL | | x + 1
+LL | | };
+ | |_________^
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:126:12
+ |
+LL | pub fn used_impl<G: Default>() -> u32 {
+ | ^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:115:23
+ |
+LL | impl<F: Default> Foo<F> {
+ | - generic parameter `F` is unused
+...
+LL | let add_one = |x: u32| {
+ | _______________________^
+LL | |
+LL | | let _: G = Default::default();
+LL | | x + 1
+LL | | };
+ | |_________^
+
+error: item has unused generic parameters
+ --> $DIR/closures.rs:113:12
+ |
+LL | impl<F: Default> Foo<F> {
+ | - generic parameter `F` is unused
+...
+LL | pub fn used_fn<G: Default>() -> u32 {
+ | ^^^^^^^
+
+error: aborting due to 9 previous errors
+
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(rustc_attrs)]
+
+// This test checks that the polymorphization analysis correctly detects unused type
+// parameters in functions.
+
+// Function doesn't have any generic parameters to be unused.
+#[rustc_polymorphize_error]
+pub fn no_parameters() {}
+
+// Function has an unused generic parameter.
+#[rustc_polymorphize_error]
+pub fn unused<T>() {
+ //~^ ERROR item has unused generic parameters
+}
+
+// Function uses generic parameter in value of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding_value<T: Default>() {
+ let _: T = Default::default();
+}
+
+// Function uses generic parameter in generic of a binding.
+#[rustc_polymorphize_error]
+pub fn used_binding_generic<T>() {
+ let _: Option<T> = None;
+}
+
+// Function uses generic parameter in argument.
+#[rustc_polymorphize_error]
+pub fn used_argument<T>(_: T) {}
+
+// Function uses generic parameter in substitutions to another function.
+#[rustc_polymorphize_error]
+pub fn used_substs<T>() {
+ unused::<T>()
+}
+
+struct Foo<F>(F);
+
+impl<F: Default> Foo<F> {
+ // Function has an unused generic parameter from impl.
+ #[rustc_polymorphize_error]
+ pub fn unused_impl() {
+ //~^ ERROR item has unused generic parameters
+ }
+
+ // Function has an unused generic parameter from impl and fn.
+ #[rustc_polymorphize_error]
+ pub fn unused_both<G: Default>() {
+ //~^ ERROR item has unused generic parameters
+ }
+
+ // Function uses generic parameter from impl.
+ #[rustc_polymorphize_error]
+ pub fn used_impl() {
+ let _: F = Default::default();
+ }
+
+ // Function uses generic parameter from impl.
+ #[rustc_polymorphize_error]
+ pub fn used_fn<G: Default>() {
+ //~^ ERROR item has unused generic parameters
+ let _: G = Default::default();
+ }
+
+ // Function uses generic parameter from impl.
+ #[rustc_polymorphize_error]
+ pub fn used_both<G: Default>() {
+ let _: F = Default::default();
+ let _: G = Default::default();
+ }
+
+ // Function uses generic parameter in substitutions to another function.
+ #[rustc_polymorphize_error]
+ pub fn used_substs() {
+ unused::<F>()
+ }
+}
+
+fn main() {
+ no_parameters();
+ unused::<u32>();
+ used_binding_value::<u32>();
+ used_binding_generic::<u32>();
+ used_argument(3u32);
+ used_substs::<u32>();
+
+ Foo::<u32>::unused_impl();
+ Foo::<u32>::unused_both::<u32>();
+ Foo::<u32>::used_impl();
+ Foo::<u32>::used_fn::<u32>();
+ Foo::<u32>::used_both::<u32>();
+ Foo::<u32>::used_substs();
+}
--- /dev/null
+error: item has unused generic parameters
+ --> $DIR/functions.rs:14:8
+ |
+LL | pub fn unused<T>() {
+ | ^^^^^^ - generic parameter `T` is unused
+
+error: item has unused generic parameters
+ --> $DIR/functions.rs:45:12
+ |
+LL | impl<F: Default> Foo<F> {
+ | - generic parameter `F` is unused
+...
+LL | pub fn unused_impl() {
+ | ^^^^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/functions.rs:51:12
+ |
+LL | impl<F: Default> Foo<F> {
+ | - generic parameter `F` is unused
+...
+LL | pub fn unused_both<G: Default>() {
+ | ^^^^^^^^^^^ - generic parameter `G` is unused
+
+error: item has unused generic parameters
+ --> $DIR/functions.rs:63:12
+ |
+LL | impl<F: Default> Foo<F> {
+ | - generic parameter `F` is unused
+...
+LL | pub fn used_fn<G: Default>() {
+ | ^^^^^^^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![feature(fn_traits, rustc_attrs, unboxed_closures)]
+
+// This test checks that the polymorphization analysis considers a closure
+// as using all generic parameters if it does an unsizing cast.
+
+#[rustc_polymorphize_error]
+fn foo<T: Default>() {
+ let _: T = Default::default();
+ (|| Box::new(|| {}) as Box<dyn Fn()>)();
+ //~^ ERROR item has unused generic parameters
+ //~^^ ERROR item has unused generic parameters
+}
+
+#[rustc_polymorphize_error]
+fn foo2<T: Default>() {
+ let _: T = Default::default();
+ (|| {
+ let call: extern "rust-call" fn(_, _) = Fn::call;
+ call(&|| {}, ());
+ //~^ ERROR item has unused generic parameters
+ })();
+}
+
+fn main() {
+ foo::<u32>();
+ foo2::<u32>();
+}
--- /dev/null
+error: item has unused generic parameters
+ --> $DIR/unsized_cast.rs:11:18
+ |
+LL | fn foo<T: Default>() {
+ | - generic parameter `T` is unused
+LL | let _: T = Default::default();
+LL | (|| Box::new(|| {}) as Box<dyn Fn()>)();
+ | ^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/unsized_cast.rs:11:5
+ |
+LL | fn foo<T: Default>() {
+ | - generic parameter `T` is unused
+LL | let _: T = Default::default();
+LL | (|| Box::new(|| {}) as Box<dyn Fn()>)();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: item has unused generic parameters
+ --> $DIR/unsized_cast.rs:21:15
+ |
+LL | fn foo2<T: Default>() {
+ | - generic parameter `T` is unused
+...
+LL | call(&|| {}, ());
+ | ^^^^^
+
+error: aborting due to 3 previous errors
+
print-type-size field `.0`: 12 bytes
print-type-size variant `None`: 0 bytes
print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
-print-type-size discriminant: 1 bytes
print-type-size variant `Record`: 7 bytes
-print-type-size field `.pre`: 1 bytes
-print-type-size field `.post`: 2 bytes
print-type-size field `.val`: 4 bytes
+print-type-size field `.post`: 2 bytes
+print-type-size field `.pre`: 1 bytes
print-type-size variant `None`: 0 bytes
+print-type-size end padding: 1 bytes
print-type-size type: `MyOption<Union1<std::num::NonZeroU32>>`: 8 bytes, alignment: 4 bytes
print-type-size discriminant: 4 bytes
print-type-size variant `Some`: 4 bytes
#[proc_macro]
pub fn $name(input: TokenStream) -> TokenStream {
println!("Def site: {:?}", Span::def_site());
- input
+ println!("Input: {:?}", input);
+ let new: TokenStream = input.into_iter().map(|mut t| {
+ t.set_span(Span::def_site());
+ t
+ }).collect();
+ println!("Respanned: {:?}", new);
+ new
}
};
}
use proc_macro::{TokenStream, Span};
make_macro::make_it!(print_def_site);
+
+#[proc_macro]
+pub fn dummy(input: TokenStream) -> TokenStream { input }
// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
+// normalize-stdout-test "#\d+" -> "#CTXT"
#[macro_use]
extern crate test_macros;
PRINT-BANG INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "M",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "A",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
+// normalize-stdout-test "#\d+" -> "#CTXT"
#[macro_use]
extern crate test_macros;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "A",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "identity",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: '!',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
PRINT-ATTR INPUT (DISPLAY): struct B(identity ! ($crate :: S)) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "B",
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "identity",
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: '!',
spacing: Alone,
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #10 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
+// normalize-stdout-test "#\d+" -> "#CTXT"
#[macro_use]
extern crate test_macros;
PRINT-BANG INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "M",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "A",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ;
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "D",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #3 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ;
PRINT-BANG INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "M",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "A",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ;
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "D",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Joint,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ':',
spacing: Alone,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Ident {
ident: "S",
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
],
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
Punct {
ch: ';',
spacing: Alone,
- span: #13 bytes(LO..HI),
+ span: #CTXT bytes(LO..HI),
},
]
// Check what token streams proc macros see when interpolated tokens are passed to them as input.
// check-pass
+// normalize-stdout-test "#\d+" -> "#CTXT"
// aux-build:test-macros.rs
#[macro_use]
stream: TokenStream [
Ident {
ident: "A",
- span: #0 bytes(402..403),
+ span: #CTXT bytes(445..446),
},
],
- span: #3 bytes(269..271),
+ span: #CTXT bytes(312..314),
},
]
PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "const",
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Ident {
ident: "A",
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Punct {
ch: ':',
spacing: Alone,
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Ident {
ident: "u8",
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Punct {
ch: '=',
spacing: Alone,
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Literal {
kind: Integer,
symbol: "0",
suffix: None,
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Punct {
ch: ';',
spacing: Alone,
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct A { }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Ident {
ident: "A",
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: #0 bytes(0..0),
+ span: #CTXT bytes(0..0),
},
]
// aux-build:make-macro.rs
// aux-build:meta-macro.rs
// edition:2018
-// compile-flags: -Z span-debug -Z unpretty=expanded,hygiene
+// compile-flags: -Z span-debug -Z macro-backtrace
// check-pass
+// normalize-stdout-test "#\d+" -> "#CTXT"
// normalize-stdout-test "\d+#" -> "0#"
-// ^ We don't care about symbol ids, so set them all to 0
+//
+// We don't care about symbol ids, so we set them all to 0
// in the stdout
extern crate meta_macro;
+macro_rules! produce_it {
+ () => {
+ // `print_def_site!` will respan the `$crate` identifier
+ // with `Span::def_site()`. This should cause it to resolve
+ // relative to `meta_macro`, *not* `make_macro` (despite
+ // the fact that that `print_def_site` is produced by
+ // a `macro_rules!` macro in `make_macro`).
+ meta_macro::print_def_site!($crate::dummy!());
+ }
+}
+
fn main() {
- meta_macro::print_def_site!();
+ produce_it!();
}
-Def site: $DIR/auxiliary/make-macro.rs:7:9: 10:10 (#3)
-#![feature /* 0#0 */(prelude_import)]
-#[prelude_import /* 0#1 */]
-use std /* 0#1 */::prelude /* 0#1 */::v1 /* 0#1 */::*;
-#[macro_use /* 0#1 */]
-extern crate std /* 0#1 */;
-// aux-build:make-macro.rs
-// aux-build:meta-macro.rs
-// edition:2018
-// compile-flags: -Z span-debug -Z unpretty=expanded,hygiene
-// check-pass
-// normalize-stdout-test "\d+#" -> "0#"
-// ^ We don't care about symbol ids, so set them all to 0
-// in the stdout
-extern crate meta_macro /* 0#0 */;
-
-fn main /* 0#0 */() { }
-
-/*
-Expansions:
-0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
-1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
-2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
-
-SyntaxContexts:
-#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
-#1: parent: #0, outer_mark: (ExpnId(1), Opaque)
-#2: parent: #0, outer_mark: (ExpnId(1), Transparent)
-#3: parent: #0, outer_mark: (ExpnId(2), Opaque)
-#4: parent: #0, outer_mark: (ExpnId(2), Transparent)
-#5: parent: #0, outer_mark: (ExpnId(2), SemiTransparent)
-*/
+Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT)
+Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:20:37: 20:43 (#CTXT) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:20:43: 20:45 (#CTXT) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:20:43: 20:45 (#CTXT) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:20:45: 20:50 (#CTXT) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:20:50: 20:51 (#CTXT) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:20:51: 20:53 (#CTXT) }]
+Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }]
// aux-build:meta-macro.rs
// edition:2018
// compile-flags: -Z span-debug
+// normalize-stdout-test "#\d+" -> "#CTXT"
// run-pass
extern crate meta_macro;
-Def site: $DIR/auxiliary/make-macro.rs:7:9: 10:10 (#3)
+Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT)
+Input: TokenStream []
+Respanned: TokenStream []
// aux-build:nested-macro-rules.rs
// aux-build:test-macros.rs
// compile-flags: -Z span-debug
+// normalize-stdout-test "#\d+" -> "#CTXT"
// edition:2018
extern crate nested_macro_rules;
stream: TokenStream [
Ident {
ident: "FirstStruct",
- span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#3),
+ span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#CTXT),
},
],
- span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#3),
+ span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#CTXT),
},
]
PRINT-BANG INPUT (DISPLAY): SecondStruct
stream: TokenStream [
Ident {
ident: "SecondStruct",
- span: $DIR/nested-macro-rules.rs:18:38: 18:50 (#9),
+ span: $DIR/nested-macro-rules.rs:19:38: 19:50 (#CTXT),
},
],
- span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#8),
+ span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#CTXT),
},
]
// run-pass
// aux-build:test-macros.rs
// compile-flags: -Z span-debug
+// normalize-stdout-test "#\d+" -> "#CTXT"
// edition:2018
//
// Tests the pretty-printing behavior of inserting `NoDelim` groups
kind: Str,
symbol: "hi",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:42: 13:46 (#3),
+ span: $DIR/nodelim-groups.rs:14:42: 14:46 (#CTXT),
},
Group {
delimiter: None,
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:17:16: 17:17 (#0),
+ span: $DIR/nodelim-groups.rs:18:16: 18:17 (#CTXT),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:17:18: 17:19 (#0),
+ span: $DIR/nodelim-groups.rs:18:18: 18:19 (#CTXT),
},
Group {
delimiter: Parenthesis,
kind: Integer,
symbol: "25",
suffix: None,
- span: $DIR/nodelim-groups.rs:17:21: 17:23 (#0),
+ span: $DIR/nodelim-groups.rs:18:21: 18:23 (#CTXT),
},
],
- span: $DIR/nodelim-groups.rs:17:20: 17:24 (#0),
+ span: $DIR/nodelim-groups.rs:18:20: 18:24 (#CTXT),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:17:25: 17:26 (#0),
+ span: $DIR/nodelim-groups.rs:18:25: 18:26 (#CTXT),
},
Literal {
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:17:27: 17:28 (#0),
+ span: $DIR/nodelim-groups.rs:18:27: 18:28 (#CTXT),
},
],
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#3),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Group {
delimiter: Parenthesis,
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:53: 13:54 (#3),
+ span: $DIR/nodelim-groups.rs:14:53: 14:54 (#CTXT),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:13:55: 13:56 (#3),
+ span: $DIR/nodelim-groups.rs:14:55: 14:56 (#CTXT),
},
Literal {
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:57: 13:58 (#3),
+ span: $DIR/nodelim-groups.rs:14:57: 14:58 (#CTXT),
},
],
- span: $DIR/nodelim-groups.rs:13:52: 13:59 (#3),
+ span: $DIR/nodelim-groups.rs:14:52: 14:59 (#CTXT),
},
]
PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1)
kind: Str,
symbol: "hi",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:42: 13:46 (#8),
+ span: $DIR/nodelim-groups.rs:14:42: 14:46 (#CTXT),
},
Group {
delimiter: None,
kind: Str,
symbol: "hello",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Punct {
ch: '.',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Ident {
ident: "len",
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Literal {
kind: Str,
symbol: "world",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Punct {
ch: '.',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Ident {
ident: "len",
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
],
- span: $DIR/nodelim-groups.rs:13:47: 13:51 (#8),
+ span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
},
Group {
delimiter: Parenthesis,
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:53: 13:54 (#8),
+ span: $DIR/nodelim-groups.rs:14:53: 14:54 (#CTXT),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:13:55: 13:56 (#8),
+ span: $DIR/nodelim-groups.rs:14:55: 14:56 (#CTXT),
},
Literal {
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:13:57: 13:58 (#8),
+ span: $DIR/nodelim-groups.rs:14:57: 14:58 (#CTXT),
},
],
- span: $DIR/nodelim-groups.rs:13:52: 13:59 (#8),
+ span: $DIR/nodelim-groups.rs:14:52: 14:59 (#CTXT),
},
]
impl<'a> Foo for &'a [u8] {}
fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
- let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR cannot infer an appropriate lifetime
+ let x: Box<dyn Foo + 'static> = Box::new(v); //~ ERROR E0759
x
}
fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
- Box::new(v) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(v) //~ ERROR E0759
}
fn c(v: &[u8]) -> Box<dyn Foo> {
// same as previous case due to RFC 599
- Box::new(v) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(v) //~ ERROR E0759
}
fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/region-object-lifetime-in-coercion.rs:8:46
|
LL | fn a(v: &[u8]) -> Box<dyn Foo + 'static> {
LL | fn a(v: &'static [u8]) -> Box<dyn Foo + 'static> {
| ^^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/region-object-lifetime-in-coercion.rs:13:14
|
LL | fn b(v: &[u8]) -> Box<dyn Foo + 'static> {
LL | fn b(v: &'static [u8]) -> Box<dyn Foo + 'static> {
| ^^^^^^^^^^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/region-object-lifetime-in-coercion.rs:19:14
|
LL | fn c(v: &[u8]) -> Box<dyn Foo> {
impl Dog {
pub fn chase_cat(&mut self) {
- let p: &'static mut usize = &mut self.cats_chased; //~ ERROR cannot infer
+ let p: &'static mut usize = &mut self.cats_chased; //~ ERROR E0759
*p += 1;
}
-error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-addr-of-self.rs:7:37
|
+LL | pub fn chase_cat(&mut self) {
+ | --------- this data with an anonymous lifetime `'_`...
LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^
- |
-note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 6:5...
- --> $DIR/regions-addr-of-self.rs:6:5
- |
-LL | / pub fn chase_cat(&mut self) {
-LL | | let p: &'static mut usize = &mut self.cats_chased;
-LL | | *p += 1;
-LL | | }
- | |_____^
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-addr-of-self.rs:7:37
- |
-LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^
- = note: but, the lifetime must be valid for the static lifetime...
-note: ...so that reference does not outlive borrowed content
- --> $DIR/regions-addr-of-self.rs:7:37
- |
-LL | let p: &'static mut usize = &mut self.cats_chased;
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0495`.
+For more information about this error, try `rustc --explain E0759`.
impl<'a, T> X for B<'a, T> {}
fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
- box B(&*v) as Box<dyn X> //~ ERROR cannot infer
+ box B(&*v) as Box<dyn X> //~ ERROR E0759
}
fn main() { }
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-close-object-into-object-2.rs:10:11
|
LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
impl<'a, T> X for B<'a, T> {}
fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
- box B(&*v) as Box<dyn X> //~ ERROR cannot infer
+ box B(&*v) as Box<dyn X> //~ ERROR E0759
}
fn main() {}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-close-object-into-object-4.rs:10:11
|
LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
// This is illegal, because the region bound on `proc` is 'static.
- Box::new(move || { *x }) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(move || { *x }) //~ ERROR E0759
}
fn main() { }
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/regions-proc-bound-capture.rs:9:14
|
LL | fn static_proc(x: &isize) -> Box<dyn FnMut() -> (isize) + 'static> {
--- /dev/null
+// Regression test for #74429, where we didn't think that a type parameter
+// outlived `ReEmpty`.
+
+// check-pass
+
+use std::marker::PhantomData;
+use std::ptr::NonNull;
+
+pub unsafe trait RawData {
+ type Elem;
+}
+
+unsafe impl<A> RawData for OwnedRepr<A> {
+ type Elem = A;
+}
+
+unsafe impl<'a, A> RawData for ViewRepr<&'a A> {
+ type Elem = A;
+}
+
+pub struct OwnedRepr<A> {
+ ptr: PhantomData<A>,
+}
+
+// these Copy impls are not necessary for the repro, but allow the code to compile without error
+// on 1.44.1
+#[derive(Copy, Clone)]
+pub struct ViewRepr<A> {
+ life: PhantomData<A>,
+}
+
+#[derive(Copy, Clone)]
+pub struct ArrayBase<S>
+where
+ S: RawData,
+{
+ ptr: NonNull<S::Elem>,
+}
+
+pub type Array<A> = ArrayBase<OwnedRepr<A>>;
+
+pub type ArrayView<'a, A> = ArrayBase<ViewRepr<&'a A>>;
+
+impl<A, S> ArrayBase<S>
+where
+ S: RawData<Elem = A>,
+{
+ pub fn index_axis(&self) -> ArrayView<'_, A> {
+ unimplemented!()
+ }
+
+ pub fn axis_iter<'a>(&'a self) -> std::iter::Empty<&'a A> {
+ unimplemented!()
+ }
+}
+
+pub fn x<T: Copy>(a: Array<T>) {
+ // drop just avoids a must_use warning
+ drop((0..1).filter(|_| true));
+ let y = a.index_axis();
+ a.axis_iter().for_each(|_| {
+ drop(y);
+ });
+}
+
+fn main() {}
--- /dev/null
+// Regression test for #74429, where we didn't think that a type parameter
+// outlived `ReEmpty`.
+
+// check-pass
+
+use std::marker::PhantomData;
+
+fn apply<T, F: FnOnce(T)>(_: T, _: F) {}
+
+#[derive(Clone, Copy)]
+struct Invariant<T> {
+ t: T,
+ p: PhantomData<fn(T) -> T>,
+}
+
+fn verify_reempty<T>(x: T) {
+ // r is inferred to have type `Invariant<&ReEmpty(U0) T>`
+ let r = Invariant { t: &x, p: PhantomData };
+ // Creates a new universe, all variables from now on are in `U1`, say.
+ let _: fn(&()) = |_| {};
+ // Closure parameter is of type `&ReEmpty(U1) T`, so the closure has an implied
+ // bound of `T: ReEmpty(U1)`
+ apply(&x, |_| {
+ // Requires `typeof(r)` is well-formed, i.e. `T: ReEmpty(U0)`. If we
+ // only have the implied bound from the closure parameter to use this
+ // requires `ReEmpty(U1): ReEmpty(U0)`, which isn't true so we reported
+ // an error.
+ //
+ // This doesn't happen any more because we ensure that `T: ReEmpty(U0)`
+ // is an implicit bound for all type parameters.
+ drop(r);
+ });
+}
+
+fn main() {}
| ^^^ expected an `Fn<()>` closure, found `fn() {foo}`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}`
- = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
| ^^^ expected an `FnMut<()>` closure, found `fn() {foo}`
|
= help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}`
- = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
| ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}`
|
= help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}`
- = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
| ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
|
= help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}`
- = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
| ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
|
= help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}`
- = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
| ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
|
= help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}`
- = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
+ = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }`
= note: `#[target_feature]` functions do not implement the `Fn` traits
error: aborting due to 6 previous errors
// being run when compiling with new LLVM pass manager and ThinLTO.
// Note: The issue occurred only on non-zero opt-level.
//
-// min-llvm-version 9.0
+// min-llvm-version: 9.0
// needs-sanitizer-support
// needs-sanitizer-address
//
impl Foo {
async fn f(self: Pin<&Self>) -> impl Clone { self }
- //~^ ERROR cannot infer an appropriate lifetime
+ //~^ ERROR E0759
}
fn main() {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait-async.rs:8:16
|
LL | async fn f(self: Pin<&Self>) -> impl Clone { self }
struct Foo;
impl Foo {
- fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR cannot infer an appropriate lifetime
+ fn f(self: Pin<&Self>) -> impl Clone { self } //~ ERROR E0759
}
fn main() {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/arbitrary_self_types_pin_lifetime_impl_trait.rs:6:44
|
LL | fn f(self: Pin<&Self>) -> impl Clone { self }
--- /dev/null
+#![feature(min_specialization)]
+
+trait Trait {}
+impl Trait for NonExistent {}
+//~^ ERROR cannot find type `NonExistent` in this scope
+
+fn main() {}
--- /dev/null
+error[E0412]: cannot find type `NonExistent` in this scope
+ --> $DIR/impl-on-nonexisting.rs:4:16
+ |
+LL | impl Trait for NonExistent {}
+ | ^^^^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0412`.
#[rustc_deprecated(since = "b", reason = "text")]
#[rustc_const_unstable(feature = "c", issue = "none")]
#[rustc_const_unstable(feature = "d", issue = "none")] //~ ERROR multiple stability levels
-pub const fn multiple4() { } //~ ERROR multiple rustc_deprecated attributes [E0540]
+pub const fn multiple4() { } //~ ERROR multiple deprecated attributes
//~^ ERROR Invalid stability or deprecation version found
#[rustc_deprecated(since = "a", reason = "text")]
LL | #[stable(feature = "a", since = "b")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0540]: multiple rustc_deprecated attributes
+error[E0550]: multiple deprecated attributes
--> $DIR/stability-attribute-sanity.rs:65:1
|
LL | pub const fn multiple4() { }
error: aborting due to 18 previous errors
-Some errors have detailed explanations: E0539, E0541.
+Some errors have detailed explanations: E0539, E0541, E0550.
For more information about an error, try `rustc --explain E0539`.
--- /dev/null
+error[E0597]: `val` does not live long enough
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+ | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a`
+LL | val.use_self()
+ | ^^^ borrowed value does not live long enough
+LL | }
+ | - `val` dropped here while still borrowed
+ |
+help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+ | ^^^^
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
--- /dev/null
+// FIXME: the following cases need to suggest more things to make users reach a working end state.
+
+mod bav {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+ val.use_self() //~ ERROR E0597
+ }
+}
+
+mod bap {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0515
+ }
+}
+
+// This case in particular requires the user to write all of the bounds we have in `mod bax`.
+mod bay {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod bax {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait<'a> {
+ fn use_self(&'a self) -> &'a () { panic!() }
+ }
+ trait Bar {}
+
+ impl<'a> MyTrait<'a> for Box<dyn ObjectTrait<Assoc = i32> + 'a> {
+ fn use_self(&'a self) -> &'a () { panic!() }
+ }
+ impl Bar for i32 {}
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+ val.use_self()
+ }
+}
+
+mod baw {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {
+ type Assoc: Bar;
+ }
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Bar {}
+
+ impl<'a> MyTrait for Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = Box<dyn Bar>>>) -> impl OtherTrait<'a> + 'a{
+ val.use_self() //~ ERROR E0515
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0597]: `val` does not live long enough
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:21:9
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> {
+ | -- lifetime `'a` defined here ------------------- opaque type requires that `val` is borrowed for `'a`
+LL | val.use_self()
+ | ^^^ borrowed value does not live long enough
+LL | }
+ | - `val` dropped here while still borrowed
+ |
+help: you can add a bound to the opaque type to make it last less than `'static` and match `'a`
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32>>) -> impl OtherTrait<'a> + 'a {
+ | ^^^^
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:43:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error[E0515]: cannot return value referencing function parameter `val`
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:109:9
+ |
+LL | val.use_self()
+ | ---^^^^^^^^^^^
+ | |
+ | returns a value referencing data owned by the current function
+ | `val` is borrowed here
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:66:13
+ |
+LL | fn use_it<'a>(val: Box<dyn ObjectTrait<Assoc = i32> + 'a>) -> &'a () {
+ | -------------------------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {
+ | ^^^^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0515, E0597.
+For more information about an error, try `rustc --explain E0515`.
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+mod foo {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait<T> {}
+ trait MyTrait<T> {
+ fn use_self<K>(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ {
+ fn use_self<K>(&self) -> &() { panic!() }
+ }
+ impl<T> Irrelevant for dyn ObjectTrait<T> {}
+
+ fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ val.use_self::<T>() //~ ERROR E0759
+ }
+}
+
+mod bar {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for dyn ObjectTrait + '_ {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod baz {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for Box<dyn ObjectTrait + '_> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for Box<dyn ObjectTrait> {}
+
+ fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod bat {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+
+ impl dyn ObjectTrait + '_ {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod ban {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait + '_ {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0759
+ }
+}
+
+mod bal {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait + '_ {}
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ MyTrait::use_self(val) //~ ERROR E0759
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9
+ |
+LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ | --- `val` is a reference that is only valid in the function body
+LL | val.use_self::<T>()
+ | ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | --- `val` is a reference that is only valid in the function body
+LL | val.use_self()
+ | ^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+ | --- `val` is a reference that is only valid in the function body
+LL | val.use_self()
+ | ^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error[E0521]: borrowed data escapes outside of function
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | --- `val` is a reference that is only valid in the function body
+LL | MyTrait::use_self(val)
+ | ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+ |
+ = help: consider replacing `'a` with `'static`
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// run-rustfix
+#![allow(dead_code)]
+
+mod foo {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait<T> {}
+ trait MyTrait<T> {
+ fn use_self<K>(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl<T> MyTrait<T> for dyn ObjectTrait<T> {
+ fn use_self<K>(&self) -> &() { panic!() }
+ }
+ impl<T> Irrelevant for dyn ObjectTrait<T> {}
+
+ fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ val.use_self::<T>() //~ ERROR E0759
+ }
+}
+
+mod bar {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for dyn ObjectTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod baz {
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &();
+ }
+ trait Irrelevant {}
+
+ impl MyTrait for Box<dyn ObjectTrait> {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ impl Irrelevant for Box<dyn ObjectTrait> {}
+
+ fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod bat {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+
+ impl dyn ObjectTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ val.use_self() //~ ERROR E0772
+ }
+}
+
+mod ban {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+ val.use_self() //~ ERROR E0759
+ }
+}
+
+mod bal {
+ trait OtherTrait<'a> {}
+ impl<'a> OtherTrait<'a> for &'a () {}
+
+ trait ObjectTrait {}
+ trait MyTrait {
+ fn use_self(&self) -> &() { panic!() }
+ }
+ trait Irrelevant {
+ fn use_self(&self) -> &() { panic!() }
+ }
+
+ impl MyTrait for dyn ObjectTrait {}
+ impl Irrelevant for dyn ObjectTrait {}
+
+ fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ MyTrait::use_self(val) //~ ERROR E0759
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:13
+ |
+LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
+ | ---------------------- this data with lifetime `'a`...
+LL | val.use_self::<T>()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32
+ |
+LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> {
+ | ^^^^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self<K>(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl<T> MyTrait<T> for dyn ObjectTrait<T> + '_ {
+ | ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:13
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | ------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl`
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14
+ |
+LL | impl dyn ObjectTrait {
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl dyn ObjectTrait + '_ {
+ | ^^^^
+
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:13
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
+ | ------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26
+ |
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL | impl MyTrait for dyn ObjectTrait {}
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for dyn ObjectTrait + '_ {}
+ | ^^^^
+help: to declare that the `impl Trait` captures data from argument `val`, you can add an explicit `'a` lifetime bound
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | ^^^^
+
+error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:27
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
+ | ------------------- this data with lifetime `'a`...
+LL | MyTrait::use_self(val)
+ | ^^^ ...is captured here...
+ |
+note: ...and is required to live as long as `'static` here
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
+ |
+LL | MyTrait::use_self(val)
+ | ^^^^^^^^^^^^^^^^^
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:104:26
+ |
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+...
+LL | impl MyTrait for dyn ObjectTrait {}
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for dyn ObjectTrait + '_ {}
+ | ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:37:13
+ |
+LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () {
+ | ------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26
+ |
+LL | impl MyTrait for dyn ObjectTrait {
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for dyn ObjectTrait + '_ {
+ | ^^^^
+
+error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an implicit `'static` lifetime requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:54:13
+ |
+LL | fn use_it<'a>(val: &'a Box<dyn ObjectTrait + 'a>) -> &'a () {
+ | ----------------------------- this data with lifetime `'a`...
+LL | val.use_self()
+ | ^^^^^^^^ ...is captured and required to live as long as `'static` here
+ |
+note: the used `impl` has a `'static` requirement
+ --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait> {
+ | ^^^^^^^^^^^ this has an implicit `'static` lifetime requirement
+LL | fn use_self(&self) -> &() { panic!() }
+ | -------- calling this method introduces the `impl`'s 'static` requirement
+help: consider relaxing the implicit `'static` requirement
+ |
+LL | impl MyTrait for Box<dyn ObjectTrait + '_> {
+ | ^^^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0759`.
where
G: Get<T>
{
- move || { //~ ERROR cannot infer an appropriate lifetime
+ move || { //~ ERROR `dest`
*dest = g.get();
}
}
| |
| help: consider introducing lifetime `'a` here: `'a,`
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `dest` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/missing-lifetimes-in-signature.rs:19:5
|
LL | fn foo<G, T>(g: G, dest: &mut T) -> impl FnOnce()
fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
Iter {
current: None,
- remaining: self.0.iter(), //~ ERROR cannot infer an appropriate lifetime
+ remaining: self.0.iter(), //~ ERROR E0759
}
}
}
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:30:31
|
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> {
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:41:31
|
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo>> + '_ {
LL | fn iter(&self) -> impl Iterator<Item = Box<dyn Foo + '_>> + '_ {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:52:31
|
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> + 'a {
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo + 'a>> + 'a {
| ^^^^
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `self` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/trait-object-nested-in-impl-trait.rs:63:31
|
LL | fn iter<'a>(&'a self) -> impl Iterator<Item = Box<dyn Foo>> {
--- /dev/null
+fn main() {
+ let _ = vec![1, 2, 3].into_iter().collect::Vec<_>();
+ //~^ ERROR generic parameters without surrounding angle brackets
+ let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>>();
+ //~^ ERROR generic parameters without surrounding angle brackets
+ let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>();
+ //~^ ERROR generic parameters without surrounding angle brackets
+ let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>();
+ //~^ ERROR generic parameters without surrounding angle brackets
+}
--- /dev/null
+error: generic parameters without surrounding angle brackets
+ --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:2:48
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>();
+ | ^^^^^^
+ |
+help: surround the type parameters with angle brackets
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
+ | ^ ^
+
+error: generic parameters without surrounding angle brackets
+ --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:4:48
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>>();
+ | ^^^^^^
+ |
+help: surround the type parameters with angle brackets
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
+ | ^ ^
+
+error: generic parameters without surrounding angle brackets
+ --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:6:48
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>>();
+ | ^^^^^^
+ |
+help: surround the type parameters with angle brackets
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
+ | ^ ^
+
+error: generic parameters without surrounding angle brackets
+ --> $DIR/recover-missing-turbofish-surrounding-angle-braket.rs:8:48
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::Vec<_>>();
+ | ^^^^^^
+ |
+help: surround the type parameters with angle brackets
+ |
+LL | let _ = vec![1, 2, 3].into_iter().collect::<Vec<_>>();
+ | ^ ^
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+// Regression test for #72410, this should be used with debug assertion enabled.
+
+// should be fine
+pub trait Foo {
+ fn map()
+ where
+ Self: Sized,
+ for<'a> &'a mut [u8]: ;
+}
+
+// should fail
+pub trait Bar {
+ fn map()
+ where for<'a> &'a mut [dyn Bar]: ;
+ //~^ ERROR: the trait `Bar` cannot be made into an object
+}
+
+fn main() {}
--- /dev/null
+error[E0038]: the trait `Bar` cannot be made into an object
+ --> $DIR/issue-72410.rs:14:19
+ |
+LL | pub trait Bar {
+ | --- this trait cannot be made into an object...
+LL | fn map()
+ | --- ...because associated function `map` has no `self` parameter
+LL | where for<'a> &'a mut [dyn Bar]: ;
+ | ^^^^^^^^^^^^^^^^^ the trait `Bar` cannot be made into an object
+ |
+help: consider turning `map` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects
+ |
+LL | where for<'a> &'a mut [dyn Bar]:, Self: Sized ;
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
#![feature(never_type)]
use std::mem::size_of;
-use std::num::NonZeroU8;
struct t {a: u8, b: i8}
struct u {a: u8, b: i8, c: u8}
None
}
-// Two layouts are considered for `CanBeNicheFilledButShouldnt`:
-// Niche-filling:
-// { u32 (4 bytes), NonZeroU8 + tag in niche (1 byte), padding (3 bytes) }
-// Tagged:
-// { tag (1 byte), NonZeroU8 (1 byte), padding (2 bytes), u32 (4 bytes) }
-// Both are the same size (due to padding),
-// but the tagged layout is better as the tag creates a niche with 254 invalid values,
-// allowing types like `Option<Option<CanBeNicheFilledButShouldnt>>` to fit into 8 bytes.
-pub enum CanBeNicheFilledButShouldnt {
- A(NonZeroU8, u32),
- B
-}
-pub enum AlwaysTaggedBecauseItHasNoNiche {
- A(u8, u32),
- B
-}
-
pub fn main() {
assert_eq!(size_of::<u8>(), 1 as usize);
assert_eq!(size_of::<u32>(), 4 as usize);
assert_eq!(size_of::<Option<Option<(&(), bool)>>>(), size_of::<(bool, &())>());
assert_eq!(size_of::<Option<Option2<bool, &()>>>(), size_of::<(bool, &())>());
assert_eq!(size_of::<Option<Option2<&(), bool>>>(), size_of::<(bool, &())>());
-
- assert_eq!(size_of::<CanBeNicheFilledButShouldnt>(), 8);
- assert_eq!(size_of::<Option<CanBeNicheFilledButShouldnt>>(), 8);
- assert_eq!(size_of::<Option<Option<CanBeNicheFilledButShouldnt>>>(), 8);
- assert_eq!(size_of::<AlwaysTaggedBecauseItHasNoNiche>(), 8);
- assert_eq!(size_of::<Option<AlwaysTaggedBecauseItHasNoNiche>>(), 8);
- assert_eq!(size_of::<Option<Option<AlwaysTaggedBecauseItHasNoNiche>>>(), 8);
}
const D: _ = 42;
//~^ ERROR the type placeholder `_` is not allowed within types on item signatures
// type E: _; // FIXME: make the parser propagate the existence of `B`
+ type F: std::ops::Fn(_);
+ //~^ ERROR the type placeholder `_` is not allowed within types on item signatures
}
impl Qux for Struct {
type A = _;
| ^ expected identifier, found reserved identifier
error: associated constant in `impl` without body
- --> $DIR/typeck_type_placeholder_item.rs:203:5
+ --> $DIR/typeck_type_placeholder_item.rs:205:5
|
LL | const C: _;
| ^^^^^^^^^^-
| not allowed in type signatures
| help: replace `_` with the correct type: `i32`
+error[E0121]: the type placeholder `_` is not allowed within types on item signatures
+ --> $DIR/typeck_type_placeholder_item.rs:197:26
+ |
+LL | type F: std::ops::Fn(_);
+ | ^ not allowed in type signatures
+
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
--> $DIR/typeck_type_placeholder_item.rs:40:24
|
| help: replace with the correct return type: `main::FnTest9`
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:199:14
+ --> $DIR/typeck_type_placeholder_item.rs:201:14
|
LL | type A = _;
| ^ not allowed in type signatures
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:201:14
+ --> $DIR/typeck_type_placeholder_item.rs:203:14
|
LL | type B = _;
| ^ not allowed in type signatures
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:203:14
+ --> $DIR/typeck_type_placeholder_item.rs:205:14
|
LL | const C: _;
| ^ not allowed in type signatures
error[E0121]: the type placeholder `_` is not allowed within types on item signatures
- --> $DIR/typeck_type_placeholder_item.rs:206:14
+ --> $DIR/typeck_type_placeholder_item.rs:208:14
|
LL | const D: _ = 42;
| ^
| not allowed in type signatures
| help: replace `_` with the correct type: `i32`
-error: aborting due to 66 previous errors
+error: aborting due to 67 previous errors
Some errors have detailed explanations: E0121, E0282, E0403.
For more information about an error, try `rustc --explain E0121`.
fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
// ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static`
- Box::new(items.iter()) //~ ERROR cannot infer an appropriate lifetime
+ Box::new(items.iter()) //~ ERROR E0759
}
fn b<T>(items: &[T]) -> Box<dyn Iterator<Item=&T> + '_> {
-error[E0759]: cannot infer an appropriate lifetime
+error[E0759]: `items` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> $DIR/dyn-trait-underscore.rs:8:20
|
LL | fn a<T>(items: &[T]) -> Box<dyn Iterator<Item=&T>> {
error[E0277]: the size for values of type `X` cannot be known at compilation time
- --> $DIR/unsized-trait-impl-self-type.rs:10:17
+ --> $DIR/unsized-trait-impl-self-type.rs:10:27
|
LL | struct S5<Y>(Y);
| - required by this bound in `S5`
LL |
LL | impl<X: ?Sized> T3<X> for S5<X> {
- | - ^^^^^ doesn't have a size known at compile-time
+ | - ^^^^^ doesn't have a size known at compile-time
| |
| this type parameter needs to be `std::marker::Sized`
|
--- /dev/null
+pub trait Unsatisfied {}
+
+#[repr(transparent)]
+pub struct Bar<T: Unsatisfied>(T);
+
+pub trait Foo {
+ type Assoc;
+}
+
+extern "C" {
+ pub fn lint_me() -> <() as Foo>::Assoc;
+ //~^ ERROR: the trait bound `(): Foo` is not satisfied [E0277]
+
+ pub fn lint_me_aswell() -> Bar<u32>;
+ //~^ ERROR: the trait bound `u32: Unsatisfied` is not satisfied [E0277]
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `(): Foo` is not satisfied
+ --> $DIR/wf-foreign-fn-decl-ret.rs:11:5
+ |
+LL | pub fn lint_me() -> <() as Foo>::Assoc;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
+
+error[E0277]: the trait bound `u32: Unsatisfied` is not satisfied
+ --> $DIR/wf-foreign-fn-decl-ret.rs:14:32
+ |
+LL | pub struct Bar<T: Unsatisfied>(T);
+ | ----------- required by this bound in `Bar`
+...
+LL | pub fn lint_me_aswell() -> Bar<u32>;
+ | ^^^^^^^^ the trait `Unsatisfied` is not implemented for `u32`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// Tests that we point at the proper location for an error
+// involving the self-type of an impl
+
+trait Foo {}
+impl Foo for Option<[u8]> {} //~ ERROR the size for
+
+fn main() {}
--- /dev/null
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/wf-impl-self-type.rs:5:14
+ |
+LL | impl Foo for Option<[u8]> {}
+ | ^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ ::: $SRC_DIR/libcore/option.rs:LL:COL
+ |
+LL | pub enum Option<T> {
+ | - required by this bound in `std::option::Option`
+ |
+ = help: the trait `std::marker::Sized` is not implemented for `[u8]`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
-Subproject commit 43cf77395cad5b79887b20b7cf19d418bbd703a9
+Subproject commit aa6872140ab0fa10f641ab0b981d5330d419e927
if [[ $BETA = "true" ]]; then
echo "Update documentation for the beta release"
- cp -r out/master out/beta
+ cp -r out/master/* out/beta
fi
# Generate version index that is shown as root index page
git config user.name "GHA CI"
git config user.email "gha@ci.invalid"
-if git diff --exit-code --quiet; then
- echo "No changes to the output on this push; exiting."
- exit 0
-fi
-
if [[ -n $TAG_NAME ]]; then
+ # track files, so that the following check works
+ git add --intent-to-add "$TAG_NAME"
+ if git diff --exit-code --quiet -- $TAG_NAME/; then
+ echo "No changes to the output on this push; exiting."
+ exit 0
+ fi
# Add the new dir
git add "$TAG_NAME"
# Update the symlink
git add versions.json
git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}"
elif [[ $BETA = "true" ]]; then
+ if git diff --exit-code --quiet -- beta/; then
+ echo "No changes to the output on this push; exiting."
+ exit 0
+ fi
git add beta
git commit -m "Automatic deploy to GitHub Pages (beta): ${SHA}"
else
+ if git diff --exit-code --quiet; then
+ echo "No changes to the output on this push; exiting."
+ exit 0
+ fi
git add .
git commit -m "Automatic deploy to GitHub Pages: ${SHA}"
fi
-# Change Log
+# Changelog
All notable changes to this project will be documented in this file.
See [Changelog Update](doc/changelog_update.md) if you want to update this
## Unreleased / In Rust Nightly
-[7ea7cd1...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master)
+[c2c07fa...master](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master)
+
+## Rust 1.46
+
+Current beta, release 2020-08-27
+
+[7ea7cd1...c2c07fa](https://github.com/rust-lang/rust-clippy/compare/7ea7cd1...master)
+
+### New lints
+
+* [`unnested_or_patterns`] [#5378](https://github.com/rust-lang/rust-clippy/pull/5378)
+* [`iter_next_slice`] [#5597](https://github.com/rust-lang/rust-clippy/pull/5597)
+* [`unnecessary_sort_by`] [#5623](https://github.com/rust-lang/rust-clippy/pull/5623)
+* [`vec_resize_to_zero`] [#5637](https://github.com/rust-lang/rust-clippy/pull/5637)
+
+### Moves and Deprecations
+
+* Move [`cast_ptr_alignment`] to pedantic [#5667](https://github.com/rust-lang/rust-clippy/pull/5667)
+
+### Enhancements
+
+* Improve [`mem_replace_with_uninit`] lint [#5695](https://github.com/rust-lang/rust-clippy/pull/5695)
+
+### False Positive Fixes
+
+* [`len_zero`]: Avoid linting ranges when the `range_is_empty` feature is not enabled
+ [#5656](https://github.com/rust-lang/rust-clippy/pull/5656)
+* [`let_and_return`]: Don't lint if a temporary borrow is involved
+ [#5680](https://github.com/rust-lang/rust-clippy/pull/5680)
+* [`reversed_empty_ranges`]: Avoid linting `N..N` in for loop arguments in
+ [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
+* [`if_same_then_else`]: Don't assume multiplication is always commutative
+ [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
+* [`blacklisted_name`]: Remove `bar` from the default configuration
+ [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
+* [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
+ [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
+
+### Suggestion Fixes/Improvements
+
+* Fix suggestion of [`unit_arg`] lint, so that it suggest semantic equivalent code
+ [#4455](https://github.com/rust-lang/rust-clippy/pull/4455)
+* Add auto applicable suggestion to [`macro_use_imports`]
+ [#5279](https://github.com/rust-lang/rust-clippy/pull/5279)
+
+### ICE Fixes
+
+* Fix ICE in the `consts` module of Clippy [#5709](https://github.com/rust-lang/rust-clippy/pull/5709)
+
+### Documentation Improvements
+
+* Improve code examples across multiple lints [#5664](https://github.com/rust-lang/rust-clippy/pull/5664)
+
+### Others
+
+* Introduce a `--rustc` flag to `clippy-driver`, which turns `clippy-driver`
+ into `rustc` and passes all the given arguments to `rustc`. This is especially
+ useful for tools that need the `rustc` version Clippy was compiled with,
+ instead of the Clippy version. E.g. `clippy-driver --rustc --version` will
+ print the output of `rustc --version`.
+ [#5178](https://github.com/rust-lang/rust-clippy/pull/5178)
+* New issue templates now make it easier to complain if Clippy is too annoying
+ or not annoying enough! [#5735](https://github.com/rust-lang/rust-clippy/pull/5735)
## Rust 1.45
-Current beta, release 2020-07-16
+Current stable, released 2020-07-16
[891e1a8...7ea7cd1](https://github.com/rust-lang/rust-clippy/compare/891e1a8...7ea7cd1)
## Rust 1.44
-Current stable, released 2020-06-04
+Released 2020-06-04
[204bb9b...891e1a8](https://github.com/rust-lang/rust-clippy/compare/204bb9b...891e1a8)
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
+[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
## Usage
-Since this is a tool for helping the developer of a library or application
-write better code, it is recommended not to include Clippy as a hard dependency.
-Options include using it as an optional dependency, as a cargo subcommand, or
-as an included feature during build. These options are detailed below.
+Below are instructions on how to use Clippy as a subcommand, compiled from source
+or in Travis CI.
### As a cargo subcommand (`cargo clippy`)
///
/// **Deprecation reason:** Associated-constants are now preferred.
pub REPLACE_CONSTS,
- "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants"
+ "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants"
}
declare_deprecated_lint! {
declare_clippy_lint! {
/// **What it does:** Checks for explicit `deref()` or `deref_mut()` method calls.
///
- /// **Why is this bad?** Derefencing by `&*x` or `&mut *x` is clearer and more concise,
+ /// **Why is this bad?** Dereferencing by `&*x` or `&mut *x` is clearer and more concise,
/// when not part of a method chain.
///
/// **Example:**
..
} = item.kind
{
- // Remember for each inherent implementation encoutered its span and generics
+ // Remember for each inherent implementation encountered its span and generics
// but filter out implementations that have generic params (type or lifetime)
// or are derived from a macro
if !in_macro(item.span) && generics.params.is_empty() {
mod question_mark;
mod ranges;
mod redundant_clone;
+mod redundant_closure_call;
mod redundant_field_names;
mod redundant_pub_crate;
mod redundant_static_lifetimes;
mod try_err;
mod types;
mod unicode;
+mod unit_return_expecting_ord;
mod unnamed_address;
mod unnecessary_sort_by;
mod unnested_or_patterns;
);
store.register_removed(
"clippy::replace_consts",
- "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants",
+ "associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants",
);
store.register_removed(
"clippy::regex_macro",
&misc_early::DOUBLE_NEG,
&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
&misc_early::MIXED_CASE_HEX_LITERALS,
- &misc_early::REDUNDANT_CLOSURE_CALL,
&misc_early::REDUNDANT_PATTERN,
&misc_early::UNNEEDED_FIELD_PATTERN,
&misc_early::UNNEEDED_WILDCARD_PATTERN,
&ranges::RANGE_ZIP_WITH_LEN,
&ranges::REVERSED_EMPTY_RANGES,
&redundant_clone::REDUNDANT_CLONE,
+ &redundant_closure_call::REDUNDANT_CLOSURE_CALL,
&redundant_field_names::REDUNDANT_FIELD_NAMES,
&redundant_pub_crate::REDUNDANT_PUB_CRATE,
&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
&unicode::NON_ASCII_LITERAL,
&unicode::UNICODE_NOT_NFC,
&unicode::ZERO_WIDTH_SPACE,
+ &unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
&unnamed_address::FN_ADDRESS_COMPARISONS,
&unnamed_address::VTABLE_ADDRESS_COMPARISONS,
&unnecessary_sort_by::UNNECESSARY_SORT_BY,
store.register_late_pass(|| box attrs::Attributes);
store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions);
store.register_late_pass(|| box unicode::Unicode);
+ store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd);
store.register_late_pass(|| box strings::StringAdd);
store.register_late_pass(|| box implicit_return::ImplicitReturn);
store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
store.register_early_pass(|| box int_plus_one::IntPlusOne);
store.register_early_pass(|| box formatting::Formatting);
store.register_early_pass(|| box misc_early::MiscEarlyLints);
+ store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall);
+ store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall);
store.register_early_pass(|| box returns::Return);
store.register_late_pass(|| box let_and_return::LetReturn);
store.register_early_pass(|| box collapsible_if::CollapsibleIf);
LintId::of(&misc_early::DOUBLE_NEG),
LintId::of(&misc_early::DUPLICATE_UNDERSCORE_ARGUMENT),
LintId::of(&misc_early::MIXED_CASE_HEX_LITERALS),
- LintId::of(&misc_early::REDUNDANT_CLOSURE_CALL),
LintId::of(&misc_early::REDUNDANT_PATTERN),
LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(&misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
LintId::of(&redundant_clone::REDUNDANT_CLONE),
+ LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
LintId::of(&reference::DEREF_ADDROF),
LintId::of(&types::UNNECESSARY_CAST),
LintId::of(&types::VEC_BOX),
LintId::of(&unicode::ZERO_WIDTH_SPACE),
+ LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY),
LintId::of(&methods::UNNECESSARY_FILTER_MAP),
LintId::of(&methods::USELESS_ASREF),
LintId::of(&misc::SHORT_CIRCUIT_STATEMENT),
- LintId::of(&misc_early::REDUNDANT_CLOSURE_CALL),
LintId::of(&misc_early::UNNEEDED_WILDCARD_PATTERN),
LintId::of(&misc_early::ZERO_PREFIXED_LITERAL),
LintId::of(&needless_bool::BOOL_COMPARISON),
LintId::of(&precedence::PRECEDENCE),
LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
+ LintId::of(&redundant_closure_call::REDUNDANT_CLOSURE_CALL),
LintId::of(&reference::DEREF_ADDROF),
LintId::of(&reference::REF_IN_DEREF),
LintId::of(&repeat_once::REPEAT_ONCE),
LintId::of(&types::CAST_REF_TO_MUT),
LintId::of(&types::UNIT_CMP),
LintId::of(&unicode::ZERO_WIDTH_SPACE),
+ LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS),
LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS),
LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT),
}
}
+ let result_expr = match &op.kind {
+ ExprKind::AddrOf(_, _, borrowed) => borrowed,
+ _ => op,
+ };
span_lint_and_then(
cx,
REDUNDANT_PATTERN_MATCHING,
// while let ... = ... { ... }
// ^^^
- let op_span = op.span.source_callsite();
+ let op_span = result_expr.span.source_callsite();
// while let ... = ... { ... }
// ^^^^^^^^^^^^^^^^^^^
};
if let Some(good_method) = found_good_method {
+ let span = expr.span.to(op.span);
+ let result_expr = match &op.kind {
+ ExprKind::AddrOf(_, _, borrowed) => borrowed,
+ _ => op,
+ };
span_lint_and_then(
cx,
REDUNDANT_PATTERN_MATCHING,
expr.span,
&format!("redundant pattern matching, consider using `{}`", good_method),
|diag| {
- let span = expr.span.to(op.span);
diag.span_suggestion(
span,
"try this",
- format!("{}.{}", snippet(cx, op.span, "_"), good_method),
+ format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
Applicability::MaybeIncorrect, // snippet
);
},
cx,
ITER_NTH_ZERO,
expr.span,
- "called `.nth(0)` on a `std::iter::Iterator`",
- "try calling",
+ "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
+ "try calling `.next()` instead of `.nth(0)`",
format!("{}.next()", snippet_with_applicability(cx, nth_args[0].span, "..", &mut applicability)),
applicability,
);
if let hir::ExprKind::Path(qpath) = &args[0].kind;
if let hir::def::Res::Local(local_id) = cx.qpath_res(qpath, args[0].hir_id);
if closure_body.params[0].pat.hir_id == local_id;
- let adj = cx.typeck_results().expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
+ let adj = cx
+ .typeck_results()
+ .expr_adjustments(&args[0])
+ .iter()
+ .map(|x| &x.kind)
+ .collect::<Box<[_]>>();
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
then {
let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
/// if y != x {} // where both are floats
///
/// // Good
- /// let error = 0.01f64; // Use an epsilon for comparison
+ /// let error = f64::EPSILON; // Use an epsilon for comparison
+ /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+ /// // let error = std::f64::EPSILON;
/// if (y - 1.23f64).abs() < error { }
/// if (y - x).abs() > error { }
/// ```
/// const ONE: f64 = 1.00;
///
/// // Bad
- /// if x == ONE { } // where both are floats
+ /// if x == ONE { } // where both are floats
///
/// // Good
- /// let error = 0.1f64; // Use an epsilon for comparison
+ /// let error = f64::EPSILON; // Use an epsilon for comparison
+ /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
+ /// // let error = std::f64::EPSILON;
/// if (x - ONE).abs() < error { }
/// ```
pub FLOAT_CMP_CONST,
-use crate::utils::{
- constants, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help, span_lint_and_sugg,
- span_lint_and_then,
-};
-use if_chain::if_chain;
+use crate::utils::{constants, snippet_opt, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use rustc_ast::ast::{
- BindingMode, Block, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability,
- NodeId, Pat, PatKind, StmtKind, UnOp,
+ BindingMode, Expr, ExprKind, GenericParamKind, Generics, Lit, LitFloatType, LitIntType, LitKind, Mutability,
+ NodeId, Pat, PatKind, UnOp,
};
-use rustc_ast::visit::{walk_expr, FnKind, Visitor};
+use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
"function arguments having names which only differ by an underscore"
}
-declare_clippy_lint! {
- /// **What it does:** Detects closures called in the same expression where they
- /// are defined.
- ///
- /// **Why is this bad?** It is unnecessarily adding to the expression's
- /// complexity.
- ///
- /// **Known problems:** None.
- ///
- /// **Example:**
- /// ```rust,ignore
- /// // Bad
- /// let a = (|| 42)()
- ///
- /// // Good
- /// let a = 42
- /// ```
- pub REDUNDANT_CLOSURE_CALL,
- complexity,
- "throwaway closures called in the expression they are defined"
-}
-
declare_clippy_lint! {
/// **What it does:** Detects expressions of the form `--x`.
///
declare_lint_pass!(MiscEarlyLints => [
UNNEEDED_FIELD_PATTERN,
DUPLICATE_UNDERSCORE_ARGUMENT,
- REDUNDANT_CLOSURE_CALL,
DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
UNNEEDED_WILDCARD_PATTERN,
]);
-// Used to find `return` statements or equivalents e.g., `?`
-struct ReturnVisitor {
- found_return: bool,
-}
-
-impl ReturnVisitor {
- #[must_use]
- fn new() -> Self {
- Self { found_return: false }
- }
-}
-
-impl<'ast> Visitor<'ast> for ReturnVisitor {
- fn visit_expr(&mut self, ex: &'ast Expr) {
- if let ExprKind::Ret(_) = ex.kind {
- self.found_return = true;
- } else if let ExprKind::Try(_) = ex.kind {
- self.found_return = true;
- }
-
- walk_expr(self, ex)
- }
-}
-
impl EarlyLintPass for MiscEarlyLints {
fn check_generics(&mut self, cx: &EarlyContext<'_>, gen: &Generics) {
for param in &gen.params {
return;
}
match expr.kind {
- ExprKind::Call(ref paren, _) => {
- if let ExprKind::Paren(ref closure) = paren.kind {
- if let ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind {
- let mut visitor = ReturnVisitor::new();
- visitor.visit_expr(block);
- if !visitor.found_return {
- span_lint_and_then(
- cx,
- REDUNDANT_CLOSURE_CALL,
- expr.span,
- "Try not to call a closure in the expression where it is declared.",
- |diag| {
- if decl.inputs.is_empty() {
- let mut app = Applicability::MachineApplicable;
- let hint =
- snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
- diag.span_suggestion(expr.span, "Try doing something like: ", hint, app);
- }
- },
- );
- }
- }
- }
- },
ExprKind::Unary(UnOp::Neg, ref inner) => {
if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
span_lint(
_ => (),
}
}
-
- fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
- for w in block.stmts.windows(2) {
- if_chain! {
- if let StmtKind::Local(ref local) = w[0].kind;
- if let Option::Some(ref t) = local.init;
- if let ExprKind::Closure(..) = t.kind;
- if let PatKind::Ident(_, ident, _) = local.pat.kind;
- if let StmtKind::Semi(ref second) = w[1].kind;
- if let ExprKind::Assign(_, ref call, _) = second.kind;
- if let ExprKind::Call(ref closure, _) = call.kind;
- if let ExprKind::Path(_, ref path) = closure.kind;
- then {
- if ident == path.segments[0].ident {
- span_lint(
- cx,
- REDUNDANT_CLOSURE_CALL,
- second.span,
- "Closure called just once immediately after it was declared",
- );
- }
- }
- }
- }
- }
}
impl MiscEarlyLints {
/// Returns true if any of the method parameters is a type that implements `Drop`. The method
/// can't be made const then, because `drop` can't be const-evaluated.
fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
- // If any of the params are dropable, return true
+ // If any of the params are droppable, return true
param_tys.iter().any(|hir_ty| {
let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty);
has_drop(cx, ty_ty)
use std::fmt::Display;
declare_clippy_lint! {
- /// **What it does:** Checks for modulo arithemtic.
+ /// **What it does:** Checks for modulo arithmetic.
///
/// **Why is this bad?** The results of modulo (%) operation might differ
/// depending on the language, when negative numbers are involved.
let mut split_at = None;
match existing_name.len.cmp(&count) {
Ordering::Greater => {
- if existing_name.len - count != 1 || levenstein_not_1(&interned_name, &existing_name.interned.as_str()) {
+ if existing_name.len - count != 1
+ || levenstein_not_1(&interned_name, &existing_name.interned.as_str())
+ {
continue;
}
},
Ordering::Less => {
- if count - existing_name.len != 1 || levenstein_not_1(&existing_name.interned.as_str(), &interned_name) {
+ if count - existing_name.len != 1
+ || levenstein_not_1(&existing_name.interned.as_str(), &interned_name)
+ {
continue;
}
},
}
}
-/// A struct containing information about occurences of the
+/// A struct containing information about occurrences of the
/// `if let Some(..) = .. else` construct that this lint detects.
struct OptionIfLetElseOccurence {
option: String,
if_chain! {
if let ExprKind::Block(ref block, _) = expr.kind;
if let Some(ref ex) = block.expr;
- if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC);
- if params.len() == 1;
+ if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC)
+ .or_else(|| match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT));
then {
+ let span = get_outer_span(expr);
if is_expn_of(expr.span, "unimplemented").is_some() {
- let span = get_outer_span(expr);
span_lint(cx, UNIMPLEMENTED, span,
"`unimplemented` should not be present in production code");
} else if is_expn_of(expr.span, "todo").is_some() {
- let span = get_outer_span(expr);
span_lint(cx, TODO, span,
"`todo` should not be present in production code");
} else if is_expn_of(expr.span, "unreachable").is_some() {
- let span = get_outer_span(expr);
span_lint(cx, UNREACHABLE, span,
"`unreachable` should not be present in production code");
} else if is_expn_of(expr.span, "panic").is_some() {
- let span = get_outer_span(expr);
span_lint(cx, PANIC, span,
"`panic` should not be present in production code");
match_panic(params, expr, cx);
continue;
}
+ if let ty::Adt(ref def, _) = arg_ty.kind {
+ if match_def_path(cx, def.did, &paths::MEM_MANUALLY_DROP) {
+ continue;
+ }
+ }
+
// `{ cloned = &arg; clone(move cloned); }` or `{ cloned = &arg; to_path_buf(cloned); }`
let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(cx, mir, arg, from_borrow, bb));
--- /dev/null
+use crate::utils::{snippet_with_applicability, span_lint, span_lint_and_then};
+use if_chain::if_chain;
+use rustc_ast::ast;
+use rustc_ast::visit as ast_visit;
+use rustc_ast::visit::Visitor as AstVisitor;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::intravisit as hir_visit;
+use rustc_hir::intravisit::Visitor as HirVisitor;
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::map::Map;
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// **What it does:** Detects closures called in the same expression where they
+ /// are defined.
+ ///
+ /// **Why is this bad?** It is unnecessarily adding to the expression's
+ /// complexity.
+ ///
+ /// **Known problems:** None.
+ ///
+ /// **Example:**
+ /// ```rust,ignore
+ /// // Bad
+ /// let a = (|| 42)()
+ ///
+ /// // Good
+ /// let a = 42
+ /// ```
+ pub REDUNDANT_CLOSURE_CALL,
+ complexity,
+ "throwaway closures called in the expression they are defined"
+}
+
+declare_lint_pass!(RedundantClosureCall => [REDUNDANT_CLOSURE_CALL]);
+
+// Used to find `return` statements or equivalents e.g., `?`
+struct ReturnVisitor {
+ found_return: bool,
+}
+
+impl ReturnVisitor {
+ #[must_use]
+ fn new() -> Self {
+ Self { found_return: false }
+ }
+}
+
+impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
+ fn visit_expr(&mut self, ex: &'ast ast::Expr) {
+ if let ast::ExprKind::Ret(_) = ex.kind {
+ self.found_return = true;
+ } else if let ast::ExprKind::Try(_) = ex.kind {
+ self.found_return = true;
+ }
+
+ ast_visit::walk_expr(self, ex)
+ }
+}
+
+impl EarlyLintPass for RedundantClosureCall {
+ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+ if in_external_macro(cx.sess(), expr.span) {
+ return;
+ }
+ if_chain! {
+ if let ast::ExprKind::Call(ref paren, _) = expr.kind;
+ if let ast::ExprKind::Paren(ref closure) = paren.kind;
+ if let ast::ExprKind::Closure(_, _, _, ref decl, ref block, _) = closure.kind;
+ then {
+ let mut visitor = ReturnVisitor::new();
+ visitor.visit_expr(block);
+ if !visitor.found_return {
+ span_lint_and_then(
+ cx,
+ REDUNDANT_CLOSURE_CALL,
+ expr.span,
+ "try not to call a closure in the expression where it is declared.",
+ |diag| {
+ if decl.inputs.is_empty() {
+ let mut app = Applicability::MachineApplicable;
+ let hint =
+ snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
+ diag.span_suggestion(expr.span, "try doing something like", hint, app);
+ }
+ },
+ );
+ }
+ }
+ }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
+ fn count_closure_usage<'tcx>(block: &'tcx hir::Block<'_>, path: &'tcx hir::Path<'tcx>) -> usize {
+ struct ClosureUsageCount<'tcx> {
+ path: &'tcx hir::Path<'tcx>,
+ count: usize,
+ };
+ impl<'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'tcx> {
+ type Map = Map<'tcx>;
+
+ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+ if_chain! {
+ if let hir::ExprKind::Call(ref closure, _) = expr.kind;
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
+ if self.path.segments[0].ident == path.segments[0].ident
+ && self.path.res == path.res;
+ then {
+ self.count += 1;
+ }
+ }
+ hir_visit::walk_expr(self, expr);
+ }
+
+ fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
+ hir_visit::NestedVisitorMap::None
+ }
+ };
+ let mut closure_usage_count = ClosureUsageCount { path, count: 0 };
+ closure_usage_count.visit_block(block);
+ closure_usage_count.count
+ }
+
+ for w in block.stmts.windows(2) {
+ if_chain! {
+ if let hir::StmtKind::Local(ref local) = w[0].kind;
+ if let Option::Some(ref t) = local.init;
+ if let hir::ExprKind::Closure(..) = t.kind;
+ if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind;
+ if let hir::StmtKind::Semi(ref second) = w[1].kind;
+ if let hir::ExprKind::Assign(_, ref call, _) = second.kind;
+ if let hir::ExprKind::Call(ref closure, _) = call.kind;
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = closure.kind;
+ if ident == path.segments[0].ident;
+ if count_closure_usage(block, path) == 1;
+ then {
+ span_lint(
+ cx,
+ REDUNDANT_CLOSURE_CALL,
+ second.span,
+ "closure called just once immediately after it was declared",
+ );
+ }
+ }
+ }
+ }
+}
cx,
SHADOW_UNRELATED,
pattern_span,
- &format!(
- "`{}` is shadowed by `{}`",
- snippet(cx, pattern_span, "_"),
- snippet(cx, expr.span, "..")
- ),
+ &format!("`{}` is being shadowed", snippet(cx, pattern_span, "_")),
|diag| {
diag.span_note(expr.span, "initialization happens here");
diag.span_note(prev_span, "previous binding is here");
--- /dev/null
+use crate::utils::{get_trait_def_id, paths, span_lint, span_lint_and_help};
+use if_chain::if_chain;
+use rustc_hir::def_id::DefId;
+use rustc_hir::{Expr, ExprKind, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_middle::ty::{GenericPredicates, PredicateKind, ProjectionPredicate, TraitPredicate};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{BytePos, Span};
+
+declare_clippy_lint! {
+ /// **What it does:** Checks for functions that expect closures of type
+ /// Fn(...) -> Ord where the implemented closure returns the unit type.
+ /// The lint also suggests to remove the semi-colon at the end of the statement if present.
+ ///
+ /// **Why is this bad?** Likely, returning the unit type is unintentional, and
+ /// could simply be caused by an extra semi-colon. Since () implements Ord
+ /// it doesn't cause a compilation error.
+ /// This is the same reasoning behind the unit_cmp lint.
+ ///
+ /// **Known problems:** If returning unit is intentional, then there is no
+ /// way of specifying this without triggering needless_return lint
+ ///
+ /// **Example:**
+ ///
+ /// ```rust
+ /// let mut twins = vec!((1,1), (2,2));
+ /// twins.sort_by_key(|x| { x.1; });
+ /// ```
+ pub UNIT_RETURN_EXPECTING_ORD,
+ correctness,
+ "fn arguments of type Fn(...) -> Ord returning the unit type ()."
+}
+
+declare_lint_pass!(UnitReturnExpectingOrd => [UNIT_RETURN_EXPECTING_ORD]);
+
+fn get_trait_predicates_for_trait_id<'tcx>(
+ cx: &LateContext<'tcx>,
+ generics: GenericPredicates<'tcx>,
+ trait_id: Option<DefId>,
+) -> Vec<TraitPredicate<'tcx>> {
+ let mut preds = Vec::new();
+ for (pred, _) in generics.predicates {
+ if_chain! {
+ if let PredicateKind::Trait(poly_trait_pred, _) = pred.kind();
+ let trait_pred = cx.tcx.erase_late_bound_regions(&poly_trait_pred);
+ if let Some(trait_def_id) = trait_id;
+ if trait_def_id == trait_pred.trait_ref.def_id;
+ then {
+ preds.push(trait_pred);
+ }
+ }
+ }
+ preds
+}
+
+fn get_projection_pred<'tcx>(
+ cx: &LateContext<'tcx>,
+ generics: GenericPredicates<'tcx>,
+ pred: TraitPredicate<'tcx>,
+) -> Option<ProjectionPredicate<'tcx>> {
+ generics.predicates.iter().find_map(|(proj_pred, _)| {
+ if let PredicateKind::Projection(proj_pred) = proj_pred.kind() {
+ let projection_pred = cx.tcx.erase_late_bound_regions(proj_pred);
+ if projection_pred.projection_ty.substs == pred.trait_ref.substs {
+ return Some(projection_pred);
+ }
+ }
+ None
+ })
+}
+
+fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Vec<(usize, String)> {
+ let mut args_to_check = Vec::new();
+ if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) {
+ let fn_sig = cx.tcx.fn_sig(def_id);
+ let generics = cx.tcx.predicates_of(def_id);
+ let fn_mut_preds = get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().fn_mut_trait());
+ let ord_preds = get_trait_predicates_for_trait_id(cx, generics, get_trait_def_id(cx, &paths::ORD));
+ let partial_ord_preds =
+ get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
+ // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
+ // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]`
+ let inputs_output = cx.tcx.erase_late_bound_regions(&fn_sig.inputs_and_output());
+ inputs_output
+ .iter()
+ .rev()
+ .skip(1)
+ .rev()
+ .enumerate()
+ .for_each(|(i, inp)| {
+ for trait_pred in &fn_mut_preds {
+ if_chain! {
+ if trait_pred.self_ty() == inp;
+ if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
+ then {
+ if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.ty) {
+ args_to_check.push((i, "Ord".to_string()));
+ } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) {
+ args_to_check.push((i, "PartialOrd".to_string()));
+ }
+ }
+ }
+ }
+ });
+ }
+ args_to_check
+}
+
+fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Span, Option<Span>)> {
+ if_chain! {
+ if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind;
+ if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind;
+ let ret_ty = substs.as_closure().sig().output();
+ let ty = cx.tcx.erase_late_bound_regions(&ret_ty);
+ if ty.is_unit();
+ then {
+ if_chain! {
+ let body = cx.tcx.hir().body(body_id);
+ if let ExprKind::Block(block, _) = body.value.kind;
+ if block.expr.is_none();
+ if let Some(stmt) = block.stmts.last();
+ if let StmtKind::Semi(_) = stmt.kind;
+ then {
+ let data = stmt.span.data();
+ // Make a span out of the semicolon for the help message
+ Some((span, Some(Span::new(data.hi-BytePos(1), data.hi, data.ctxt))))
+ } else {
+ Some((span, None))
+ }
+ }
+ } else {
+ None
+ }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for UnitReturnExpectingOrd {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind {
+ let arg_indices = get_args_to_check(cx, expr);
+ for (i, trait_name) in arg_indices {
+ if i < args.len() {
+ match check_arg(cx, &args[i]) {
+ Some((span, None)) => {
+ span_lint(
+ cx,
+ UNIT_RETURN_EXPECTING_ORD,
+ span,
+ &format!(
+ "this closure returns \
+ the unit type which also implements {}",
+ trait_name
+ ),
+ );
+ },
+ Some((span, Some(last_semi))) => {
+ span_lint_and_help(
+ cx,
+ UNIT_RETURN_EXPECTING_ORD,
+ span,
+ &format!(
+ "this closure returns \
+ the unit type which also implements {}",
+ trait_name
+ ),
+ Some(last_semi),
+ &"probably caused by this trailing semicolon".to_string(),
+ );
+ },
+ None => {},
+ }
+ }
+ }
+ }
+ }
+}
use crate::utils::{
- is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet, snippet_with_macro_callsite,
- span_lint_and_help, span_lint_and_sugg,
+ get_parent_expr, is_type_diagnostic_item, match_def_path, match_trait_method, paths, snippet,
+ snippet_with_macro_callsite, span_lint_and_help, span_lint_and_sugg,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
}
}
if match_trait_method(cx, e, &paths::INTO_ITERATOR) && &*name.ident.as_str() == "into_iter" {
+ if let Some(parent_expr) = get_parent_expr(cx, e) {
+ if let ExprKind::MethodCall(ref parent_name, ..) = parent_expr.kind {
+ if &*parent_name.ident.as_str() != "into_iter" {
+ return;
+ }
+ }
+ }
let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(&args[0]);
if TyS::same_type(a, b) {
.predicates
.iter()
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
- !traits::normalize_and_test_predicates(
+ traits::impossible_predicates(
cx.tcx,
traits::elaborate_predicates(cx.tcx, predicates)
.map(|o| o.predicate)
pub integer: &'a str,
/// The fraction part of the number.
pub fraction: Option<&'a str>,
- /// The character used as exponent seperator (b'e' or b'E') and the exponent part.
+ /// The character used as exponent separator (b'e' or b'E') and the exponent part.
pub exponent: Option<(char, &'a str)>,
/// The type suffix, including preceding underscore if present.
pub const LINT: [&str; 3] = ["rustc_session", "lint", "Lint"];
pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
+pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "ManuallyDrop"];
pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"];
pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"];
pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"];
use rustc_hir as hir;
declare_clippy_lint! {
- /// **What it does:** Finds occurences of `Vec::resize(0, an_int)`
+ /// **What it does:** Finds occurrences of `Vec::resize(0, an_int)`
///
/// **Why is this bad?** This is probably an argument inversion mistake.
///
group: "complexity",
desc: "throwaway closures called in the expression they are defined",
deprecation: None,
- module: "misc_early",
+ module: "redundant_closure_call",
},
Lint {
name: "redundant_closure_for_method_calls",
deprecation: None,
module: "types",
},
+ Lint {
+ name: "unit_return_expecting_ord",
+ group: "correctness",
+ desc: "fn arguments of type Fn(...) -> Ord returning the unit type ().",
+ deprecation: None,
+ module: "unit_return_expecting_ord",
+ },
Lint {
name: "unknown_clippy_lints",
group: "style",
-error: called `.nth(0)` on a `std::iter::Iterator`
+error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent
--> $DIR/iter_nth_zero.rs:20:14
|
LL | let _x = s.iter().nth(0);
- | ^^^^^^^^^^^^^^^ help: try calling: `s.iter().next()`
+ | ^^^^^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `s.iter().next()`
|
= note: `-D clippy::iter-nth-zero` implied by `-D warnings`
-error: called `.nth(0)` on a `std::iter::Iterator`
+error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent
--> $DIR/iter_nth_zero.rs:25:14
|
LL | let _y = iter.nth(0);
- | ^^^^^^^^^^^ help: try calling: `iter.next()`
+ | ^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `iter.next()`
-error: called `.nth(0)` on a `std::iter::Iterator`
+error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent
--> $DIR/iter_nth_zero.rs:30:22
|
LL | let _unwrapped = iter2.nth(0).unwrap();
- | ^^^^^^^^^^^^ help: try calling: `iter2.next()`
+ | ^^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `iter2.next()`
error: aborting due to 3 previous errors
struct S {}
impl S {
async fn inh_fut() -> i32 {
- // NOTE: this code is here just to check that the identation is correct in the suggested fix
+ // NOTE: this code is here just to check that the indentation is correct in the suggested fix
let a = 42;
let b = 21;
if a < b {
impl S {
fn inh_fut() -> impl Future<Output = i32> {
async {
- // NOTE: this code is here just to check that the identation is correct in the suggested fix
+ // NOTE: this code is here just to check that the indentation is correct in the suggested fix
let a = 42;
let b = 21;
if a < b {
help: move the body of the async block to the enclosing function
|
LL | fn inh_fut() -> impl Future<Output = i32> {
-LL | // NOTE: this code is here just to check that the identation is correct in the suggested fix
+LL | // NOTE: this code is here just to check that the indentation is correct in the suggested fix
LL | let a = 42;
LL | let b = 21;
LL | if a < b {
println!("{}", arr[i]);
}
}
+
+mod issue2277 {
+ pub fn example(list: &[[f64; 3]]) {
+ let mut x: [f64; 3] = [10.; 3];
+
+ for i in 0..3 {
+ x[i] = list.iter().map(|item| item[i]).sum::<f64>();
+ }
+ }
+}
}
}
-// Issue #1991: the outter loop should not warn.
+// Issue #1991: the outer loop should not warn.
pub fn test15() {
'label: loop {
while false {
fn panic() {
let a = 2;
panic!();
+ panic!("message");
+ panic!("{} {}", "panic with", "multiple arguments");
let b = a + 2;
}
fn todo() {
let a = 2;
todo!();
+ todo!("message");
+ todo!("{} {}", "panic with", "multiple arguments");
let b = a + 2;
}
fn unimplemented() {
let a = 2;
unimplemented!();
+ unimplemented!("message");
+ unimplemented!("{} {}", "panic with", "multiple arguments");
let b = a + 2;
}
fn unreachable() {
let a = 2;
unreachable!();
+ unreachable!("message");
+ unreachable!("{} {}", "panic with", "multiple arguments");
let b = a + 2;
}
|
= note: `-D clippy::panic` implied by `-D warnings`
+error: `panic` should not be present in production code
+ --> $DIR/panicking_macros.rs:7:5
+ |
+LL | panic!("message");
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `panic` should not be present in production code
+ --> $DIR/panicking_macros.rs:8:5
+ |
+LL | panic!("{} {}", "panic with", "multiple arguments");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
error: `todo` should not be present in production code
- --> $DIR/panicking_macros.rs:12:5
+ --> $DIR/panicking_macros.rs:14:5
|
LL | todo!();
| ^^^^^^^^
|
= note: `-D clippy::todo` implied by `-D warnings`
+error: `todo` should not be present in production code
+ --> $DIR/panicking_macros.rs:15:5
+ |
+LL | todo!("message");
+ | ^^^^^^^^^^^^^^^^^
+
+error: `todo` should not be present in production code
+ --> $DIR/panicking_macros.rs:16:5
+ |
+LL | todo!("{} {}", "panic with", "multiple arguments");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
error: `unimplemented` should not be present in production code
- --> $DIR/panicking_macros.rs:18:5
+ --> $DIR/panicking_macros.rs:22:5
|
LL | unimplemented!();
| ^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::unimplemented` implied by `-D warnings`
-error: `unreachable` should not be present in production code
+error: `unimplemented` should not be present in production code
+ --> $DIR/panicking_macros.rs:23:5
+ |
+LL | unimplemented!("message");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `unimplemented` should not be present in production code
--> $DIR/panicking_macros.rs:24:5
|
+LL | unimplemented!("{} {}", "panic with", "multiple arguments");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `unreachable` should not be present in production code
+ --> $DIR/panicking_macros.rs:30:5
+ |
LL | unreachable!();
| ^^^^^^^^^^^^^^^
|
= note: `-D clippy::unreachable` implied by `-D warnings`
-error: aborting due to 4 previous errors
+error: `unreachable` should not be present in production code
+ --> $DIR/panicking_macros.rs:31:5
+ |
+LL | unreachable!("message");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: `unreachable` should not be present in production code
+ --> $DIR/panicking_macros.rs:32:5
+ |
+LL | unreachable!("{} {}", "panic with", "multiple arguments");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
let _ = -(1i32.abs());
let _ = -(1f32.abs());
- // Odd functions shoud not trigger an error
+ // Odd functions should not trigger an error
let _ = -1f64.asin();
let _ = -1f64.asinh();
let _ = -1f64.atan();
let _ = -(1i32.abs());
let _ = -(1f32.abs());
- // Odd functions shoud not trigger an error
+ // Odd functions should not trigger an error
let _ = -1f64.asin();
let _ = -1f64.asinh();
let _ = -1f64.atan();
borrower_propagation();
not_consumed();
issue_5405();
+ manually_drop();
}
#[derive(Clone)]
let c: [usize; 2] = [2, 3];
let _d: usize = c[1].clone();
}
+
+fn manually_drop() {
+ use std::mem::ManuallyDrop;
+ use std::sync::Arc;
+
+ let a = ManuallyDrop::new(Arc::new("Hello!".to_owned()));
+ let _ = a.clone(); // OK
+
+ let p: *const String = Arc::into_raw(ManuallyDrop::into_inner(a));
+ unsafe {
+ Arc::from_raw(p);
+ Arc::from_raw(p);
+ }
+}
borrower_propagation();
not_consumed();
issue_5405();
+ manually_drop();
}
#[derive(Clone)]
let c: [usize; 2] = [2, 3];
let _d: usize = c[1].clone();
}
+
+fn manually_drop() {
+ use std::mem::ManuallyDrop;
+ use std::sync::Arc;
+
+ let a = ManuallyDrop::new(Arc::new("Hello!".to_owned()));
+ let _ = a.clone(); // OK
+
+ let p: *const String = Arc::into_raw(ManuallyDrop::into_inner(a));
+ unsafe {
+ Arc::from_raw(p);
+ Arc::from_raw(p);
+ }
+}
| ^^^^^
error: redundant clone
- --> $DIR/redundant_clone.rs:61:22
+ --> $DIR/redundant_clone.rs:62:22
|
LL | (a.clone(), a.clone())
| ^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/redundant_clone.rs:61:21
+ --> $DIR/redundant_clone.rs:62:21
|
LL | (a.clone(), a.clone())
| ^
error: redundant clone
- --> $DIR/redundant_clone.rs:121:15
+ --> $DIR/redundant_clone.rs:122:15
|
LL | let _s = s.clone();
| ^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/redundant_clone.rs:121:14
+ --> $DIR/redundant_clone.rs:122:14
|
LL | let _s = s.clone();
| ^
error: redundant clone
- --> $DIR/redundant_clone.rs:122:15
+ --> $DIR/redundant_clone.rs:123:15
|
LL | let _t = t.clone();
| ^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/redundant_clone.rs:122:14
+ --> $DIR/redundant_clone.rs:123:14
|
LL | let _t = t.clone();
| ^
error: redundant clone
- --> $DIR/redundant_clone.rs:132:19
+ --> $DIR/redundant_clone.rs:133:19
|
LL | let _f = f.clone();
| ^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/redundant_clone.rs:132:18
+ --> $DIR/redundant_clone.rs:133:18
|
LL | let _f = f.clone();
| ^
error: redundant clone
- --> $DIR/redundant_clone.rs:144:14
+ --> $DIR/redundant_clone.rs:145:14
|
LL | let y = x.clone().join("matthias");
| ^^^^^^^^ help: remove this
|
note: cloned value is neither consumed nor mutated
- --> $DIR/redundant_clone.rs:144:13
+ --> $DIR/redundant_clone.rs:145:13
|
LL | let y = x.clone().join("matthias");
| ^^^^^^^^^
+++ /dev/null
-// non rustfixable, see redundant_closure_call_fixable.rs
-
-#![warn(clippy::redundant_closure_call)]
-
-fn main() {
- let mut i = 1;
- let mut k = (|m| m + 1)(i);
-
- k = (|a, b| a * b)(1, 5);
-
- let closure = || 32;
- i = closure();
-
- let closure = |i| i + 1;
- i = closure(3);
-
- i = closure(4);
-
- #[allow(clippy::needless_return)]
- (|| return 2)();
- (|| -> Option<i32> { None? })();
- (|| -> Result<i32, i32> { Err(2)? })();
-}
+++ /dev/null
-error: Closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call.rs:12:5
- |
-LL | i = closure();
- | ^^^^^^^^^^^^^
- |
- = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
-
-error: Closure called just once immediately after it was declared
- --> $DIR/redundant_closure_call.rs:15:5
- |
-LL | i = closure(3);
- | ^^^^^^^^^^^^^^
-
-error: Try not to call a closure in the expression where it is declared.
- --> $DIR/redundant_closure_call.rs:7:17
- |
-LL | let mut k = (|m| m + 1)(i);
- | ^^^^^^^^^^^^^^
-
-error: Try not to call a closure in the expression where it is declared.
- --> $DIR/redundant_closure_call.rs:9:9
- |
-LL | k = (|a, b| a * b)(1, 5);
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 4 previous errors
-
--- /dev/null
+// non rustfixable, see redundant_closure_call_fixable.rs
+
+#![warn(clippy::redundant_closure_call)]
+
+fn main() {
+ let mut i = 1;
+
+ // lint here
+ let mut k = (|m| m + 1)(i);
+
+ // lint here
+ k = (|a, b| a * b)(1, 5);
+
+ // don't lint these
+ #[allow(clippy::needless_return)]
+ (|| return 2)();
+ (|| -> Option<i32> { None? })();
+ (|| -> Result<i32, i32> { Err(2)? })();
+}
--- /dev/null
+error: try not to call a closure in the expression where it is declared.
+ --> $DIR/redundant_closure_call_early.rs:9:17
+ |
+LL | let mut k = (|m| m + 1)(i);
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
+
+error: try not to call a closure in the expression where it is declared.
+ --> $DIR/redundant_closure_call_early.rs:12:9
+ |
+LL | k = (|a, b| a * b)(1, 5);
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
-error: Try not to call a closure in the expression where it is declared.
+error: try not to call a closure in the expression where it is declared.
--> $DIR/redundant_closure_call_fixable.rs:7:13
|
LL | let a = (|| 42)();
- | ^^^^^^^^^ help: Try doing something like: : `42`
+ | ^^^^^^^^^ help: try doing something like: `42`
|
= note: `-D clippy::redundant-closure-call` implied by `-D warnings`
--- /dev/null
+// non rustfixable, see redundant_closure_call_fixable.rs
+
+#![warn(clippy::redundant_closure_call)]
+
+fn main() {
+ let mut i = 1;
+
+ // don't lint here, the closure is used more than once
+ let closure = |i| i + 1;
+ i = closure(3);
+ i = closure(4);
+
+ // lint here
+ let redun_closure = || 1;
+ i = redun_closure();
+
+ // shadowed closures are supported, lint here
+ let shadowed_closure = || 1;
+ i = shadowed_closure();
+ let shadowed_closure = || 2;
+ i = shadowed_closure();
+
+ // don't lint here
+ let shadowed_closure = || 2;
+ i = shadowed_closure();
+ i = shadowed_closure();
+}
--- /dev/null
+error: closure called just once immediately after it was declared
+ --> $DIR/redundant_closure_call_late.rs:15:5
+ |
+LL | i = redun_closure();
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
+
+error: closure called just once immediately after it was declared
+ --> $DIR/redundant_closure_call_late.rs:19:5
+ |
+LL | i = shadowed_closure();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: closure called just once immediately after it was declared
+ --> $DIR/redundant_closure_call_late.rs:21:5
+ |
+LL | i = shadowed_closure();
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
)]
fn main() {
+ let result: Result<usize, usize> = Err(5);
+ if result.is_ok() {}
+
if Ok::<i32, i32>(42).is_ok() {}
if Err::<i32, i32>(42).is_err() {}
)]
fn main() {
+ let result: Result<usize, usize> = Err(5);
+ if let Ok(_) = &result {}
+
if let Ok(_) = Ok::<i32, i32>(42) {}
if let Err(_) = Err::<i32, i32>(42) {}
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:14:12
+ --> $DIR/redundant_pattern_matching.rs:15:12
|
-LL | if let Ok(_) = Ok::<i32, i32>(42) {}
- | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+LL | if let Ok(_) = &result {}
+ | -------^^^^^---------- help: try this: `if result.is_ok()`
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+error: redundant pattern matching, consider using `is_ok()`
+ --> $DIR/redundant_pattern_matching.rs:17:12
+ |
+LL | if let Ok(_) = Ok::<i32, i32>(42) {}
+ | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
+
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:16:12
+ --> $DIR/redundant_pattern_matching.rs:19:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:18:12
+ --> $DIR/redundant_pattern_matching.rs:21:12
|
LL | if let None = None::<()> {}
| -------^^^^------------- help: try this: `if None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:20:12
+ --> $DIR/redundant_pattern_matching.rs:23:12
|
LL | if let Some(_) = Some(42) {}
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:22:12
+ --> $DIR/redundant_pattern_matching.rs:25:12
|
LL | if let Some(_) = Some(42) {
| -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:28:15
+ --> $DIR/redundant_pattern_matching.rs:31:15
|
LL | while let Some(_) = Some(42) {}
| ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:30:15
+ --> $DIR/redundant_pattern_matching.rs:33:15
|
LL | while let None = Some(42) {}
| ----------^^^^----------- help: try this: `while Some(42).is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:32:15
+ --> $DIR/redundant_pattern_matching.rs:35:15
|
LL | while let None = None::<()> {}
| ----------^^^^------------- help: try this: `while None::<()>.is_none()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:34:15
+ --> $DIR/redundant_pattern_matching.rs:37:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:36:15
+ --> $DIR/redundant_pattern_matching.rs:39:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:39:15
+ --> $DIR/redundant_pattern_matching.rs:42:15
|
LL | while let Some(_) = v.pop() {
| ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:55:5
+ --> $DIR/redundant_pattern_matching.rs:58:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => true,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:60:5
+ --> $DIR/redundant_pattern_matching.rs:63:5
|
LL | / match Ok::<i32, i32>(42) {
LL | | Ok(_) => false,
| |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:65:5
+ --> $DIR/redundant_pattern_matching.rs:68:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => false,
| |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:70:5
+ --> $DIR/redundant_pattern_matching.rs:73:5
|
LL | / match Err::<i32, i32>(42) {
LL | | Ok(_) => true,
| |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:75:5
+ --> $DIR/redundant_pattern_matching.rs:78:5
|
LL | / match Some(42) {
LL | | Some(_) => true,
| |_____^ help: try this: `Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:80:5
+ --> $DIR/redundant_pattern_matching.rs:83:5
|
LL | / match None::<()> {
LL | | Some(_) => false,
| |_____^ help: try this: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:85:13
+ --> $DIR/redundant_pattern_matching.rs:88:13
|
LL | let _ = match None::<()> {
| _____________^
| |_____^ help: try this: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:90:20
+ --> $DIR/redundant_pattern_matching.rs:93:20
|
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
| -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:93:20
+ --> $DIR/redundant_pattern_matching.rs:96:20
|
LL | let x = if let Some(_) = opt { true } else { false };
| -------^^^^^^^------ help: try this: `if opt.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:99:20
+ --> $DIR/redundant_pattern_matching.rs:102:20
|
LL | let _ = if let Some(_) = gen_opt() {
| -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching.rs:101:19
+ --> $DIR/redundant_pattern_matching.rs:104:19
|
LL | } else if let None = gen_opt() {
| -------^^^^------------ help: try this: `if gen_opt().is_none()`
error: redundant pattern matching, consider using `is_ok()`
- --> $DIR/redundant_pattern_matching.rs:103:19
+ --> $DIR/redundant_pattern_matching.rs:106:19
|
LL | } else if let Ok(_) = gen_res() {
| -------^^^^^------------ help: try this: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> $DIR/redundant_pattern_matching.rs:105:19
+ --> $DIR/redundant_pattern_matching.rs:108:19
|
LL | } else if let Err(_) = gen_res() {
| -------^^^^^^------------ help: try this: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:138:19
+ --> $DIR/redundant_pattern_matching.rs:141:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
| ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:139:16
+ --> $DIR/redundant_pattern_matching.rs:142:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
| -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:145:12
+ --> $DIR/redundant_pattern_matching.rs:148:12
|
LL | if let Some(_) = m!() {}
| -------^^^^^^^------- help: try this: `if m!().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching.rs:146:15
+ --> $DIR/redundant_pattern_matching.rs:149:15
|
LL | while let Some(_) = m!() {}
| ----------^^^^^^^------- help: try this: `while m!().is_some()`
-error: aborting due to 28 previous errors
+error: aborting due to 29 previous errors
LL | let x = (1, x);
| ^
-error: `x` is shadowed by `y`
+error: `x` is being shadowed
--> $DIR/shadow.rs:34:9
|
LL | let x = y;
--- /dev/null
+#![warn(clippy::unit_return_expecting_ord)]
+#![allow(clippy::needless_return)]
+#![allow(clippy::unused_unit)]
+#![feature(is_sorted)]
+
+struct Struct {
+ field: isize,
+}
+
+fn double(i: isize) -> isize {
+ i * 2
+}
+
+fn unit(_i: isize) {}
+
+fn main() {
+ let mut structs = vec![Struct { field: 2 }, Struct { field: 1 }];
+ structs.sort_by_key(|s| {
+ double(s.field);
+ });
+ structs.sort_by_key(|s| double(s.field));
+ structs.is_sorted_by_key(|s| {
+ double(s.field);
+ });
+ structs.is_sorted_by_key(|s| {
+ if s.field > 0 {
+ ()
+ } else {
+ return ();
+ }
+ });
+ structs.sort_by_key(|s| {
+ return double(s.field);
+ });
+ structs.sort_by_key(|s| unit(s.field));
+}
--- /dev/null
+error: this closure returns the unit type which also implements Ord
+ --> $DIR/unit_return_expecting_ord.rs:18:25
+ |
+LL | structs.sort_by_key(|s| {
+ | ^^^
+ |
+ = note: `-D clippy::unit-return-expecting-ord` implied by `-D warnings`
+help: probably caused by this trailing semicolon
+ --> $DIR/unit_return_expecting_ord.rs:19:24
+ |
+LL | double(s.field);
+ | ^
+
+error: this closure returns the unit type which also implements PartialOrd
+ --> $DIR/unit_return_expecting_ord.rs:22:30
+ |
+LL | structs.is_sorted_by_key(|s| {
+ | ^^^
+ |
+help: probably caused by this trailing semicolon
+ --> $DIR/unit_return_expecting_ord.rs:23:24
+ |
+LL | double(s.field);
+ | ^
+
+error: this closure returns the unit type which also implements PartialOrd
+ --> $DIR/unit_return_expecting_ord.rs:25:30
+ |
+LL | structs.is_sorted_by_key(|s| {
+ | ^^^
+
+error: this closure returns the unit type which also implements Ord
+ --> $DIR/unit_return_expecting_ord.rs:35:25
+ |
+LL | structs.sort_by_key(|s| unit(s.field));
+ | ^^^
+
+error: aborting due to 4 previous errors
+
Ok(())
}
+fn test_issue_5833() -> Result<(), ()> {
+ let text = "foo\r\nbar\n\nbaz\n";
+ let lines = text.lines();
+ if Some("ok") == lines.into_iter().next() {}
+
+ Ok(())
+}
+
fn main() {
test_generic(10i32);
test_generic2::<i32, i32>(10i32);
test_questionmark().unwrap();
test_issue_3913().unwrap();
+ test_issue_5833().unwrap();
let _: String = "foo".into();
let _: String = From::from("foo");
Ok(())
}
+fn test_issue_5833() -> Result<(), ()> {
+ let text = "foo\r\nbar\n\nbaz\n";
+ let lines = text.lines();
+ if Some("ok") == lines.into_iter().next() {}
+
+ Ok(())
+}
+
fn main() {
test_generic(10i32);
test_generic2::<i32, i32>(10i32);
test_questionmark().unwrap();
test_issue_3913().unwrap();
+ test_issue_5833().unwrap();
let _: String = "foo".into();
let _: String = From::from("foo");
| ^^^^^^^^^^^ help: consider removing `.into()`: `0i32`
error: useless conversion to the same type
- --> $DIR/useless_conversion.rs:51:21
+ --> $DIR/useless_conversion.rs:60:21
|
LL | let _: String = "foo".to_string().into();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()`
error: useless conversion to the same type
- --> $DIR/useless_conversion.rs:52:21
+ --> $DIR/useless_conversion.rs:61:21
|
LL | let _: String = From::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()`
error: useless conversion to the same type
- --> $DIR/useless_conversion.rs:53:13
+ --> $DIR/useless_conversion.rs:62:13
|
LL | let _ = String::from("foo".to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()`
error: useless conversion to the same type
- --> $DIR/useless_conversion.rs:54:13
+ --> $DIR/useless_conversion.rs:63:13
|
LL | let _ = String::from(format!("A: {:04}", 123));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)`
error: useless conversion to the same type
- --> $DIR/useless_conversion.rs:55:13
+ --> $DIR/useless_conversion.rs:64:13
|
LL | let _ = "".lines().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()`
error: useless conversion to the same type
- --> $DIR/useless_conversion.rs:56:13
+ --> $DIR/useless_conversion.rs:65:13
|
LL | let _ = vec![1, 2, 3].into_iter().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()`
error: useless conversion to the same type
- --> $DIR/useless_conversion.rs:57:21
+ --> $DIR/useless_conversion.rs:66:21
|
LL | let _: String = format!("Hello {}", "world").into();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")`
// not applicable
vec![1, 2, 3, 4, 5].resize(2, 5);
- // applicable here, but only implemented for integer litterals for now
+ // applicable here, but only implemented for integer literals for now
vec!["foo", "bar", "baz"].resize(0, "bar");
// not applicable
pub gdb_native_rust: bool,
/// Version of LLDB
- pub lldb_version: Option<String>,
+ pub lldb_version: Option<u32>,
/// Whether LLDB has native rust support
pub lldb_native_rust: bool,
/// Version of LLVM
- pub llvm_version: Option<String>,
+ pub llvm_version: Option<u32>,
/// Is LLVM a system LLVM
pub system_llvm: bool,
fn ignore_gdb(config: &Config, line: &str) -> bool {
if let Some(actual_version) = config.gdb_version {
- if line.starts_with("min-gdb-version") {
- let (start_ver, end_ver) = extract_gdb_version_range(line);
+ if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) {
+ let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version)
+ .unwrap_or_else(|| {
+ panic!("couldn't parse version range: {:?}", rest);
+ });
if start_ver != end_ver {
panic!("Expected single GDB version")
}
// Ignore if actual version is smaller the minimum required
// version
- actual_version < start_ver
- } else if line.starts_with("ignore-gdb-version") {
- let (min_version, max_version) = extract_gdb_version_range(line);
+ return actual_version < start_ver;
+ } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) {
+ let (min_version, max_version) =
+ extract_version_range(rest, extract_gdb_version).unwrap_or_else(|| {
+ panic!("couldn't parse version range: {:?}", rest);
+ });
if max_version < min_version {
panic!("Malformed GDB version range: max < min")
}
- actual_version >= min_version && actual_version <= max_version
- } else {
- false
- }
- } else {
- false
- }
- }
-
- // Takes a directive of the form "ignore-gdb-version <version1> [- <version2>]",
- // returns the numeric representation of <version1> and <version2> as
- // tuple: (<version1> as u32, <version2> as u32)
- // If the <version2> part is omitted, the second component of the tuple
- // is the same as <version1>.
- fn extract_gdb_version_range(line: &str) -> (u32, u32) {
- const ERROR_MESSAGE: &'static str = "Malformed GDB version directive";
-
- let range_components = line
- .split(&[' ', '-'][..])
- .filter(|word| !word.is_empty())
- .map(extract_gdb_version)
- .skip_while(Option::is_none)
- .take(3) // 3 or more = invalid, so take at most 3.
- .collect::<Vec<Option<u32>>>();
-
- match range_components.len() {
- 1 => {
- let v = range_components[0].unwrap();
- (v, v)
- }
- 2 => {
- let v_min = range_components[0].unwrap();
- let v_max = range_components[1].expect(ERROR_MESSAGE);
- (v_min, v_max)
+ return actual_version >= min_version && actual_version <= max_version;
}
- _ => panic!(ERROR_MESSAGE),
}
+ false
}
fn ignore_lldb(config: &Config, line: &str) -> bool {
- if let Some(ref actual_version) = config.lldb_version {
- if line.starts_with("min-lldb-version") {
- let min_version = line
- .trim_end()
- .rsplit(' ')
- .next()
- .expect("Malformed lldb version directive");
+ if let Some(actual_version) = config.lldb_version {
+ if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) {
+ let min_version = min_version.parse().unwrap_or_else(|e| {
+ panic!(
+ "Unexpected format of LLDB version string: {}\n{:?}",
+ min_version, e
+ );
+ });
// Ignore if actual version is smaller the minimum required
// version
- lldb_version_to_int(actual_version) < lldb_version_to_int(min_version)
+ actual_version < min_version
} else if line.starts_with("rust-lldb") && !config.lldb_native_rust {
true
} else {
if config.system_llvm && line.starts_with("no-system-llvm") {
return true;
}
- if let Some(ref actual_version) = config.llvm_version {
- let actual_version = version_to_int(actual_version);
- if line.starts_with("min-llvm-version") {
- let min_version = line
- .trim_end()
- .rsplit(' ')
- .next()
- .expect("Malformed llvm version directive");
+ if let Some(actual_version) = config.llvm_version {
+ if let Some(rest) = line.strip_prefix("min-llvm-version:").map(str::trim) {
+ let min_version = extract_llvm_version(rest).unwrap();
// Ignore if actual version is smaller the minimum required
// version
- actual_version < version_to_int(min_version)
- } else if line.starts_with("min-system-llvm-version") {
- let min_version = line
- .trim_end()
- .rsplit(' ')
- .next()
- .expect("Malformed llvm version directive");
+ actual_version < min_version
+ } else if let Some(rest) =
+ line.strip_prefix("min-system-llvm-version:").map(str::trim)
+ {
+ let min_version = extract_llvm_version(rest).unwrap();
// Ignore if using system LLVM and actual version
// is smaller the minimum required version
- config.system_llvm && actual_version < version_to_int(min_version)
- } else if line.starts_with("ignore-llvm-version") {
- // Syntax is: "ignore-llvm-version <version1> [- <version2>]"
- let range_components = line
- .split(' ')
- .skip(1) // Skip the directive.
- .map(|s| s.trim())
- .filter(|word| !word.is_empty() && word != &"-")
- .take(3) // 3 or more = invalid, so take at most 3.
- .collect::<Vec<&str>>();
- match range_components.len() {
- 1 => actual_version == version_to_int(range_components[0]),
- 2 => {
- let v_min = version_to_int(range_components[0]);
- let v_max = version_to_int(range_components[1]);
- if v_max < v_min {
- panic!("Malformed LLVM version range: max < min")
- }
- // Ignore if version lies inside of range.
- actual_version >= v_min && actual_version <= v_max
- }
- _ => panic!("Malformed LLVM version directive"),
+ config.system_llvm && actual_version < min_version
+ } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim)
+ {
+ // Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
+ let (v_min, v_max) = extract_version_range(rest, extract_llvm_version)
+ .unwrap_or_else(|| {
+ panic!("couldn't parse version range: {:?}", rest);
+ });
+ if v_max < v_min {
+ panic!("Malformed LLVM version range: max < min")
}
+ // Ignore if version lies inside of range.
+ actual_version >= v_min && actual_version <= v_max
} else {
false
}
false
}
}
-
- fn version_to_int(version: &str) -> u32 {
- let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
- let components: Vec<u32> = version_without_suffix
- .split('.')
- .map(|s| s.parse().expect("Malformed version component"))
- .collect();
- match components.len() {
- 1 => components[0] * 10000,
- 2 => components[0] * 10000 + components[1] * 100,
- 3 => components[0] * 10000 + components[1] * 100 + components[2],
- _ => panic!("Malformed version"),
- }
- }
}
}
}
}
-pub fn lldb_version_to_int(version_string: &str) -> isize {
- let error_string =
- format!("Encountered LLDB version string with unexpected format: {}", version_string);
- version_string.parse().expect(&error_string)
-}
-
fn expand_variables(mut value: String, config: &Config) -> String {
const CWD: &'static str = "{{cwd}}";
const SRC_BASE: &'static str = "{{src-base}}";
*line = &line[end + 1..];
Some(result)
}
+
+pub fn extract_llvm_version(version: &str) -> Option<u32> {
+ let version_without_suffix = version.trim_end_matches("git").split('-').next().unwrap();
+ let components: Vec<u32> = version_without_suffix
+ .split('.')
+ .map(|s| s.parse().expect("Malformed version component"))
+ .collect();
+ let version = match *components {
+ [a] => a * 10_000,
+ [a, b] => a * 10_000 + b * 100,
+ [a, b, c] => a * 10_000 + b * 100 + c,
+ _ => panic!("Malformed version"),
+ };
+ Some(version)
+}
+
+// Takes a directive of the form "<version1> [- <version2>]",
+// returns the numeric representation of <version1> and <version2> as
+// tuple: (<version1> as u32, <version2> as u32)
+// If the <version2> part is omitted, the second component of the tuple
+// is the same as <version1>.
+fn extract_version_range<F>(line: &str, parse: F) -> Option<(u32, u32)>
+where
+ F: Fn(&str) -> Option<u32>,
+{
+ let mut splits = line.splitn(2, "- ").map(str::trim);
+ let min = splits.next().unwrap();
+ if min.ends_with('-') {
+ return None;
+ }
+
+ let max = splits.next();
+
+ if min.is_empty() {
+ return None;
+ }
+
+ let min = parse(min)?;
+ let max = match max {
+ Some(max) if max.is_empty() => return None,
+ Some(max) => parse(max)?,
+ _ => min,
+ };
+
+ Some((min, max))
+}
fn llvm_version() {
let mut config = config();
- config.llvm_version = Some("8.1.2-rust".to_owned());
- assert!(parse_rs(&config, "// min-llvm-version 9.0").ignore);
+ config.llvm_version = Some(80102);
+ assert!(parse_rs(&config, "// min-llvm-version: 9.0").ignore);
- config.llvm_version = Some("9.0.1-rust-1.43.0-dev".to_owned());
- assert!(parse_rs(&config, "// min-llvm-version 9.2").ignore);
+ config.llvm_version = Some(90001);
+ assert!(parse_rs(&config, "// min-llvm-version: 9.2").ignore);
- config.llvm_version = Some("9.3.1-rust-1.43.0-dev".to_owned());
- assert!(!parse_rs(&config, "// min-llvm-version 9.2").ignore);
+ config.llvm_version = Some(90301);
+ assert!(!parse_rs(&config, "// min-llvm-version: 9.2").ignore);
- config.llvm_version = Some("10.0.0-rust".to_owned());
- assert!(!parse_rs(&config, "// min-llvm-version 9.0").ignore);
+ config.llvm_version = Some(100000);
+ assert!(!parse_rs(&config, "// min-llvm-version: 9.0").ignore);
}
#[test]
assert!(parse_rs(&config, "// needs-sanitizer-memory").ignore);
assert!(parse_rs(&config, "// needs-sanitizer-thread").ignore);
}
+
+#[test]
+fn test_extract_version_range() {
+ use super::{extract_llvm_version, extract_version_range};
+
+ assert_eq!(extract_version_range("1.2.3 - 4.5.6", extract_llvm_version), Some((10203, 40506)));
+ assert_eq!(extract_version_range("0 - 4.5.6", extract_llvm_version), Some((0, 40506)));
+ assert_eq!(extract_version_range("1.2.3 -", extract_llvm_version), None);
+ assert_eq!(extract_version_range("1.2.3 - ", extract_llvm_version), None);
+ assert_eq!(extract_version_range("- 4.5.6", extract_llvm_version), None);
+ assert_eq!(extract_version_range("-", extract_llvm_version), None);
+ assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None);
+ assert_eq!(extract_version_range(" - 4.5.6", extract_llvm_version), None);
+ assert_eq!(extract_version_range("0 -", extract_llvm_version), None);
+}
let cdb = analyze_cdb(matches.opt_str("cdb"), &target);
let (gdb, gdb_version, gdb_native_rust) =
analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path);
- let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version"));
-
- let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
+ let (lldb_version, lldb_native_rust) = matches
+ .opt_str("lldb-version")
+ .as_deref()
+ .and_then(extract_lldb_version)
+ .map(|(v, b)| (Some(v), b))
+ .unwrap_or((None, false));
+ let color = match matches.opt_str("color").as_deref() {
Some("auto") | None => ColorConfig::AutoColor,
Some("always") => ColorConfig::AlwaysColor,
Some("never") => ColorConfig::NeverColor,
Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x),
};
+ let llvm_version =
+ matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version);
let src_base = opt_path(matches, "src-base");
let run_ignored = matches.opt_present("ignored");
gdb_native_rust,
lldb_version,
lldb_native_rust,
- llvm_version: matches.opt_str("llvm-version"),
+ llvm_version,
system_llvm: matches.opt_present("system-llvm"),
android_cross_path,
adb_path: opt_str2(matches.opt_str("adb-path")),
logv(c, format!("stage_id: {}", config.stage_id));
logv(c, format!("mode: {}", config.mode));
logv(c, format!("run_ignored: {}", config.run_ignored));
- logv(c, format!("filter: {}", opt_str(&config.filter.as_ref().map(|re| re.to_owned()))));
+ logv(c, format!("filter: {}", opt_str(&config.filter)));
logv(c, format!("filter_exact: {}", config.filter_exact));
logv(
c,
return None;
}
- if let Some(lldb_version) = config.lldb_version.as_ref() {
- if lldb_version == "350" {
- println!(
- "WARNING: The used version of LLDB ({}) has a \
- known issue that breaks debuginfo tests. See \
- issue #32520 for more information. Skipping all \
- LLDB-based tests!",
- lldb_version
- );
- return None;
- }
+ if let Some(350) = config.lldb_version {
+ println!(
+ "WARNING: The used version of LLDB (350) has a \
+ known issue that breaks debuginfo tests. See \
+ issue #32520 for more information. Skipping all \
+ LLDB-based tests!",
+ );
+ return None;
}
// Some older versions of LLDB seem to have problems with multiple
let config = config.clone();
let testpaths = testpaths.clone();
let revision = revision.cloned();
- test::DynTestFn(Box::new(move || {
- runtest::run(config, &testpaths, revision.as_ref().map(|s| s.as_str()))
- }))
+ test::DynTestFn(Box::new(move || runtest::run(config, &testpaths, revision.as_deref())))
}
/// Returns `true` if the given target is an Android target for the
// This particular form is documented in the GNU coding standards:
// https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion
- // don't start parsing in the middle of a number
- let mut prev_was_digit = false;
- let mut in_parens = false;
- for (pos, c) in full_version_line.char_indices() {
- if in_parens {
- if c == ')' {
- in_parens = false;
- }
- continue;
- } else if c == '(' {
- in_parens = true;
- continue;
- }
-
- if prev_was_digit || !c.is_digit(10) {
- prev_was_digit = c.is_digit(10);
- continue;
+ let mut splits = full_version_line.rsplit(' ');
+ let version_string = splits.next().unwrap();
+
+ let mut splits = version_string.split('.');
+ let major = splits.next().unwrap();
+ let minor = splits.next().unwrap();
+ let patch = splits.next();
+
+ let major: u32 = major.parse().unwrap();
+ let (minor, patch): (u32, u32) = match minor.find(not_a_digit) {
+ None => {
+ let minor = minor.parse().unwrap();
+ let patch: u32 = match patch {
+ Some(patch) => match patch.find(not_a_digit) {
+ None => patch.parse().unwrap(),
+ Some(idx) if idx > 3 => 0,
+ Some(idx) => patch[..idx].parse().unwrap(),
+ },
+ None => 0,
+ };
+ (minor, patch)
}
-
- prev_was_digit = true;
-
- let line = &full_version_line[pos..];
-
- let next_split = match line.find(|c: char| !c.is_digit(10)) {
- Some(idx) => idx,
- None => continue, // no minor version
- };
-
- if line.as_bytes()[next_split] != b'.' {
- continue; // no minor version
+ // There is no patch version after minor-date (e.g. "4-2012").
+ Some(idx) => {
+ let minor = minor[..idx].parse().unwrap();
+ (minor, 0)
}
+ };
- let major = &line[..next_split];
- let line = &line[next_split + 1..];
-
- let (minor, patch) = match line.find(|c: char| !c.is_digit(10)) {
- Some(idx) => {
- if line.as_bytes()[idx] == b'.' {
- let patch = &line[idx + 1..];
-
- let patch_len =
- patch.find(|c: char| !c.is_digit(10)).unwrap_or_else(|| patch.len());
- let patch = &patch[..patch_len];
- let patch = if patch_len > 3 || patch_len == 0 { None } else { Some(patch) };
-
- (&line[..idx], patch)
- } else {
- (&line[..idx], None)
- }
- }
- None => (line, None),
- };
-
- if minor.is_empty() {
- continue;
- }
-
- let major: u32 = major.parse().unwrap();
- let minor: u32 = minor.parse().unwrap();
- let patch: u32 = patch.unwrap_or("0").parse().unwrap();
-
- return Some(((major * 1000) + minor) * 1000 + patch);
- }
-
- None
+ Some(((major * 1000) + minor) * 1000 + patch)
}
/// Returns (LLDB version, LLDB is rust-enabled)
-fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, bool) {
+fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> {
// Extract the major LLDB version from the given version string.
// LLDB version strings are different for Apple and non-Apple platforms.
// The Apple variant looks like this:
// lldb-300.2.51 (new versions)
//
// We are only interested in the major version number, so this function
- // will return `Some("179")` and `Some("300")` respectively.
+ // will return `Some(179)` and `Some(300)` respectively.
//
// Upstream versions look like:
// lldb version 6.0.1
// normally fine because the only non-Apple version we test is
// rust-enabled.
- if let Some(ref full_version_line) = full_version_line {
- if !full_version_line.trim().is_empty() {
- let full_version_line = full_version_line.trim();
-
- for (pos, l) in full_version_line.char_indices() {
- if l != 'l' && l != 'L' {
- continue;
- }
- if pos + 5 >= full_version_line.len() {
- continue;
- }
- let l = full_version_line[pos + 1..].chars().next().unwrap();
- if l != 'l' && l != 'L' {
- continue;
- }
- let d = full_version_line[pos + 2..].chars().next().unwrap();
- if d != 'd' && d != 'D' {
- continue;
- }
- let b = full_version_line[pos + 3..].chars().next().unwrap();
- if b != 'b' && b != 'B' {
- continue;
- }
- let dash = full_version_line[pos + 4..].chars().next().unwrap();
- if dash != '-' {
- continue;
- }
-
- let vers = full_version_line[pos + 5..]
- .chars()
- .take_while(|c| c.is_digit(10))
- .collect::<String>();
- if !vers.is_empty() {
- return (Some(vers), full_version_line.contains("rust-enabled"));
- }
- }
+ let full_version_line = full_version_line.trim();
- if full_version_line.starts_with("lldb version ") {
- let vers = full_version_line[13..]
- .chars()
- .take_while(|c| c.is_digit(10))
- .collect::<String>();
- if !vers.is_empty() {
- return (Some(vers + "00"), full_version_line.contains("rust-enabled"));
- }
- }
+ if let Some(apple_ver) =
+ full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-"))
+ {
+ if let Some(idx) = apple_ver.find(not_a_digit) {
+ let version: u32 = apple_ver[..idx].parse().unwrap();
+ return Some((version, full_version_line.contains("rust-enabled")));
+ }
+ } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") {
+ if let Some(idx) = lldb_ver.find(not_a_digit) {
+ let version: u32 = lldb_ver[..idx].parse().unwrap();
+ return Some((version * 100, full_version_line.contains("rust-enabled")));
}
}
- (None, false)
+ None
+}
+
+fn not_a_digit(c: char) -> bool {
+ !c.is_digit(10)
}
}
for l in test_file_contents.lines() {
if l.starts_with("// EMIT_MIR ") {
- let test_name = l.trim_start_matches("// EMIT_MIR ");
- let expected_file = test_dir.join(test_name);
-
- let dumped_string = if test_name.ends_with(".diff") {
- let test_name = test_name.trim_end_matches(".diff");
- let before = format!("{}.before.mir", test_name);
- let after = format!("{}.after.mir", test_name);
- let before = self.get_mir_dump_dir().join(before);
+ let test_name = l.trim_start_matches("// EMIT_MIR ").trim();
+ let mut test_names = test_name.split(' ');
+ // sometimes we specify two files so that we get a diff between the two files
+ let test_name = test_names.next().unwrap();
+ let expected_file;
+ let from_file;
+ let to_file;
+
+ if test_name.ends_with(".diff") {
+ let trimmed = test_name.trim_end_matches(".diff");
+ let test_against = format!("{}.after.mir", trimmed);
+ from_file = format!("{}.before.mir", trimmed);
+ expected_file = test_name.to_string();
+ assert!(
+ test_names.next().is_none(),
+ "two mir pass names specified for MIR diff"
+ );
+ to_file = Some(test_against);
+ } else if let Some(first_pass) = test_names.next() {
+ let second_pass = test_names.next().unwrap();
+ assert!(
+ test_names.next().is_none(),
+ "three mir pass names specified for MIR diff"
+ );
+ expected_file = format!("{}.{}-{}.diff", test_name, first_pass, second_pass);
+ let second_file = format!("{}.{}.mir", test_name, second_pass);
+ from_file = format!("{}.{}.mir", test_name, first_pass);
+ to_file = Some(second_file);
+ } else {
+ expected_file = test_name.to_string();
+ from_file = test_name.to_string();
+ assert!(
+ test_names.next().is_none(),
+ "two mir pass names specified for MIR dump"
+ );
+ to_file = None;
+ };
+ let expected_file = test_dir.join(expected_file);
+
+ let dumped_string = if let Some(after) = to_file {
+ let before = self.get_mir_dump_dir().join(from_file);
let after = self.get_mir_dump_dir().join(after);
debug!(
"comparing the contents of: {} with {}",
} else {
let mut output_file = PathBuf::new();
output_file.push(self.get_mir_dump_dir());
- output_file.push(test_name);
+ output_file.push(&from_file);
debug!(
"comparing the contents of: {} with {}",
output_file.display(),
output_file.parent().unwrap().display()
);
}
- self.check_mir_test_timestamp(test_name, &output_file);
+ self.check_mir_test_timestamp(&from_file, &output_file);
let dumped_string = fs::read_to_string(&output_file).unwrap();
self.normalize_output(&dumped_string, &[])
};
+use super::header::extract_llvm_version;
use super::*;
#[test]
fn test_extract_gdb_version() {
- macro_rules! test { ($($expectation:tt: $input:tt,)*) => {{$(
+ macro_rules! test { ($($expectation:literal: $input:literal,)*) => {{$(
assert_eq!(extract_gdb_version($input), Some($expectation));
)*}}}
}
}
+#[test]
+fn test_extract_lldb_version() {
+ // Apple variants
+ assert_eq!(extract_lldb_version("LLDB-179.5"), Some((179, false)));
+ assert_eq!(extract_lldb_version("lldb-300.2.51"), Some((300, false)));
+
+ // Upstream versions
+ assert_eq!(extract_lldb_version("lldb version 6.0.1"), Some((600, false)));
+ assert_eq!(extract_lldb_version("lldb version 9.0.0"), Some((900, false)));
+}
+
#[test]
fn is_test_test() {
assert_eq!(true, is_test(&OsString::from("a_test.rs")));
assert_eq!(false, is_test(&OsString::from("#a_dog_gif")));
assert_eq!(false, is_test(&OsString::from("~a_temp_file")));
}
+
+#[test]
+fn test_extract_llvm_version() {
+ assert_eq!(extract_llvm_version("8.1.2-rust"), Some(80102));
+ assert_eq!(extract_llvm_version("9.0.1-rust-1.43.0-dev"), Some(90001));
+ assert_eq!(extract_llvm_version("9.3.1-rust-1.43.0-dev"), Some(90301));
+ assert_eq!(extract_llvm_version("10.0.0-rust"), Some(100000));
+}
name = "error_index_generator"
version = "0.0.0"
edition = "2018"
-build = "build.rs"
[dependencies]
rustdoc = { path = "../../librustdoc" }
MAINTAINERS = {
'miri': {'oli-obk', 'RalfJung', 'eddyb'},
'rls': {'Xanewok'},
- 'rustfmt': {'topecongiro'},
+ 'rustfmt': {'topecongiro', 'calebcartwright'},
'book': {'carols10cents', 'steveklabnik'},
'nomicon': {'frewsxcv', 'Gankra'},
'reference': {'steveklabnik', 'Havvy', 'matthewjasper', 'ehuss'},
-Subproject commit dd341d53075411cf0f71c5853c98facda35112ef
+Subproject commit a0e80a9783b1485fe8935d5de4dec34fe6bb5f10
-Subproject commit 8b0983e89ad9a28b142eccf3755a8c9aaeb37852
+Subproject commit c9c518e5e9761bf35d466c47c57c3a1358b56b3c
-Subproject commit c1e9b7b87493c5197c4330693bdf4ccb30a90971
+Subproject commit cef1c0d5ebde015d72d830e655ca1b4079a08494
"MIT",
"Unlicense/MIT",
"Unlicense OR MIT",
- "0BSD OR MIT OR Apache-2.0", // adler license
];
/// These are exceptions to Rust's permissive licensing policy, and
("ryu", "Apache-2.0 OR BSL-1.0"), // rls/cargo/... (because of serde)
("bytesize", "Apache-2.0"), // cargo
("im-rc", "MPL-2.0+"), // cargo
+ ("adler32", "BSD-3-Clause AND Zlib"), // cargo dep that isn't used
("constant_time_eq", "CC0-1.0"), // rustfmt
("sized-chunks", "MPL-2.0+"), // cargo via im-rc
("bitmaps", "MPL-2.0+"), // cargo via im-rc
/// This list is here to provide a speed-bump to adding a new dependency to
/// rustc. Please check with the compiler team before adding an entry.
const PERMITTED_DEPENDENCIES: &[&str] = &[
- "addr2line",
- "adler",
+ "adler32",
"aho-corasick",
"annotate-snippets",
"ansi_term",
"atty",
"autocfg",
"backtrace",
+ "backtrace-sys",
"bitflags",
"block-buffer",
"block-padding",
"generic-array",
"getopts",
"getrandom",
- "gimli",
"hashbrown",
"hermit-abi",
"humantime",
"miniz_oxide",
"nodrop",
"num_cpus",
- "object",
"once_cell",
"opaque-debug",
"parking_lot",
"src/tools/rust-installer",
"src/tools/rustfmt",
"src/doc/book",
- "src/backtrace",
// Filter RLS output directories
"target/rls",
];
message_on_add = """\
@*WG-prioritization/alerts* issue #{number} has been requested for prioritization.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#Unprioritized-I-prioritize)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#assign-priority-to-unprioritized-issues-with-i-prioritize-label)
- Priority?
- Regression?
- Notify people/groups?
message_on_add = """\
@*WG-prioritization/alerts* #{number} has been nominated for discussion in `T-compiler` meeting.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#I-nominated)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-i-nominated-issues)
- Already discussed?
- Worth the meeting time?
- Add agenda entry:
message_on_add = """\
@*WG-prioritization/alerts* PR #{number} has been requested for beta backport.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
Prepare agenda entry:
- Why nominated?
- Author, assignee?
message_on_add = """\
@*WG-prioritization/alerts* PR #{number} has been requested for stable backport.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#StableBeta-nominations)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-stablebeta-nominations)
Prepare agenda entry:
- Why nominated?
- Author, assignee?
message_on_add = """\
@*WG-prioritization/alerts* PR #{number} is waiting on `T-compiler`.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#PR%E2%80%99s-waiting-on-team)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-prs-waiting-on-team)
- Prepare agenda entry:
- What is it waiting for?
- Important details?
message_on_add = """\
@*WG-prioritization/alerts* issue #{number} has been assigned `P-critical`.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
- Notify people/groups?
- Assign if possible?
- Add to agenda:
message_on_add = """\
@*WG-prioritization/alerts* issue #{number} has been assigned `P-high` and is a regression.
-# [Procedure](https://hackmd.io/WJ0G17DHTHGgv0OW9I2PxA?view#P-critical-and-Unassigned-P-high-regressions)
+# [Procedure](https://forge.rust-lang.org/compiler/prioritization/procedure.html#summarize-p-critical-and-unassigned-p-high-regressions)
Is issue assigned? If not:
- Try to find an assignee?
- Otherwise add to agenda: