Merge from rustc
This commit is contained in:
commit
2d180714e1
1351 changed files with 53386 additions and 14824 deletions
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
|
|
@ -7,6 +7,6 @@ tracking issue or there are none, feel free to ignore this.
|
|||
This PR will get automatically assigned to a reviewer. In case you would like
|
||||
a specific user to review your work, you can assign it to them by using
|
||||
|
||||
r\? <reviewer name> (with the `\` removed)
|
||||
r? <reviewer name>
|
||||
-->
|
||||
<!-- homu-ignore:end -->
|
||||
|
|
|
|||
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
|
|
@ -2,7 +2,7 @@
|
|||
# and also on pushes to special branches (auto, try).
|
||||
#
|
||||
# The actual definition of the executed jobs is calculated by a Python
|
||||
# script located at src/ci/github-actions/calculate-job-matrix.py, which
|
||||
# script located at src/ci/github-actions/ci.py, which
|
||||
# uses job definition data from src/ci/github-actions/jobs.yml.
|
||||
# You should primarily modify the `jobs.yml` file if you want to modify
|
||||
# what jobs are executed in CI.
|
||||
|
|
@ -56,10 +56,10 @@ jobs:
|
|||
- name: Calculate the CI job matrix
|
||||
env:
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT
|
||||
run: python3 src/ci/github-actions/ci.py calculate-job-matrix >> $GITHUB_OUTPUT
|
||||
id: jobs
|
||||
job:
|
||||
name: ${{ matrix.name }}
|
||||
name: ${{ matrix.full_name }}
|
||||
needs: [ calculate_matrix ]
|
||||
runs-on: "${{ matrix.os }}"
|
||||
defaults:
|
||||
|
|
@ -67,7 +67,7 @@ jobs:
|
|||
shell: ${{ contains(matrix.os, 'windows') && 'msys2 {0}' || 'bash' }}
|
||||
timeout-minutes: 360
|
||||
env:
|
||||
CI_JOB_NAME: ${{ matrix.image }}
|
||||
CI_JOB_NAME: ${{ matrix.name }}
|
||||
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
|
||||
# commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs.
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
|
|
@ -233,7 +233,7 @@ jobs:
|
|||
env:
|
||||
DATADOG_SITE: datadoghq.com
|
||||
DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }}
|
||||
DD_GITHUB_JOB_NAME: ${{ matrix.name }}
|
||||
DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
|
||||
run: |
|
||||
cd src/ci
|
||||
npm ci
|
||||
|
|
|
|||
101
Cargo.lock
101
Cargo.lock
|
|
@ -185,9 +185,6 @@ name = "anyhow"
|
|||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ar_archive_writer"
|
||||
|
|
@ -285,9 +282,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.11.1"
|
||||
version = "1.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8"
|
||||
checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata 0.4.9",
|
||||
|
|
@ -533,7 +530,7 @@ dependencies = [
|
|||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -544,7 +541,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.85"
|
||||
version = "0.1.86"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
|
@ -564,7 +561,7 @@ dependencies = [
|
|||
"rustc_tools_util",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"tempfile",
|
||||
"termize",
|
||||
"tokio",
|
||||
|
|
@ -575,7 +572,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.85"
|
||||
version = "0.1.86"
|
||||
dependencies = [
|
||||
"clippy_utils",
|
||||
"itertools",
|
||||
|
|
@ -600,7 +597,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.85"
|
||||
version = "0.1.86"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
|
@ -623,7 +620,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.85"
|
||||
version = "0.1.86"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itertools",
|
||||
|
|
@ -674,7 +671,7 @@ dependencies = [
|
|||
"nom",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -899,7 +896,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -910,7 +907,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
|||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -947,7 +944,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -968,7 +965,7 @@ dependencies = [
|
|||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -978,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -990,7 +987,7 @@ dependencies = [
|
|||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1068,7 +1065,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1365,7 +1362,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1599,7 +1596,7 @@ dependencies = [
|
|||
"markup5ever",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1788,7 +1785,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2744,7 +2741,7 @@ dependencies = [
|
|||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3154,7 +3151,7 @@ dependencies = [
|
|||
"rinja_parser",
|
||||
"rustc-hash 2.1.0",
|
||||
"serde",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3499,6 +3496,7 @@ name = "rustc_codegen_llvm"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"gimli 0.30.0",
|
||||
"itertools",
|
||||
"libc",
|
||||
"measureme",
|
||||
|
|
@ -3794,7 +3792,7 @@ dependencies = [
|
|||
"fluent-syntax",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"unic-langid",
|
||||
]
|
||||
|
||||
|
|
@ -3929,7 +3927,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4077,7 +4075,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -4117,7 +4115,6 @@ name = "rustc_middle"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"derive-where",
|
||||
"either",
|
||||
"field-offset",
|
||||
"gsgdt",
|
||||
|
|
@ -4161,6 +4158,7 @@ dependencies = [
|
|||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -4665,7 +4663,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -4754,7 +4752,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4891,7 +4889,7 @@ checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5008,9 +5006,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "spdx"
|
||||
version = "0.10.7"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bae30cc7bfe3656d60ee99bf6836f472b0c53dddcbf335e253329abb16e535a2"
|
||||
checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
|
@ -5149,9 +5147,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.93"
|
||||
version = "2.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c786062daee0d6db1132800e623df74274a0a87322d8e183338e01b3d98d058"
|
||||
checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -5166,7 +5164,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5203,12 +5201,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.14.0"
|
||||
version = "3.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
||||
checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
|
|
@ -5308,7 +5307,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5319,7 +5318,7 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5520,7 +5519,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5691,7 +5690,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b"
|
|||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"unic-langid-impl",
|
||||
]
|
||||
|
||||
|
|
@ -5897,7 +5896,7 @@ dependencies = [
|
|||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
|
@ -5919,7 +5918,7 @@ checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
|
@ -6101,7 +6100,7 @@ dependencies = [
|
|||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"windows-metadata",
|
||||
]
|
||||
|
||||
|
|
@ -6134,7 +6133,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6145,7 +6144,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6424,7 +6423,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -6446,7 +6445,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6466,7 +6465,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
|
|
@ -6489,5 +6488,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.93",
|
||||
"syn 2.0.94",
|
||||
]
|
||||
|
|
|
|||
118
RELEASES.md
118
RELEASES.md
|
|
@ -1,3 +1,119 @@
|
|||
Version 1.84.0 (2025-01-09)
|
||||
==========================
|
||||
|
||||
<a id="
|
||||
Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Allow `#[deny]` inside `#[forbid]` as a no-op](https://github.com/rust-lang/rust/pull/121560/)
|
||||
- [Show a warning when `-Ctarget-feature` is used to toggle features that can lead to unsoundness due to ABI mismatches](https://github.com/rust-lang/rust/pull/129884)
|
||||
- [Use the next-generation trait solver in coherence](https://github.com/rust-lang/rust/pull/130654)
|
||||
- [Allow coercions to drop the principal of trait objects](https://github.com/rust-lang/rust/pull/131857)
|
||||
- [Support `/` as the path separator for `include!()` in all cases on Windows](https://github.com/rust-lang/rust/pull/125205)
|
||||
- [Taking a raw ref (`raw (const|mut)`) of a deref of a pointer (`*ptr`) is now safe](https://github.com/rust-lang/rust/pull/129248)
|
||||
- [Stabilize s390x inline assembly](https://github.com/rust-lang/rust/pull/131258)
|
||||
- [Stabilize Arm64EC inline assembly](https://github.com/rust-lang/rust/pull/131781)
|
||||
- [Lint against creating pointers to immediately dropped temporaries](https://github.com/rust-lang/rust/pull/128985)
|
||||
- [Execute drop glue when unwinding in an `extern "C"` function](https://github.com/rust-lang/rust/pull/129582)
|
||||
|
||||
<a id="1.84.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Add `--print host-tuple` flag to print the host target tuple and affirm the "target tuple" terminology over "target triple"](https://github.com/rust-lang/rust/pull/125579)
|
||||
- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935)
|
||||
- [Set up indirect access to external data for `loongarch64-unknown-linux-{musl,ohos}`](https://github.com/rust-lang/rust/pull/131583)
|
||||
- [Enable XRay instrumentation for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/131818)
|
||||
- [Extend the `unexpected_cfgs` lint to also warn in external macros](https://github.com/rust-lang/rust/pull/132577)
|
||||
- [Stabilize WebAssembly `multivalue`, `reference-types`, and `tail-call` target features](https://github.com/rust-lang/rust/pull/131080)
|
||||
- [Added Tier 2 support for the `wasm32v1-none` target](https://github.com/rust-lang/rust/pull/131487)
|
||||
|
||||
<a id="1.84.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Implement `From<&mut {slice}>` for `Box/Rc/Arc<{slice}>`](https://github.com/rust-lang/rust/pull/129329)
|
||||
- [Move `<float>::copysign`, `<float>::abs`, `<float>::signum` to `core`](https://github.com/rust-lang/rust/pull/131304)
|
||||
- [Add `LowerExp` and `UpperExp` implementations to `NonZero`](https://github.com/rust-lang/rust/pull/131377)
|
||||
- [Implement `FromStr` for `CString` and `TryFrom<CString>` for `String`](https://github.com/rust-lang/rust/pull/130608)
|
||||
- [`std::os::darwin` has been made public](https://github.com/rust-lang/rust/pull/123723)
|
||||
|
||||
<a id="1.84.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`Ipv6Addr::is_unique_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unique_local)
|
||||
- [`Ipv6Addr::is_unicast_link_local`](https://doc.rust-lang.org/stable/core/net/struct.Ipv6Addr.html#method.is_unicast_link_local)
|
||||
- [`core::ptr::with_exposed_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance.html)
|
||||
- [`core::ptr::with_exposed_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.with_exposed_provenance_mut.html)
|
||||
- [`<ptr>::addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.addr)
|
||||
- [`<ptr>::expose_provenance`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.expose_provenance)
|
||||
- [`<ptr>::with_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.with_addr)
|
||||
- [`<ptr>::map_addr`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.map_addr)
|
||||
- [`<int>::isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.isqrt)
|
||||
- [`<int>::checked_isqrt`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.checked_isqrt)
|
||||
- [`<uint>::isqrt`](https://doc.rust-lang.org/stable/core/primitive.u32.html#method.isqrt)
|
||||
- [`NonZero::isqrt`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html#impl-NonZero%3Cu128%3E/method.isqrt)
|
||||
- [`core::ptr::without_provenance`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance.html)
|
||||
- [`core::ptr::without_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance_mut.html)
|
||||
- [`core::ptr::dangling`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling.html)
|
||||
- [`core::ptr::dangling_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling_mut.html)
|
||||
- [`Pin::as_deref_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.as_deref_mut)
|
||||
|
||||
These APIs are now stable in const contexts
|
||||
|
||||
- [`AtomicBool::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicBool.html#method.from_ptr)
|
||||
- [`AtomicPtr::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicPtr.html#method.from_ptr)
|
||||
- [`AtomicU8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU8.html#method.from_ptr)
|
||||
- [`AtomicU16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU16.html#method.from_ptr)
|
||||
- [`AtomicU32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU32.html#method.from_ptr)
|
||||
- [`AtomicU64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicU64.html#method.from_ptr)
|
||||
- [`AtomicUsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.from_ptr)
|
||||
- [`AtomicI8::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI8.html#method.from_ptr)
|
||||
- [`AtomicI16::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI16.html#method.from_ptr)
|
||||
- [`AtomicI32::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI32.html#method.from_ptr)
|
||||
- [`AtomicI64::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicI64.html#method.from_ptr)
|
||||
- [`AtomicIsize::from_ptr`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicIsize.html#method.from_ptr)
|
||||
- [`<ptr>::is_null`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_null-1)
|
||||
- [`<ptr>::as_ref`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_ref-1)
|
||||
- [`<ptr>::as_mut`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.as_mut)
|
||||
- [`Pin::new`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new)
|
||||
- [`Pin::new_unchecked`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.new_unchecked)
|
||||
- [`Pin::get_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_ref)
|
||||
- [`Pin::into_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.into_ref)
|
||||
- [`Pin::get_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_mut)
|
||||
- [`Pin::get_unchecked_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.get_unchecked_mut)
|
||||
- [`Pin::static_ref`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_ref)
|
||||
- [`Pin::static_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.static_mut)
|
||||
|
||||
<a id="1.84.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [Stabilize MSRV-aware resolver config](https://github.com/rust-lang/cargo/pull/14639/)
|
||||
- [Stabilize resolver v3](https://github.com/rust-lang/cargo/pull/14754/)
|
||||
|
||||
<a id="1.84-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-------
|
||||
|
||||
- [rustdoc-search: improve type-driven search](https://github.com/rust-lang/rust/pull/127589)
|
||||
|
||||
<a id="1.84.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Enable by default the `LSX` target feature for LoongArch Linux targets](https://github.com/rust-lang/rust/pull/132140)
|
||||
- [The unstable `-Zprofile` flag (“gcov-style” coverage instrumentation) has been removed.](https://github.com/rust-lang/rust/pull/131829) This does not affect the stable flags for coverage instrumentation (`-Cinstrument-coverage`) and profile-guided optimization (`-Cprofile-generate`, `-Cprofile-use`), which are unrelated and remain available.
|
||||
- Support for the target named `wasm32-wasi` has been removed as the target is now named `wasm32-wasip1`. This completes the [transition](https://github.com/rust-lang/compiler-team/issues/607) [plan](https://github.com/rust-lang/compiler-team/issues/695) for this target following [the introduction of `wasm32-wasip1`](https://github.com/rust-lang/rust/pull/120468) in Rust 1.78. Compiler warnings on [use of `wasm32-wasi`](https://github.com/rust-lang/rust/pull/126662) introduced in Rust 1.81 are now gone as well as the target is removed.
|
||||
- [The syntax `&pin (mut|const) T` is now parsed as a type which in theory could affect macro expansion results in some edge cases](https://github.com/rust-lang/rust/pull/130635#issuecomment-2375462821)
|
||||
- [Legacy syntax for calling `std::arch` functions is no longer permitted to declare items or bodies (such as closures, inline consts, or async blocks).](https://github.com/rust-lang/rust/pull/130443#issuecomment-2445678945)
|
||||
- [Declaring functions with a calling convention not supported on the current target now triggers a hard error](https://github.com/rust-lang/rust/pull/129935)
|
||||
- [The next-generation trait solver is now enabled for coherence, fixing multiple soundness issues](https://github.com/rust-lang/rust/pull/130654)
|
||||
|
||||
Version 1.83.0 (2024-11-28)
|
||||
==========================
|
||||
|
||||
|
|
@ -2067,7 +2183,7 @@ Language
|
|||
--------
|
||||
|
||||
- [Stabilize default_alloc_error_handler](https://github.com/rust-lang/rust/pull/102318/)
|
||||
This allows usage of `alloc` on stable without requiring the
|
||||
This allows usage of `alloc` on stable without requiring the
|
||||
definition of a handler for allocation failure. Defining custom handlers is still unstable.
|
||||
- [Stabilize `efiapi` calling convention.](https://github.com/rust-lang/rust/pull/105795/)
|
||||
- [Remove implicit promotion for types with drop glue](https://github.com/rust-lang/rust/pull/105085/)
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
.chain(Niche::from_scalar(dl, Size::ZERO, a))
|
||||
.max_by_key(|niche| niche.available(dl));
|
||||
|
||||
let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes());
|
||||
|
||||
LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Arbitrary {
|
||||
|
|
@ -131,6 +133,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
size,
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: align.abi,
|
||||
randomization_seed: combined_seed,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -223,6 +226,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
size: Size::ZERO,
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: dl.i8_align.abi,
|
||||
randomization_seed: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -385,6 +389,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
return Err(LayoutCalculatorError::EmptyUnion);
|
||||
};
|
||||
|
||||
let combined_seed = only_variant
|
||||
.iter()
|
||||
.map(|v| v.randomization_seed)
|
||||
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
|
||||
|
||||
Ok(LayoutData {
|
||||
variants: Variants::Single { index: only_variant_idx },
|
||||
fields: FieldsShape::Union(union_field_count),
|
||||
|
|
@ -394,6 +403,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
size: size.align_to(align.abi),
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
randomization_seed: combined_seed,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -650,6 +660,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
BackendRepr::Memory { sized: true }
|
||||
};
|
||||
|
||||
let combined_seed = variant_layouts
|
||||
.iter()
|
||||
.map(|v| v.randomization_seed)
|
||||
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
|
||||
|
||||
let layout = LayoutData {
|
||||
variants: Variants::Multiple {
|
||||
tag: niche_scalar,
|
||||
|
|
@ -671,6 +686,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
align,
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
randomization_seed: combined_seed,
|
||||
};
|
||||
|
||||
Some(TmpLayout { layout, variants: variant_layouts })
|
||||
|
|
@ -961,6 +977,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
|
||||
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
|
||||
|
||||
let combined_seed = layout_variants
|
||||
.iter()
|
||||
.map(|v| v.randomization_seed)
|
||||
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
|
||||
|
||||
let tagged_layout = LayoutData {
|
||||
variants: Variants::Multiple {
|
||||
tag,
|
||||
|
|
@ -978,6 +999,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
size,
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
randomization_seed: combined_seed,
|
||||
};
|
||||
|
||||
let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
|
||||
|
|
@ -1030,12 +1052,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let mut max_repr_align = repr.align;
|
||||
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
|
||||
let optimize_field_order = !repr.inhibit_struct_field_reordering();
|
||||
if optimize_field_order && fields.len() > 1 {
|
||||
let end =
|
||||
if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
||||
let optimizing = &mut inverse_memory_index.raw[..end];
|
||||
let fields_excluding_tail = &fields.raw[..end];
|
||||
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
|
||||
let optimizing = &mut inverse_memory_index.raw[..end];
|
||||
let fields_excluding_tail = &fields.raw[..end];
|
||||
// unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts.
|
||||
let field_seed = fields_excluding_tail
|
||||
.iter()
|
||||
.fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed));
|
||||
|
||||
if optimize_field_order && fields.len() > 1 {
|
||||
// If `-Z randomize-layout` was enabled for the type definition we can shuffle
|
||||
// the field ordering to try and catch some code making assumptions about layouts
|
||||
// we don't guarantee.
|
||||
|
|
@ -1046,8 +1071,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
use rand::seq::SliceRandom;
|
||||
// `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field
|
||||
// ordering.
|
||||
let mut rng =
|
||||
rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
|
||||
let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(
|
||||
field_seed.wrapping_add(repr.field_shuffle_seed),
|
||||
);
|
||||
|
||||
// Shuffle the ordering of the fields.
|
||||
optimizing.shuffle(&mut rng);
|
||||
|
|
@ -1344,6 +1370,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
unadjusted_abi_align
|
||||
};
|
||||
|
||||
let seed = field_seed.wrapping_add(repr.field_shuffle_seed);
|
||||
|
||||
Ok(LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Arbitrary { offsets, memory_index },
|
||||
|
|
@ -1353,6 +1381,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
size,
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
randomization_seed: seed,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1719,6 +1719,18 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
|
|||
/// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment
|
||||
/// in some cases.
|
||||
pub unadjusted_abi_align: Align,
|
||||
|
||||
/// The randomization seed based on this type's own repr and its fields.
|
||||
///
|
||||
/// Since randomization is toggled on a per-crate basis even crates that do not have randomization
|
||||
/// enabled should still calculate a seed so that downstream uses can use it to distinguish different
|
||||
/// types.
|
||||
///
|
||||
/// For every T and U for which we do not guarantee that a repr(Rust) `Foo<T>` can be coerced or
|
||||
/// transmuted to `Foo<U>` we aim to create probalistically distinct seeds so that Foo can choose
|
||||
/// to reorder its fields based on that information. The current implementation is a conservative
|
||||
/// approximation of this goal.
|
||||
pub randomization_seed: u64,
|
||||
}
|
||||
|
||||
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
||||
|
|
@ -1739,6 +1751,30 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
|
||||
let size = scalar.size(cx);
|
||||
let align = scalar.align(cx);
|
||||
|
||||
let range = scalar.valid_range(cx);
|
||||
|
||||
// All primitive types for which we don't have subtype coercions should get a distinct seed,
|
||||
// so that types wrapping them can use randomization to arrive at distinct layouts.
|
||||
//
|
||||
// Some type information is already lost at this point, so as an approximation we derive
|
||||
// the seed from what remains. For example on 64-bit targets usize and u64 can no longer
|
||||
// be distinguished.
|
||||
let randomization_seed = size
|
||||
.bytes()
|
||||
.wrapping_add(
|
||||
match scalar.primitive() {
|
||||
Primitive::Int(_, true) => 1,
|
||||
Primitive::Int(_, false) => 2,
|
||||
Primitive::Float(_) => 3,
|
||||
Primitive::Pointer(_) => 4,
|
||||
} << 32,
|
||||
)
|
||||
// distinguishes references from pointers
|
||||
.wrapping_add((range.start as u64).rotate_right(16))
|
||||
// distinguishes char from u32 and bool from u8
|
||||
.wrapping_add((range.end as u64).rotate_right(16));
|
||||
|
||||
LayoutData {
|
||||
variants: Variants::Single { index: VariantIdx::new(0) },
|
||||
fields: FieldsShape::Primitive,
|
||||
|
|
@ -1748,6 +1784,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
|
|||
align,
|
||||
max_repr_align: None,
|
||||
unadjusted_abi_align: align.abi,
|
||||
randomization_seed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1770,6 +1807,7 @@ where
|
|||
variants,
|
||||
max_repr_align,
|
||||
unadjusted_abi_align,
|
||||
ref randomization_seed,
|
||||
} = self;
|
||||
f.debug_struct("Layout")
|
||||
.field("size", size)
|
||||
|
|
@ -1780,6 +1818,7 @@ where
|
|||
.field("variants", variants)
|
||||
.field("max_repr_align", max_repr_align)
|
||||
.field("unadjusted_abi_align", unadjusted_abi_align)
|
||||
.field("randomization_seed", randomization_seed)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ impl<T> ArenaChunk<T> {
|
|||
// been initialized.
|
||||
unsafe {
|
||||
let slice = self.storage.as_mut();
|
||||
ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));
|
||||
slice[..len].assume_init_drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -623,7 +623,7 @@ impl Pat {
|
|||
PatKind::Wild
|
||||
| PatKind::Rest
|
||||
| PatKind::Never
|
||||
| PatKind::Lit(_)
|
||||
| PatKind::Expr(_)
|
||||
| PatKind::Range(..)
|
||||
| PatKind::Ident(..)
|
||||
| PatKind::Path(..)
|
||||
|
|
@ -801,8 +801,8 @@ pub enum PatKind {
|
|||
/// A reference pattern (e.g., `&mut (a, b)`).
|
||||
Ref(P<Pat>, Mutability),
|
||||
|
||||
/// A literal.
|
||||
Lit(P<Expr>),
|
||||
/// A literal, const block or path.
|
||||
Expr(P<Expr>),
|
||||
|
||||
/// A range pattern (e.g., `1...2`, `1..2`, `1..`, `..2`, `1..=2`, `..=2`).
|
||||
Range(Option<P<Expr>>, Option<P<Expr>>, Spanned<RangeEnd>),
|
||||
|
|
|
|||
|
|
@ -1512,7 +1512,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
|||
vis.visit_ident(ident);
|
||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||
}
|
||||
PatKind::Lit(e) => vis.visit_expr(e),
|
||||
PatKind::Expr(e) => vis.visit_expr(e),
|
||||
PatKind::TupleStruct(qself, path, elems) => {
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#![cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
#![allow(rustc::symbol_intern_string_literal)]
|
||||
|
||||
use rustc_span::create_default_session_globals_then;
|
||||
|
||||
|
|
|
|||
|
|
@ -680,7 +680,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
|||
try_visit!(visitor.visit_ident(ident));
|
||||
visit_opt!(visitor, visit_pat, optional_subpattern);
|
||||
}
|
||||
PatKind::Lit(expression) => try_visit!(visitor.visit_expr(expression)),
|
||||
PatKind::Expr(expression) => try_visit!(visitor.visit_expr(expression)),
|
||||
PatKind::Range(lower_bound, upper_bound, _end) => {
|
||||
visit_opt!(visitor, visit_expr, lower_bound);
|
||||
visit_opt!(visitor, visit_expr, upper_bound);
|
||||
|
|
|
|||
|
|
@ -102,17 +102,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
ExprKind::ConstBlock(c) => {
|
||||
let c = self.with_new_scopes(c.value.span, |this| {
|
||||
let def_id = this.local_def_id(c.id);
|
||||
hir::ConstBlock {
|
||||
def_id,
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
}
|
||||
});
|
||||
hir::ExprKind::ConstBlock(c)
|
||||
}
|
||||
ExprKind::ConstBlock(c) => hir::ExprKind::ConstBlock(self.lower_const_block(c)),
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
let expr = self.lower_expr(expr);
|
||||
let count = self.lower_array_length_to_const_arg(count);
|
||||
|
|
@ -153,18 +143,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let ohs = self.lower_expr(ohs);
|
||||
hir::ExprKind::Unary(op, ohs)
|
||||
}
|
||||
ExprKind::Lit(token_lit) => {
|
||||
let lit_kind = match LitKind::from_token_lit(*token_lit) {
|
||||
Ok(lit_kind) => lit_kind,
|
||||
Err(err) => {
|
||||
let guar =
|
||||
report_lit_error(&self.tcx.sess.psess, err, *token_lit, e.span);
|
||||
LitKind::Err(guar)
|
||||
}
|
||||
};
|
||||
let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind));
|
||||
hir::ExprKind::Lit(lit)
|
||||
}
|
||||
ExprKind::Lit(token_lit) => hir::ExprKind::Lit(self.lower_lit(token_lit, e.span)),
|
||||
ExprKind::IncludedBytes(bytes) => {
|
||||
let lit = self.arena.alloc(respan(
|
||||
self.lower_span(e.span),
|
||||
|
|
@ -403,6 +382,32 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
|
||||
self.with_new_scopes(c.value.span, |this| {
|
||||
let def_id = this.local_def_id(c.id);
|
||||
hir::ConstBlock {
|
||||
def_id,
|
||||
hir_id: this.lower_node_id(c.id),
|
||||
body: this.lower_const_body(c.value.span, Some(&c.value)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn lower_lit(
|
||||
&mut self,
|
||||
token_lit: &token::Lit,
|
||||
span: Span,
|
||||
) -> &'hir Spanned<LitKind> {
|
||||
let lit_kind = match LitKind::from_token_lit(*token_lit) {
|
||||
Ok(lit_kind) => lit_kind,
|
||||
Err(err) => {
|
||||
let guar = report_lit_error(&self.tcx.sess.psess, err, *token_lit, span);
|
||||
LitKind::Err(guar)
|
||||
}
|
||||
};
|
||||
self.arena.alloc(respan(self.lower_span(span), lit_kind))
|
||||
}
|
||||
|
||||
fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
|
||||
match u {
|
||||
UnOp::Deref => hir::UnOp::Deref,
|
||||
|
|
|
|||
|
|
@ -209,6 +209,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
});
|
||||
}
|
||||
|
||||
fn visit_pat_expr(&mut self, expr: &'hir PatExpr<'hir>) {
|
||||
self.insert(expr.span, expr.hir_id, Node::PatExpr(expr));
|
||||
|
||||
self.with_parent(expr.hir_id, |this| {
|
||||
intravisit::walk_pat_expr(this, expr);
|
||||
});
|
||||
}
|
||||
|
||||
fn visit_pat_field(&mut self, field: &'hir PatField<'hir>) {
|
||||
self.insert(field.span, field.hir_id, Node::PatField(field));
|
||||
self.with_parent(field.hir_id, |this| {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![warn(unreachable_pub)]
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_span::source_map::{Spanned, respan};
|
||||
use rustc_span::{Ident, Span};
|
||||
|
||||
use super::errors::{
|
||||
|
|
@ -35,8 +38,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
lower_sub,
|
||||
);
|
||||
}
|
||||
PatKind::Lit(e) => {
|
||||
break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
|
||||
PatKind::Expr(e) => {
|
||||
break hir::PatKind::Expr(self.lower_expr_within_pat(e, false));
|
||||
}
|
||||
PatKind::TupleStruct(qself, path, pats) => {
|
||||
let qpath = self.lower_qpath(
|
||||
|
|
@ -120,8 +123,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.lower_range_end(end, e2.is_some()),
|
||||
);
|
||||
}
|
||||
// FIXME(guard_patterns): lower pattern guards to HIR
|
||||
PatKind::Guard(inner, _) => pattern = inner,
|
||||
PatKind::Guard(inner, cond) => {
|
||||
break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
|
||||
}
|
||||
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
|
||||
PatKind::Rest => {
|
||||
// If we reach here the `..` pattern is not semantically allowed.
|
||||
|
|
@ -366,24 +370,54 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// }
|
||||
// m!(S);
|
||||
// ```
|
||||
fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
|
||||
match &expr.kind {
|
||||
ExprKind::Lit(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::IncludedBytes(..)
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => {}
|
||||
ExprKind::Path(..) if allow_paths => {}
|
||||
ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
|
||||
fn lower_expr_within_pat(
|
||||
&mut self,
|
||||
expr: &Expr,
|
||||
allow_paths: bool,
|
||||
) -> &'hir hir::PatExpr<'hir> {
|
||||
let err = |guar| hir::PatExprKind::Lit {
|
||||
lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))),
|
||||
negated: false,
|
||||
};
|
||||
let kind = match &expr.kind {
|
||||
ExprKind::Lit(lit) => {
|
||||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false }
|
||||
}
|
||||
ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
|
||||
ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
|
||||
lit: self.arena.alloc(respan(
|
||||
self.lower_span(expr.span),
|
||||
LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked),
|
||||
)),
|
||||
negated: false,
|
||||
},
|
||||
ExprKind::Err(guar) => err(*guar),
|
||||
ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"),
|
||||
ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath(
|
||||
expr.id,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
AllowReturnTypeNotation::No,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
None,
|
||||
)),
|
||||
ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
|
||||
hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true }
|
||||
}
|
||||
_ => {
|
||||
let pattern_from_macro = expr.is_approximately_pattern();
|
||||
let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
|
||||
span: expr.span,
|
||||
pattern_from_macro_note: pattern_from_macro,
|
||||
});
|
||||
return self.arena.alloc(self.expr_err(expr.span, guar));
|
||||
err(guar)
|
||||
}
|
||||
}
|
||||
self.lower_expr(expr)
|
||||
};
|
||||
self.arena.alloc(hir::PatExpr {
|
||||
hir_id: self.lower_node_id(expr.id),
|
||||
span: expr.span,
|
||||
kind,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
ast::ItemKind::Struct(..) => {
|
||||
ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => {
|
||||
for attr in attr::filter_by_name(&i.attrs, sym::repr) {
|
||||
for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
|
||||
if item.has_name(sym::simd) {
|
||||
|
|
@ -692,7 +692,7 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
|||
.find(|feat| feat.gate_name == sym::generic_const_exprs)
|
||||
.map(|feat| feat.attr_sp)
|
||||
{
|
||||
#[cfg_attr(not(bootstrap), allow(rustc::symbol_intern_string_literal))]
|
||||
#[allow(rustc::symbol_intern_string_literal)]
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures {
|
||||
spans: vec![gce_span],
|
||||
f1: Symbol::intern("-Znext-solver=globally"),
|
||||
|
|
|
|||
|
|
@ -1701,7 +1701,7 @@ impl<'a> State<'a> {
|
|||
self.print_pat(inner);
|
||||
}
|
||||
}
|
||||
PatKind::Lit(e) => self.print_expr(e, FixupContext::default()),
|
||||
PatKind::Expr(e) => self.print_expr(e, FixupContext::default()),
|
||||
PatKind::Range(begin, end, Spanned { node: end_kind, .. }) => {
|
||||
if let Some(e) = begin {
|
||||
self.print_expr(e, FixupContext::default());
|
||||
|
|
|
|||
|
|
@ -11,6 +11,22 @@ pub enum InlineAttr {
|
|||
Hint,
|
||||
Always,
|
||||
Never,
|
||||
/// `#[rustc_force_inline]` forces inlining to happen in the MIR inliner - it reports an error
|
||||
/// if the inlining cannot happen. It is limited to only free functions so that the calls
|
||||
/// can always be resolved.
|
||||
Force {
|
||||
attr_span: Span,
|
||||
reason: Option<Symbol>,
|
||||
},
|
||||
}
|
||||
|
||||
impl InlineAttr {
|
||||
pub fn always(&self) -> bool {
|
||||
match self {
|
||||
InlineAttr::Always | InlineAttr::Force { .. } => true,
|
||||
InlineAttr::None | InlineAttr::Hint | InlineAttr::Never => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq, HashStable_Generic)]
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@ use crate::RustcVersion;
|
|||
/// `since` field of the `#[stable]` attribute.
|
||||
///
|
||||
/// For more, see [this pull request](https://github.com/rust-lang/rust/pull/100591).
|
||||
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
|
||||
pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N");
|
||||
// Note that the `concat!` macro above prevents `src/tools/replace-version-placeholder` from
|
||||
// replacing the constant with the current version. Hardcoding the tool to skip this file doesn't
|
||||
// work as the file can (and at some point will) be moved around.
|
||||
//
|
||||
// Turning the `concat!` macro into a string literal will make Pietro cry. That'd be sad :(
|
||||
|
||||
/// Represents the following attributes:
|
||||
///
|
||||
|
|
|
|||
|
|
@ -213,6 +213,10 @@ borrowck_suggest_create_fresh_reborrow =
|
|||
borrowck_suggest_iterate_over_slice =
|
||||
consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
|
||||
|
||||
borrowck_tail_expr_drop_order = relative drop order changing in Rust 2024
|
||||
.label = this temporary value will be dropped at the end of the block
|
||||
.note = consider using a `let` binding to ensure the value will live long enough
|
||||
|
||||
borrowck_ty_no_impl_copy =
|
||||
{$is_partial_move ->
|
||||
[true] partial move
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
|||
use std::ops::Index;
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{self, Body, Local, Location, traversal};
|
||||
use rustc_middle::span_bug;
|
||||
|
|
@ -11,7 +11,6 @@ use rustc_mir_dataflow::move_paths::MoveData;
|
|||
use tracing::debug;
|
||||
|
||||
use crate::BorrowIndex;
|
||||
use crate::path_utils::allow_two_phase_borrow;
|
||||
use crate::place_ext::PlaceExt;
|
||||
|
||||
pub struct BorrowSet<'tcx> {
|
||||
|
|
@ -132,7 +131,7 @@ impl<'tcx> fmt::Display for BorrowData<'tcx> {
|
|||
|
||||
pub enum LocalsStateAtExit {
|
||||
AllAreInvalidated,
|
||||
SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> },
|
||||
SomeAreInvalidated { has_storage_dead_or_moved: DenseBitSet<Local> },
|
||||
}
|
||||
|
||||
impl LocalsStateAtExit {
|
||||
|
|
@ -141,7 +140,7 @@ impl LocalsStateAtExit {
|
|||
body: &Body<'tcx>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) -> Self {
|
||||
struct HasStorageDead(BitSet<Local>);
|
||||
struct HasStorageDead(DenseBitSet<Local>);
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for HasStorageDead {
|
||||
fn visit_local(&mut self, local: Local, ctx: PlaceContext, _: Location) {
|
||||
|
|
@ -154,7 +153,8 @@ impl LocalsStateAtExit {
|
|||
if locals_are_invalidated_at_exit {
|
||||
LocalsStateAtExit::AllAreInvalidated
|
||||
} else {
|
||||
let mut has_storage_dead = HasStorageDead(BitSet::new_empty(body.local_decls.len()));
|
||||
let mut has_storage_dead =
|
||||
HasStorageDead(DenseBitSet::new_empty(body.local_decls.len()));
|
||||
has_storage_dead.visit_body(body);
|
||||
let mut has_storage_dead_or_moved = has_storage_dead.0;
|
||||
for move_out in &move_data.moves {
|
||||
|
|
@ -350,7 +350,7 @@ impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
|
|||
start_location, assigned_place, borrow_index,
|
||||
);
|
||||
|
||||
if !allow_two_phase_borrow(kind) {
|
||||
if !kind.allows_two_phase_borrow() {
|
||||
debug!(" -> {:?}", start_location);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ pub use super::dataflow::{BorrowIndex, Borrows, calculate_borrows_out_of_scope_a
|
|||
pub use super::place_ext::PlaceExt;
|
||||
pub use super::places_conflict::{PlaceConflictBias, places_conflict};
|
||||
pub use super::polonius::legacy::{
|
||||
AllFacts as PoloniusInput, LocationTable, PoloniusOutput, PoloniusRegionVid, RichLocation,
|
||||
RustcFacts,
|
||||
PoloniusFacts as PoloniusInput, PoloniusLocationTable, PoloniusOutput, PoloniusRegionVid,
|
||||
RichLocation, RustcFacts,
|
||||
};
|
||||
pub use super::region_infer::RegionInferenceContext;
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ pub enum ConsumerOptions {
|
|||
/// without significant slowdowns.
|
||||
///
|
||||
/// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext),
|
||||
/// and additionally retrieve the [`LocationTable`] and [`PoloniusInput`] that
|
||||
/// and additionally retrieve the [`PoloniusLocationTable`] and [`PoloniusInput`] that
|
||||
/// would be given to Polonius. Critically, this does not run Polonius, which
|
||||
/// one may want to avoid due to performance issues on large bodies.
|
||||
PoloniusInputFacts,
|
||||
|
|
@ -71,7 +71,7 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
|||
/// The table that maps Polonius points to locations in the table.
|
||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
pub location_table: Option<LocationTable>,
|
||||
pub location_table: Option<PoloniusLocationTable>,
|
||||
/// Polonius input facts.
|
||||
/// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
|
||||
/// or [`ConsumerOptions::PoloniusOutputFacts`].
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
|||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
|
||||
};
|
||||
|
|
@ -180,7 +180,7 @@ pub struct Borrows<'a, 'tcx> {
|
|||
}
|
||||
|
||||
struct OutOfScopePrecomputer<'a, 'tcx> {
|
||||
visited: BitSet<mir::BasicBlock>,
|
||||
visited: DenseBitSet<mir::BasicBlock>,
|
||||
visit_stack: Vec<mir::BasicBlock>,
|
||||
body: &'a Body<'tcx>,
|
||||
regioncx: &'a RegionInferenceContext<'tcx>,
|
||||
|
|
@ -190,7 +190,7 @@ struct OutOfScopePrecomputer<'a, 'tcx> {
|
|||
impl<'a, 'tcx> OutOfScopePrecomputer<'a, 'tcx> {
|
||||
fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
|
||||
OutOfScopePrecomputer {
|
||||
visited: BitSet::new_empty(body.basic_blocks.len()),
|
||||
visited: DenseBitSet::new_empty(body.basic_blocks.len()),
|
||||
visit_stack: vec![],
|
||||
body,
|
||||
regioncx,
|
||||
|
|
@ -292,7 +292,7 @@ pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
|
|||
}
|
||||
|
||||
struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
|
||||
visited: BitSet<mir::BasicBlock>,
|
||||
visited: DenseBitSet<mir::BasicBlock>,
|
||||
visit_stack: Vec<mir::BasicBlock>,
|
||||
body: &'a Body<'tcx>,
|
||||
regioncx: &'a RegionInferenceContext<'tcx>,
|
||||
|
|
@ -303,7 +303,7 @@ struct PoloniusOutOfScopePrecomputer<'a, 'tcx> {
|
|||
impl<'a, 'tcx> PoloniusOutOfScopePrecomputer<'a, 'tcx> {
|
||||
fn new(body: &'a Body<'tcx>, regioncx: &'a RegionInferenceContext<'tcx>) -> Self {
|
||||
Self {
|
||||
visited: BitSet::new_empty(body.basic_blocks.len()),
|
||||
visited: DenseBitSet::new_empty(body.basic_blocks.len()),
|
||||
visit_stack: vec![],
|
||||
body,
|
||||
regioncx,
|
||||
|
|
@ -559,7 +559,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
type BorrowsDomain = BitSet<BorrowIndex>;
|
||||
type BorrowsDomain = DenseBitSet<BorrowIndex>;
|
||||
|
||||
/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
|
||||
/// - we gen the introduced loans
|
||||
|
|
@ -575,7 +575,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
|
||||
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
|
||||
// bottom = nothing is reserved or activated yet;
|
||||
BitSet::new_empty(self.borrow_set.len())
|
||||
DenseBitSet::new_empty(self.borrow_set.len())
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
|
||||
|
|
|
|||
|
|
@ -1516,15 +1516,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
});
|
||||
|
||||
self.explain_why_borrow_contains_point(location, borrow, None)
|
||||
.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
Some(borrow_span),
|
||||
None,
|
||||
);
|
||||
.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);
|
||||
self.suggest_copy_for_type_in_cloned_ref(&mut err, place);
|
||||
let typeck_results = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
if let Some(expr) = self.find_expr(borrow_span) {
|
||||
|
|
@ -1591,15 +1583,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
});
|
||||
|
||||
self.explain_why_borrow_contains_point(location, borrow, None)
|
||||
.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
None,
|
||||
None,
|
||||
);
|
||||
.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
|
||||
err
|
||||
}
|
||||
|
||||
|
|
@ -1886,9 +1870,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
|
||||
explanation.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&self,
|
||||
&mut err,
|
||||
first_borrow_desc,
|
||||
None,
|
||||
|
|
@ -2698,22 +2680,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let mut sugg = vec![];
|
||||
let sm = self.infcx.tcx.sess.source_map();
|
||||
|
||||
if let Some(span) = finder.closure_arg_span {
|
||||
sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
|
||||
}
|
||||
for span in finder.closure_change_spans {
|
||||
sugg.push((span, "this".to_string()));
|
||||
}
|
||||
|
||||
for (span, suggest) in finder.closure_call_changes {
|
||||
sugg.push((span, suggest));
|
||||
}
|
||||
let sugg = finder
|
||||
.closure_arg_span
|
||||
.map(|span| (sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg))
|
||||
.into_iter()
|
||||
.chain(
|
||||
finder.closure_change_spans.into_iter().map(|span| (span, "this".to_string())),
|
||||
)
|
||||
.chain(finder.closure_call_changes)
|
||||
.collect();
|
||||
|
||||
err.multipart_suggestion_verbose(
|
||||
"try explicitly pass `&Self` into the Closure as an argument",
|
||||
"try explicitly passing `&Self` into the closure as an argument",
|
||||
sugg,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
|
|
@ -3046,15 +3025,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
if let BorrowExplanation::MustBeValidFor { .. } = explanation {
|
||||
} else {
|
||||
explanation.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
None,
|
||||
None,
|
||||
);
|
||||
explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
|
||||
}
|
||||
} else {
|
||||
err.span_label(borrow_span, "borrowed value does not live long enough");
|
||||
|
|
@ -3067,15 +3038,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
});
|
||||
|
||||
explanation.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
Some(borrow_span),
|
||||
None,
|
||||
);
|
||||
explanation.add_explanation_to_diagnostic(&self, &mut err, "", Some(borrow_span), None);
|
||||
}
|
||||
|
||||
err
|
||||
|
|
@ -3128,15 +3091,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
explanation.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
None,
|
||||
None,
|
||||
);
|
||||
explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
|
||||
|
||||
self.buffer_error(err);
|
||||
}
|
||||
|
|
@ -3309,15 +3264,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
explanation.add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
None,
|
||||
None,
|
||||
);
|
||||
explanation.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
|
||||
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
|
|
@ -3808,15 +3755,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
});
|
||||
|
||||
self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
&self.local_names,
|
||||
&mut err,
|
||||
"",
|
||||
None,
|
||||
None,
|
||||
);
|
||||
self.explain_why_borrow_contains_point(location, loan, None)
|
||||
.add_explanation_to_diagnostic(&self, &mut err, "", None, None);
|
||||
|
||||
self.explain_deref_coercion(loan, &mut err);
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,9 @@
|
|||
|
||||
use std::assert_matches::assert_matches;
|
||||
|
||||
use rustc_errors::{Applicability, Diag};
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
|
||||
use rustc_middle::mir::{
|
||||
|
|
@ -17,14 +16,16 @@ use rustc_middle::mir::{
|
|||
};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_span::{DesugaringKind, Span, Symbol, kw, sym};
|
||||
use rustc_middle::util::CallKind;
|
||||
use rustc_span::{DesugaringKind, Span, kw, sym};
|
||||
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::{RegionName, UseSpans, find_use};
|
||||
use crate::borrow_set::BorrowData;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::nll::ConstraintDescription;
|
||||
use crate::region_infer::{BlameConstraint, Cause, ExtraConstraintInfo};
|
||||
use crate::region_infer::{BlameConstraint, Cause};
|
||||
use crate::{MirBorrowckCtxt, WriteKind};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -42,7 +43,7 @@ pub(crate) enum BorrowExplanation<'tcx> {
|
|||
span: Span,
|
||||
region_name: RegionName,
|
||||
opt_place_desc: Option<String>,
|
||||
extra_info: Vec<ExtraConstraintInfo>,
|
||||
path: Vec<OutlivesConstraint<'tcx>>,
|
||||
},
|
||||
Unexplained,
|
||||
}
|
||||
|
|
@ -60,16 +61,18 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
pub(crate) fn is_explained(&self) -> bool {
|
||||
!matches!(self, BorrowExplanation::Unexplained)
|
||||
}
|
||||
pub(crate) fn add_explanation_to_diagnostic(
|
||||
pub(crate) fn add_explanation_to_diagnostic<G: EmissionGuarantee>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
local_names: &IndexSlice<Local, Option<Symbol>>,
|
||||
err: &mut Diag<'_>,
|
||||
cx: &MirBorrowckCtxt<'_, '_, 'tcx>,
|
||||
err: &mut Diag<'_, G>,
|
||||
borrow_desc: &str,
|
||||
borrow_span: Option<Span>,
|
||||
multiple_borrow_span: Option<(Span, Span)>,
|
||||
) {
|
||||
let tcx = cx.infcx.tcx;
|
||||
let body = cx.body;
|
||||
let local_names = &cx.local_names;
|
||||
|
||||
if let Some(span) = borrow_span {
|
||||
let def_id = body.source.def_id();
|
||||
if let Some(node) = tcx.hir().get_if_local(def_id)
|
||||
|
|
@ -305,7 +308,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
ref region_name,
|
||||
ref opt_place_desc,
|
||||
from_closure: _,
|
||||
ref extra_info,
|
||||
ref path,
|
||||
} => {
|
||||
region_name.highlight_region_name(err);
|
||||
|
||||
|
|
@ -327,13 +330,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
);
|
||||
};
|
||||
|
||||
for extra in extra_info {
|
||||
match extra {
|
||||
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
|
||||
err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
|
||||
}
|
||||
}
|
||||
}
|
||||
cx.add_placeholder_from_predicate_note(err, &path);
|
||||
cx.add_sized_or_copy_bound_info(err, category, &path);
|
||||
|
||||
if let ConstraintCategory::Cast {
|
||||
is_implicit_coercion: true,
|
||||
|
|
@ -348,10 +346,10 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_object_lifetime_default_note(
|
||||
fn add_object_lifetime_default_note<G: EmissionGuarantee>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: &mut Diag<'_>,
|
||||
err: &mut Diag<'_, G>,
|
||||
unsize_ty: Ty<'tcx>,
|
||||
) {
|
||||
if let ty::Adt(def, args) = unsize_ty.kind() {
|
||||
|
|
@ -405,9 +403,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn add_lifetime_bound_suggestion_to_diagnostic(
|
||||
fn add_lifetime_bound_suggestion_to_diagnostic<G: EmissionGuarantee>(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
err: &mut Diag<'_, G>,
|
||||
category: &ConstraintCategory<'tcx>,
|
||||
span: Span,
|
||||
region_name: &RegionName,
|
||||
|
|
@ -434,14 +432,14 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn suggest_rewrite_if_let(
|
||||
fn suggest_rewrite_if_let<G: EmissionGuarantee>(
|
||||
tcx: TyCtxt<'_>,
|
||||
expr: &hir::Expr<'_>,
|
||||
pat: &str,
|
||||
init: &hir::Expr<'_>,
|
||||
conseq: &hir::Expr<'_>,
|
||||
alt: Option<&hir::Expr<'_>>,
|
||||
err: &mut Diag<'_>,
|
||||
err: &mut Diag<'_, G>,
|
||||
) {
|
||||
let source_map = tcx.sess.source_map();
|
||||
err.span_note(
|
||||
|
|
@ -486,8 +484,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
&self,
|
||||
borrow_region: RegionVid,
|
||||
outlived_region: RegionVid,
|
||||
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
|
||||
let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
|
||||
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<OutlivesConstraint<'tcx>>)
|
||||
{
|
||||
let (blame_constraint, path) = self.regioncx.best_blame_constraint(
|
||||
borrow_region,
|
||||
NllRegionVariableOrigin::FreeRegion,
|
||||
|r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
|
||||
|
|
@ -496,7 +495,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
|
||||
let outlived_fr_name = self.give_region_a_name(outlived_region);
|
||||
|
||||
(category, from_closure, cause.span, outlived_fr_name, extra_info)
|
||||
(category, from_closure, cause.span, outlived_fr_name, path)
|
||||
}
|
||||
|
||||
/// Returns structured explanation for *why* the borrow contains the
|
||||
|
|
@ -595,7 +594,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
|
||||
None => {
|
||||
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
|
||||
let (category, from_closure, span, region_name, extra_info) =
|
||||
let (category, from_closure, span, region_name, path) =
|
||||
self.free_region_constraint_info(borrow_region_vid, region);
|
||||
if let Some(region_name) = region_name {
|
||||
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
|
||||
|
|
@ -605,7 +604,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
span,
|
||||
region_name,
|
||||
opt_place_desc,
|
||||
extra_info,
|
||||
path,
|
||||
}
|
||||
} else {
|
||||
debug!("Could not generate a region name");
|
||||
|
|
@ -635,6 +634,39 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
// Used in a closure.
|
||||
(LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span))
|
||||
}
|
||||
// In the case that the borrowed value (probably a temporary)
|
||||
// overlaps with the method's receiver, then point at the method.
|
||||
UseSpans::FnSelfUse {
|
||||
var_span: span,
|
||||
kind: CallKind::Normal { desugaring: None, .. },
|
||||
..
|
||||
} if span
|
||||
.overlaps(self.body.local_decls[borrow.assigned_place.local].source_info.span) =>
|
||||
{
|
||||
if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } =
|
||||
&self.body.basic_blocks[location.block].terminator().kind
|
||||
{
|
||||
// Just point to the function, to reduce the chance of overlapping spans.
|
||||
let function_span = match func {
|
||||
Operand::Constant(c) => c.span,
|
||||
Operand::Copy(place) | Operand::Move(place) => {
|
||||
if let Some(l) = place.as_local() {
|
||||
let local_decl = &self.body.local_decls[l];
|
||||
if self.local_names[l].is_none() {
|
||||
local_decl.source_info.span
|
||||
} else {
|
||||
span
|
||||
}
|
||||
} else {
|
||||
span
|
||||
}
|
||||
}
|
||||
};
|
||||
(LaterUseKind::Call, function_span, None)
|
||||
} else {
|
||||
(LaterUseKind::Other, span, None)
|
||||
}
|
||||
}
|
||||
UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span)
|
||||
| UseSpans::FnSelfUse { var_span: span, .. } => {
|
||||
|
|
|
|||
|
|
@ -4,18 +4,20 @@ use std::collections::BTreeMap;
|
|||
|
||||
use rustc_abi::{FieldIdx, VariantIdx};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_errors::{Applicability, Diag, MultiSpan};
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan};
|
||||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::BoundRegionConversionTime;
|
||||
use rustc_infer::infer::{
|
||||
BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin,
|
||||
};
|
||||
use rustc_infer::traits::SelectionError;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
|
||||
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||
TerminatorKind,
|
||||
AggregateKind, CallSource, ConstOperand, ConstraintCategory, FakeReadCause, Local, LocalInfo,
|
||||
LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement,
|
||||
StatementKind, Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::print::Print;
|
||||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
|
|
@ -33,7 +35,9 @@ use tracing::debug;
|
|||
|
||||
use super::MirBorrowckCtxt;
|
||||
use super::borrow_set::BorrowData;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::fluent_generated as fluent;
|
||||
use crate::nll::ConstraintDescription;
|
||||
use crate::session_diagnostics::{
|
||||
CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
|
||||
CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
|
||||
|
|
@ -619,6 +623,52 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
region.print(&mut printer).unwrap();
|
||||
printer.into_buffer()
|
||||
}
|
||||
|
||||
/// Add a note to region errors and borrow explanations when higher-ranked regions in predicates
|
||||
/// implicitly introduce an "outlives `'static`" constraint.
|
||||
fn add_placeholder_from_predicate_note<G: EmissionGuarantee>(
|
||||
&self,
|
||||
err: &mut Diag<'_, G>,
|
||||
path: &[OutlivesConstraint<'tcx>],
|
||||
) {
|
||||
let predicate_span = path.iter().find_map(|constraint| {
|
||||
let outlived = constraint.sub;
|
||||
if let Some(origin) = self.regioncx.var_infos.get(outlived)
|
||||
&& let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(_)) =
|
||||
origin.origin
|
||||
&& let ConstraintCategory::Predicate(span) = constraint.category
|
||||
{
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(span) = predicate_span {
|
||||
err.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a label to region errors and borrow explanations when outlives constraints arise from
|
||||
/// proving a type implements `Sized` or `Copy`.
|
||||
fn add_sized_or_copy_bound_info<G: EmissionGuarantee>(
|
||||
&self,
|
||||
err: &mut Diag<'_, G>,
|
||||
blamed_category: ConstraintCategory<'tcx>,
|
||||
path: &[OutlivesConstraint<'tcx>],
|
||||
) {
|
||||
for sought_category in [ConstraintCategory::SizedBound, ConstraintCategory::CopyBound] {
|
||||
if sought_category != blamed_category
|
||||
&& let Some(sought_constraint) = path.iter().find(|c| c.category == sought_category)
|
||||
{
|
||||
let label = format!(
|
||||
"requirement occurs due to {}",
|
||||
sought_category.description().trim_end()
|
||||
);
|
||||
err.span_label(sought_constraint.span, label);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The span(s) associated to a use of a place.
|
||||
|
|
@ -661,9 +711,6 @@ impl UseSpans<'_> {
|
|||
UseSpans::ClosureUse { args_span: span, .. }
|
||||
| UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span) => span,
|
||||
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
|
||||
fn_call_span
|
||||
}
|
||||
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||
}
|
||||
}
|
||||
|
|
@ -674,9 +721,6 @@ impl UseSpans<'_> {
|
|||
UseSpans::ClosureUse { path_span: span, .. }
|
||||
| UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span) => span,
|
||||
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
|
||||
fn_call_span
|
||||
}
|
||||
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||
}
|
||||
}
|
||||
|
|
@ -687,9 +731,6 @@ impl UseSpans<'_> {
|
|||
UseSpans::ClosureUse { capture_kind_span: span, .. }
|
||||
| UseSpans::PatUse(span)
|
||||
| UseSpans::OtherUse(span) => span,
|
||||
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
|
||||
fn_call_span
|
||||
}
|
||||
UseSpans::FnSelfUse { var_span, .. } => var_span,
|
||||
}
|
||||
}
|
||||
|
|
@ -1001,6 +1042,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
kind,
|
||||
};
|
||||
}
|
||||
|
||||
normal_ret
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use rustc_hir::intravisit::Visitor;
|
|||
use rustc_hir::{self as hir, BindingMode, ByRef, Node};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
use rustc_middle::mir::visit::PlaceContext;
|
||||
use rustc_middle::mir::{
|
||||
self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location, Mutability, Place,
|
||||
PlaceRef, ProjectionElem,
|
||||
|
|
@ -22,7 +23,6 @@ use rustc_trait_selection::traits;
|
|||
use tracing::debug;
|
||||
|
||||
use crate::diagnostics::BorrowedContentSource;
|
||||
use crate::util::FindAssignments;
|
||||
use crate::{MirBorrowckCtxt, session_diagnostics};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
|
|
@ -1088,6 +1088,38 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Finds all statements that assign directly to local (i.e., X = ...) and returns their
|
||||
/// locations.
|
||||
fn find_assignments(&self, local: Local) -> Vec<Location> {
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
|
||||
struct FindLocalAssignmentVisitor {
|
||||
needle: Local,
|
||||
locations: Vec<Location>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
|
||||
fn visit_local(
|
||||
&mut self,
|
||||
local: Local,
|
||||
place_context: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
if self.needle != local {
|
||||
return;
|
||||
}
|
||||
|
||||
if place_context.is_place_assignment() {
|
||||
self.locations.push(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
|
||||
visitor.visit_body(self.body);
|
||||
visitor.locations
|
||||
}
|
||||
|
||||
fn suggest_make_local_mut(&self, err: &mut Diag<'_>, local: Local, name: Symbol) {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
|
||||
|
|
@ -1121,7 +1153,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
})) => {
|
||||
// check if the RHS is from desugaring
|
||||
let opt_assignment_rhs_span =
|
||||
self.body.find_assignments(local).first().map(|&location| {
|
||||
self.find_assignments(local).first().map(|&location| {
|
||||
if let Some(mir::Statement {
|
||||
source_info: _,
|
||||
kind:
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate};
|
|||
use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::hir::place::PlaceBase;
|
||||
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
|
||||
use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint};
|
||||
use rustc_middle::ty::{self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeVisitor};
|
||||
use rustc_span::{Ident, Span, kw};
|
||||
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
|
||||
|
|
@ -29,7 +29,7 @@ use tracing::{debug, instrument, trace};
|
|||
use super::{OutlivesSuggestionBuilder, RegionName, RegionNameSource};
|
||||
use crate::nll::ConstraintDescription;
|
||||
use crate::region_infer::values::RegionElement;
|
||||
use crate::region_infer::{BlameConstraint, ExtraConstraintInfo, TypeTest};
|
||||
use crate::region_infer::{BlameConstraint, TypeTest};
|
||||
use crate::session_diagnostics::{
|
||||
FnMutError, FnMutReturnTypeErr, GenericDoesNotLiveLongEnough, LifetimeOutliveErr,
|
||||
LifetimeReturnCategoryErr, RequireStaticErr, VarHereDenote,
|
||||
|
|
@ -49,8 +49,8 @@ impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
|
|||
ConstraintCategory::Cast { is_implicit_coercion: false, .. } => "cast ",
|
||||
ConstraintCategory::Cast { is_implicit_coercion: true, .. } => "coercion ",
|
||||
ConstraintCategory::CallArgument(_) => "argument ",
|
||||
ConstraintCategory::TypeAnnotation => "type annotation ",
|
||||
ConstraintCategory::ClosureBounds => "closure body ",
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => "generic argument ",
|
||||
ConstraintCategory::TypeAnnotation(_) => "type annotation ",
|
||||
ConstraintCategory::SizedBound => "proving this value is `Sized` ",
|
||||
ConstraintCategory::CopyBound => "copying this value ",
|
||||
ConstraintCategory::OpaqueType => "opaque type ",
|
||||
|
|
@ -440,10 +440,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
) {
|
||||
debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
|
||||
|
||||
let (blame_constraint, extra_info) =
|
||||
self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
|
||||
self.regioncx.provides_universal_region(r, fr, outlived_fr)
|
||||
});
|
||||
let (blame_constraint, path) = self.regioncx.best_blame_constraint(fr, fr_origin, |r| {
|
||||
self.regioncx.provides_universal_region(r, fr, outlived_fr)
|
||||
});
|
||||
let BlameConstraint { category, cause, variance_info, .. } = blame_constraint;
|
||||
|
||||
debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
|
||||
|
|
@ -554,13 +553,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
for extra in extra_info {
|
||||
match extra {
|
||||
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
|
||||
diag.span_note(span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
|
||||
}
|
||||
}
|
||||
}
|
||||
self.add_placeholder_from_predicate_note(&mut diag, &path);
|
||||
self.add_sized_or_copy_bound_info(&mut diag, category, &path);
|
||||
|
||||
self.buffer_error(diag);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use std::fmt::{self, Display};
|
|||
use std::iter;
|
||||
|
||||
use rustc_data_structures::fx::IndexEntry;
|
||||
use rustc_errors::Diag;
|
||||
use rustc_errors::{Diag, EmissionGuarantee};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_middle::ty::print::RegionHighlightMode;
|
||||
|
|
@ -108,7 +108,7 @@ impl RegionName {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn highlight_region_name(&self, diag: &mut Diag<'_>) {
|
||||
pub(crate) fn highlight_region_name<G: EmissionGuarantee>(&self, diag: &mut Diag<'_, G>) {
|
||||
match &self.source {
|
||||
RegionNameSource::NamedLateParamRegion(span)
|
||||
| RegionNameSource::NamedEarlyParamRegion(span) => {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
|
@ -15,16 +16,19 @@
|
|||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_errors::LintDiagnostic;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{BitSet, MixedBitSet};
|
||||
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
|
||||
|
|
@ -42,7 +46,7 @@ use rustc_mir_dataflow::move_paths::{
|
|||
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::UNUSED_MUT;
|
||||
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
use tracing::{debug, instrument};
|
||||
|
|
@ -56,7 +60,7 @@ use crate::diagnostics::{
|
|||
use crate::path_utils::*;
|
||||
use crate::place_ext::PlaceExt;
|
||||
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
||||
use crate::polonius::legacy::{LocationTable, PoloniusOutput};
|
||||
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
|
||||
use crate::prefixes::PrefixSet;
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
|
@ -81,7 +85,6 @@ mod session_diagnostics;
|
|||
mod type_check;
|
||||
mod universal_regions;
|
||||
mod used_muts;
|
||||
mod util;
|
||||
|
||||
/// A public API provided for the Rust compiler consumers.
|
||||
pub mod consumers;
|
||||
|
|
@ -176,7 +179,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
infcx.register_predefined_opaques_for_next_solver(def);
|
||||
}
|
||||
|
||||
let location_table = LocationTable::new(body);
|
||||
let location_table = PoloniusLocationTable::new(body);
|
||||
|
||||
let move_data = MoveData::gather_moves(body, tcx, |_| true);
|
||||
let promoted_move_data = promoted
|
||||
|
|
@ -247,7 +250,8 @@ fn do_mir_borrowck<'tcx>(
|
|||
infcx: &infcx,
|
||||
body: promoted_body,
|
||||
move_data: &move_data,
|
||||
location_table: &location_table, // no need to create a real one for the promoted, it is not used
|
||||
// no need to create a real location table for the promoted, it is not used
|
||||
location_table: &location_table,
|
||||
movable_coroutine,
|
||||
fn_self_span_reported: Default::default(),
|
||||
locals_are_invalidated_at_exit,
|
||||
|
|
@ -513,7 +517,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
|
||||
/// Map from MIR `Location` to `LocationIndex`; created
|
||||
/// when MIR borrowck begins.
|
||||
location_table: &'a LocationTable,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
|
||||
movable_coroutine: bool,
|
||||
/// This keeps track of whether local variables are free-ed when the function
|
||||
|
|
@ -636,9 +640,11 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
| StatementKind::Coverage(..)
|
||||
// These do not actually affect borrowck
|
||||
| StatementKind::ConstEvalCounter
|
||||
// This do not affect borrowck
|
||||
| StatementKind::BackwardIncompatibleDropHint { .. }
|
||||
| StatementKind::StorageLive(..) => {}
|
||||
// This does not affect borrowck
|
||||
StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => {
|
||||
self.check_backward_incompatible_drop(location, (**place, span), state);
|
||||
}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.access_place(
|
||||
location,
|
||||
|
|
@ -1007,6 +1013,24 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn borrows_in_scope<'s>(
|
||||
&self,
|
||||
location: Location,
|
||||
state: &'s BorrowckDomain,
|
||||
) -> Cow<'s, DenseBitSet<BorrowIndex>> {
|
||||
if let Some(polonius) = &self.polonius_output {
|
||||
// Use polonius output if it has been enabled.
|
||||
let location = self.location_table.start_index(location);
|
||||
let mut polonius_output = DenseBitSet::new_empty(self.borrow_set.len());
|
||||
for &idx in polonius.errors_at(location) {
|
||||
polonius_output.insert(idx);
|
||||
}
|
||||
Cow::Owned(polonius_output)
|
||||
} else {
|
||||
Cow::Borrowed(&state.borrows)
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, state))]
|
||||
fn check_access_for_conflict(
|
||||
&mut self,
|
||||
|
|
@ -1018,18 +1042,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
) -> bool {
|
||||
let mut error_reported = false;
|
||||
|
||||
// Use polonius output if it has been enabled.
|
||||
let mut polonius_output;
|
||||
let borrows_in_scope = if let Some(polonius) = &self.polonius_output {
|
||||
let location = self.location_table.start_index(location);
|
||||
polonius_output = BitSet::new_empty(self.borrow_set.len());
|
||||
for &idx in polonius.errors_at(location) {
|
||||
polonius_output.insert(idx);
|
||||
}
|
||||
&polonius_output
|
||||
} else {
|
||||
&state.borrows
|
||||
};
|
||||
let borrows_in_scope = self.borrows_in_scope(location, state);
|
||||
|
||||
each_borrow_involving_path(
|
||||
self,
|
||||
|
|
@ -1054,31 +1067,31 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
rw,
|
||||
(borrow_index, borrow),
|
||||
);
|
||||
Control::Continue
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
(Read(_), BorrowKind::Shared | BorrowKind::Fake(_))
|
||||
| (
|
||||
Read(ReadKind::Borrow(BorrowKind::Fake(FakeBorrowKind::Shallow))),
|
||||
BorrowKind::Mut { .. },
|
||||
) => Control::Continue,
|
||||
) => ControlFlow::Continue(()),
|
||||
|
||||
(Reservation(_), BorrowKind::Fake(_) | BorrowKind::Shared) => {
|
||||
// This used to be a future compatibility warning (to be
|
||||
// disallowed on NLL). See rust-lang/rust#56254
|
||||
Control::Continue
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
(Write(WriteKind::Move), BorrowKind::Fake(FakeBorrowKind::Shallow)) => {
|
||||
// Handled by initialization checks.
|
||||
Control::Continue
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
|
||||
(Read(kind), BorrowKind::Mut { .. }) => {
|
||||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(this.dominators(), borrow, location) {
|
||||
assert!(allow_two_phase_borrow(borrow.kind));
|
||||
return Control::Continue;
|
||||
assert!(borrow.kind.allows_two_phase_borrow());
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
error_reported = true;
|
||||
|
|
@ -1094,7 +1107,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
this.buffer_error(err);
|
||||
}
|
||||
}
|
||||
Control::Break
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
|
||||
(Reservation(kind) | Activation(kind, _) | Write(kind), _) => {
|
||||
|
|
@ -1141,7 +1154,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
|
||||
}
|
||||
}
|
||||
Control::Break
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
@ -1149,6 +1162,61 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
error_reported
|
||||
}
|
||||
|
||||
/// Through #123739, backward incompatible drops (BIDs) are introduced.
|
||||
/// We would like to emit lints whether borrow checking fails at these future drop locations.
|
||||
#[instrument(level = "debug", skip(self, state))]
|
||||
fn check_backward_incompatible_drop(
|
||||
&mut self,
|
||||
location: Location,
|
||||
(place, place_span): (Place<'tcx>, Span),
|
||||
state: &BorrowckDomain,
|
||||
) {
|
||||
let tcx = self.infcx.tcx;
|
||||
// If this type does not need `Drop`, then treat it like a `StorageDead`.
|
||||
// This is needed because we track the borrows of refs to thread locals,
|
||||
// and we'll ICE because we don't track borrows behind shared references.
|
||||
let sd = if place.ty(self.body, tcx).ty.needs_drop(tcx, self.body.typing_env(tcx)) {
|
||||
AccessDepth::Drop
|
||||
} else {
|
||||
AccessDepth::Shallow(None)
|
||||
};
|
||||
|
||||
let borrows_in_scope = self.borrows_in_scope(location, state);
|
||||
|
||||
// This is a very simplified version of `Self::check_access_for_conflict`.
|
||||
// We are here checking on BIDs and specifically still-live borrows of data involving the BIDs.
|
||||
each_borrow_involving_path(
|
||||
self,
|
||||
self.infcx.tcx,
|
||||
self.body,
|
||||
(sd, place),
|
||||
self.borrow_set,
|
||||
|borrow_index| borrows_in_scope.contains(borrow_index),
|
||||
|this, _borrow_index, borrow| {
|
||||
if matches!(borrow.kind, BorrowKind::Fake(_)) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
let borrowed = this.retrieve_borrow_spans(borrow).var_or_use_path_span();
|
||||
let explain = this.explain_why_borrow_contains_point(
|
||||
location,
|
||||
borrow,
|
||||
Some((WriteKind::StorageDeadOrDrop, place)),
|
||||
);
|
||||
this.infcx.tcx.node_span_lint(
|
||||
TAIL_EXPR_DROP_ORDER,
|
||||
CRATE_HIR_ID,
|
||||
borrowed,
|
||||
|diag| {
|
||||
session_diagnostics::TailExprDropOrder { borrowed }.decorate_lint(diag);
|
||||
explain.add_explanation_to_diagnostic(&this, diag, "", None, None);
|
||||
},
|
||||
);
|
||||
// We may stop at the first case
|
||||
ControlFlow::Break(())
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn mutate_place(
|
||||
&mut self,
|
||||
location: Location,
|
||||
|
|
@ -1185,7 +1253,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if allow_two_phase_borrow(bk) {
|
||||
if bk.allows_two_phase_borrow() {
|
||||
(Deep, Reservation(wk))
|
||||
} else {
|
||||
(Deep, Write(wk))
|
||||
|
|
|
|||
|
|
@ -28,7 +28,9 @@ use crate::borrow_set::BorrowSet;
|
|||
use crate::consumers::ConsumerOptions;
|
||||
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
|
||||
use crate::polonius::LocalizedOutlivesConstraintSet;
|
||||
use crate::polonius::legacy::{AllFacts, AllFactsExt, LocationTable, PoloniusOutput};
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
};
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::type_check::{self, MirTypeckResults};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
|
@ -39,7 +41,7 @@ use crate::{BorrowckInferCtxt, polonius, renumber};
|
|||
pub(crate) struct NllOutput<'tcx> {
|
||||
pub regioncx: RegionInferenceContext<'tcx>,
|
||||
pub opaque_type_values: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
pub polonius_input: Option<Box<AllFacts>>,
|
||||
pub polonius_input: Option<Box<PoloniusFacts>>,
|
||||
pub polonius_output: Option<Box<PoloniusOutput>>,
|
||||
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
||||
pub nll_errors: RegionErrors<'tcx>,
|
||||
|
|
@ -80,7 +82,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
universal_regions: UniversalRegions<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
|
|
@ -91,10 +93,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
|| is_polonius_legacy_enabled;
|
||||
let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
|
||||
|| is_polonius_legacy_enabled;
|
||||
let mut all_facts =
|
||||
(polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
|
||||
let mut polonius_facts =
|
||||
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
|
||||
|
||||
let elements = Rc::new(DenseLocationMap::new(body));
|
||||
let location_map = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults {
|
||||
|
|
@ -109,10 +111,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
&mut all_facts,
|
||||
&mut polonius_facts,
|
||||
flow_inits,
|
||||
move_data,
|
||||
Rc::clone(&elements),
|
||||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
// Create the region inference context, taking ownership of the
|
||||
|
|
@ -122,7 +124,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
|
||||
// If requested, emit legacy polonius facts.
|
||||
polonius::legacy::emit_facts(
|
||||
&mut all_facts,
|
||||
&mut polonius_facts,
|
||||
infcx.tcx,
|
||||
location_table,
|
||||
body,
|
||||
|
|
@ -137,23 +139,23 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
var_infos,
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
elements,
|
||||
location_map,
|
||||
);
|
||||
|
||||
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives
|
||||
// constraints.
|
||||
let localized_outlives_constraints = polonius_context
|
||||
.as_mut()
|
||||
.map(|polonius_context| polonius_context.create_localized_constraints(&mut regioncx, body));
|
||||
let localized_outlives_constraints = polonius_context.as_mut().map(|polonius_context| {
|
||||
polonius_context.create_localized_constraints(infcx.tcx, ®ioncx, body)
|
||||
});
|
||||
|
||||
// If requested: dump NLL facts, and run legacy polonius analysis.
|
||||
let polonius_output = all_facts.as_ref().and_then(|all_facts| {
|
||||
let polonius_output = polonius_facts.as_ref().and_then(|polonius_facts| {
|
||||
if infcx.tcx.sess.opts.unstable_opts.nll_facts {
|
||||
let def_id = body.source.def_id();
|
||||
let def_path = infcx.tcx.def_path(def_id);
|
||||
let dir_path = PathBuf::from(&infcx.tcx.sess.opts.unstable_opts.nll_facts_dir)
|
||||
.join(def_path.to_filename_friendly_no_crate());
|
||||
all_facts.write_to_dir(dir_path, location_table).unwrap();
|
||||
polonius_facts.write_to_dir(dir_path, location_table).unwrap();
|
||||
}
|
||||
|
||||
if polonius_output {
|
||||
|
|
@ -162,7 +164,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
let algorithm = Algorithm::from_str(&algorithm).unwrap();
|
||||
debug!("compute_regions: using polonius algorithm {:?}", algorithm);
|
||||
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_analysis");
|
||||
Some(Box::new(Output::compute(all_facts, algorithm, false)))
|
||||
Some(Box::new(Output::compute(polonius_facts, algorithm, false)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -182,7 +184,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
NllOutput {
|
||||
regioncx,
|
||||
opaque_type_values: remapped_opaque_tys,
|
||||
polonius_input: all_facts.map(Box::new),
|
||||
polonius_input: polonius_facts.map(Box::new),
|
||||
polonius_output,
|
||||
opt_closure_req: closure_region_requirements,
|
||||
nll_errors,
|
||||
|
|
|
|||
|
|
@ -1,26 +1,14 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_middle::mir::{BasicBlock, Body, BorrowKind, Location, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
|
||||
use crate::{AccessDepth, BorrowIndex, places_conflict};
|
||||
|
||||
/// Returns `true` if the borrow represented by `kind` is
|
||||
/// allowed to be split into separate Reservation and
|
||||
/// Activation phases.
|
||||
pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool {
|
||||
kind.allows_two_phase_borrow()
|
||||
}
|
||||
|
||||
/// Control for the path borrow checking code
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub(super) enum Control {
|
||||
Continue,
|
||||
Break,
|
||||
}
|
||||
|
||||
/// Encapsulates the idea of iterating over every borrow that involves a particular path
|
||||
pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
||||
s: &mut S,
|
||||
|
|
@ -31,7 +19,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
|||
is_candidate: I,
|
||||
mut op: F,
|
||||
) where
|
||||
F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
|
||||
F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> ControlFlow<()>,
|
||||
I: Fn(BorrowIndex) -> bool,
|
||||
{
|
||||
let (access, place) = access_place;
|
||||
|
|
@ -62,7 +50,7 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
|||
i, borrowed, place, access
|
||||
);
|
||||
let ctrl = op(s, i, borrowed);
|
||||
if ctrl == Control::Break {
|
||||
if matches!(ctrl, ControlFlow::Break(_)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,16 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_mir_dataflow::move_paths::{LookupResult, MoveData};
|
||||
use tracing::debug;
|
||||
|
||||
use super::{AllFacts, LocationIndex, LocationTable};
|
||||
use super::{LocationIndex, PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::def_use::{self, DefUse};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
/// Emit polonius facts for variable defs, uses, drops, and path accesses.
|
||||
pub(crate) fn emit_access_facts<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
move_data: &MoveData<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) {
|
||||
|
|
@ -31,9 +31,9 @@ pub(crate) fn emit_access_facts<'tcx>(
|
|||
|
||||
/// MIR visitor extracting point-wise facts about accesses.
|
||||
struct AccessFactsExtractor<'a, 'tcx> {
|
||||
facts: &'a mut AllFacts,
|
||||
facts: &'a mut PoloniusFacts,
|
||||
move_data: &'a MoveData<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
}
|
||||
|
||||
impl<'tcx> AccessFactsExtractor<'_, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ use std::fs::{self, File};
|
|||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use polonius_engine::{AllFacts as PoloniusFacts, Atom, Output};
|
||||
use polonius_engine::{AllFacts, Atom, Output};
|
||||
use rustc_macros::extension;
|
||||
use rustc_middle::mir::Local;
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::move_paths::MovePathIndex;
|
||||
|
||||
use super::{LocationIndex, LocationTable};
|
||||
use super::{LocationIndex, PoloniusLocationTable};
|
||||
use crate::BorrowIndex;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
|
@ -49,11 +49,11 @@ impl polonius_engine::FactTypes for RustcFacts {
|
|||
type Path = MovePathIndex;
|
||||
}
|
||||
|
||||
pub type AllFacts = PoloniusFacts<RustcFacts>;
|
||||
pub type PoloniusFacts = AllFacts<RustcFacts>;
|
||||
|
||||
#[extension(pub(crate) trait AllFactsExt)]
|
||||
impl AllFacts {
|
||||
/// Returns `true` if there is a need to gather `AllFacts` given the
|
||||
#[extension(pub(crate) trait PoloniusFactsExt)]
|
||||
impl PoloniusFacts {
|
||||
/// Returns `true` if there is a need to gather `PoloniusFacts` given the
|
||||
/// current `-Z` flags.
|
||||
fn enabled(tcx: TyCtxt<'_>) -> bool {
|
||||
tcx.sess.opts.unstable_opts.nll_facts
|
||||
|
|
@ -63,7 +63,7 @@ impl AllFacts {
|
|||
fn write_to_dir(
|
||||
&self,
|
||||
dir: impl AsRef<Path>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let dir: &Path = dir.as_ref();
|
||||
fs::create_dir_all(dir)?;
|
||||
|
|
@ -119,7 +119,7 @@ impl Atom for LocationIndex {
|
|||
}
|
||||
|
||||
struct FactWriter<'w> {
|
||||
location_table: &'w LocationTable,
|
||||
location_table: &'w PoloniusLocationTable,
|
||||
dir: &'w Path,
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ trait FactRow {
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +149,7 @@ impl FactRow for PoloniusRegionVid {
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[self])
|
||||
}
|
||||
|
|
@ -163,7 +163,7 @@ where
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1])
|
||||
}
|
||||
|
|
@ -178,7 +178,7 @@ where
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2])
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ where
|
|||
fn write(
|
||||
&self,
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
|
||||
}
|
||||
|
|
@ -202,7 +202,7 @@ where
|
|||
|
||||
fn write_row(
|
||||
out: &mut dyn Write,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
columns: &[&dyn FactCell],
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
for (index, c) in columns.iter().enumerate() {
|
||||
|
|
@ -213,41 +213,41 @@ fn write_row(
|
|||
}
|
||||
|
||||
trait FactCell {
|
||||
fn to_string(&self, location_table: &LocationTable) -> String;
|
||||
fn to_string(&self, location_table: &PoloniusLocationTable) -> String;
|
||||
}
|
||||
|
||||
impl FactCell for BorrowIndex {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for Local {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for MovePathIndex {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for PoloniusRegionVid {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for RegionVid {
|
||||
fn to_string(&self, _location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{self:?}")
|
||||
}
|
||||
}
|
||||
|
||||
impl FactCell for LocationIndex {
|
||||
fn to_string(&self, location_table: &LocationTable) -> String {
|
||||
fn to_string(&self, location_table: &PoloniusLocationTable) -> String {
|
||||
format!("{:?}", location_table.to_rich_location(*self))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::ops::ControlFlow;
|
||||
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
|
|
@ -9,7 +11,7 @@ use rustc_middle::mir::{
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
use super::{AllFacts, LocationTable};
|
||||
use super::{PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::path_utils::*;
|
||||
use crate::{
|
||||
|
|
@ -20,9 +22,9 @@ use crate::{
|
|||
/// Emit `loan_invalidated_at` facts.
|
||||
pub(super) fn emit_loan_invalidations<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) {
|
||||
let dominators = body.basic_blocks.dominators();
|
||||
|
|
@ -33,9 +35,9 @@ pub(super) fn emit_loan_invalidations<'tcx>(
|
|||
|
||||
struct LoanInvalidationsGenerator<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &'a mut AllFacts,
|
||||
facts: &'a mut PoloniusFacts,
|
||||
body: &'a Body<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
dominators: &'a Dominators<BasicBlock>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
}
|
||||
|
|
@ -260,7 +262,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
}
|
||||
BorrowKind::Mut { .. } => {
|
||||
let wk = WriteKind::MutableBorrow(bk);
|
||||
if allow_two_phase_borrow(bk) {
|
||||
if bk.allows_two_phase_borrow() {
|
||||
(Deep, Reservation(wk))
|
||||
} else {
|
||||
(Deep, Write(wk))
|
||||
|
|
@ -378,8 +380,8 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
// Reading from mere reservations of mutable-borrows is OK.
|
||||
if !is_active(this.dominators, borrow, location) {
|
||||
// If the borrow isn't active yet, reads don't invalidate it
|
||||
assert!(allow_two_phase_borrow(borrow.kind));
|
||||
return Control::Continue;
|
||||
assert!(borrow.kind.allows_two_phase_borrow());
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
// Unique and mutable borrows are invalidated by reads from any
|
||||
|
|
@ -395,7 +397,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
|
|||
this.emit_loan_invalidated_at(borrow_index, location);
|
||||
}
|
||||
}
|
||||
Control::Continue
|
||||
ControlFlow::Continue(())
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,16 @@ use rustc_middle::mir::{
|
|||
use rustc_middle::ty::TyCtxt;
|
||||
use tracing::debug;
|
||||
|
||||
use super::{AllFacts, LocationTable};
|
||||
use super::{PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::places_conflict;
|
||||
|
||||
/// Emit `loan_killed_at` and `cfg_edge` facts at the same time.
|
||||
pub(super) fn emit_loan_kills<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) {
|
||||
let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body };
|
||||
|
|
@ -26,8 +26,8 @@ pub(super) fn emit_loan_kills<'tcx>(
|
|||
|
||||
struct LoanKillsGenerator<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
facts: &'a mut AllFacts,
|
||||
location_table: &'a LocationTable,
|
||||
facts: &'a mut PoloniusFacts,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use tracing::debug;
|
|||
/// granularity through outlives relations; however, the rich location
|
||||
/// table serves another purpose: it compresses locations from
|
||||
/// multiple words into a single u32.
|
||||
pub struct LocationTable {
|
||||
pub struct PoloniusLocationTable {
|
||||
num_points: usize,
|
||||
statements_before_block: IndexVec<BasicBlock, usize>,
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ pub enum RichLocation {
|
|||
Mid(Location),
|
||||
}
|
||||
|
||||
impl LocationTable {
|
||||
impl PoloniusLocationTable {
|
||||
pub(crate) fn new(body: &Body<'_>) -> Self {
|
||||
let mut num_points = 0;
|
||||
let statements_before_block = body
|
||||
|
|
@ -43,8 +43,8 @@ impl LocationTable {
|
|||
})
|
||||
.collect();
|
||||
|
||||
debug!("LocationTable(statements_before_block={:#?})", statements_before_block);
|
||||
debug!("LocationTable: num_points={:#?}", num_points);
|
||||
debug!("PoloniusLocationTable(statements_before_block={:#?})", statements_before_block);
|
||||
debug!("PoloniusLocationTable: num_points={:#?}", num_points);
|
||||
|
||||
Self { num_points, statements_before_block }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,16 +36,16 @@ pub use self::facts::*;
|
|||
///
|
||||
/// The rest of the facts are emitted during typeck and liveness.
|
||||
pub(crate) fn emit_facts<'tcx>(
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
facts: &mut Option<PoloniusFacts>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
body: &Body<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
universal_region_relations: &UniversalRegionRelations<'tcx>,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
) {
|
||||
let Some(facts) = all_facts else {
|
||||
let Some(facts) = facts else {
|
||||
// We don't do anything if there are no facts to fill.
|
||||
return;
|
||||
};
|
||||
|
|
@ -67,9 +67,9 @@ pub(crate) fn emit_facts<'tcx>(
|
|||
|
||||
/// Emit facts needed for move/init analysis: moves and assignments.
|
||||
fn emit_move_facts(
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
body: &Body<'_>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
move_data: &MoveData<'_>,
|
||||
) {
|
||||
facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
|
||||
|
|
@ -139,7 +139,7 @@ fn emit_move_facts(
|
|||
|
||||
/// Emit universal regions facts, and their relations.
|
||||
fn emit_universal_region_facts(
|
||||
facts: &mut AllFacts,
|
||||
facts: &mut PoloniusFacts,
|
||||
borrow_set: &BorrowSet<'_>,
|
||||
universal_region_relations: &UniversalRegionRelations<'_>,
|
||||
) {
|
||||
|
|
@ -187,10 +187,10 @@ pub(crate) fn emit_drop_facts<'tcx>(
|
|||
local: Local,
|
||||
kind: &GenericArg<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
facts: &mut Option<PoloniusFacts>,
|
||||
) {
|
||||
debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
|
||||
let Some(facts) = all_facts.as_mut() else { return };
|
||||
let Some(facts) = facts.as_mut() else { return };
|
||||
let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
|
||||
tcx.for_each_free_region(kind, |drop_live_region| {
|
||||
let region_vid = universal_regions.to_region_vid(drop_live_region);
|
||||
|
|
@ -201,8 +201,8 @@ pub(crate) fn emit_drop_facts<'tcx>(
|
|||
/// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive
|
||||
/// closure.
|
||||
fn emit_outlives_facts<'tcx>(
|
||||
facts: &mut AllFacts,
|
||||
location_table: &LocationTable,
|
||||
facts: &mut PoloniusFacts,
|
||||
location_table: &PoloniusLocationTable,
|
||||
constraints: &MirTypeckRegionConstraints<'tcx>,
|
||||
) {
|
||||
facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(
|
||||
|
|
|
|||
|
|
@ -37,21 +37,20 @@ mod constraints;
|
|||
mod dump;
|
||||
pub(crate) mod legacy;
|
||||
mod liveness_constraints;
|
||||
mod typeck_constraints;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use rustc_index::bit_set::SparseBitMatrix;
|
||||
use rustc_middle::mir::{Body, Location};
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use rustc_middle::mir::Body;
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
|
||||
pub(crate) use self::constraints::*;
|
||||
pub(crate) use self::dump::dump_polonius_mir;
|
||||
use self::liveness_constraints::create_liveness_constraints;
|
||||
use self::typeck_constraints::convert_typeck_constraints;
|
||||
use crate::RegionInferenceContext;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
|
||||
/// This struct holds the data needed to create the Polonius localized constraints.
|
||||
pub(crate) struct PoloniusContext {
|
||||
|
|
@ -88,14 +87,17 @@ impl PoloniusContext {
|
|||
/// - encoding liveness constraints
|
||||
pub(crate) fn create_localized_constraints<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
) -> LocalizedOutlivesConstraintSet {
|
||||
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
|
||||
convert_typeck_constraints(
|
||||
tcx,
|
||||
body,
|
||||
regioncx.liveness_constraints(),
|
||||
regioncx.outlives_constraints(),
|
||||
regioncx.universal_regions(),
|
||||
&mut localized_outlives_constraints,
|
||||
);
|
||||
|
||||
|
|
@ -117,38 +119,3 @@ impl PoloniusContext {
|
|||
localized_outlives_constraints
|
||||
}
|
||||
}
|
||||
|
||||
/// Propagate loans throughout the subset graph at a given point (with some subtleties around the
|
||||
/// location where effects start to be visible).
|
||||
fn convert_typeck_constraints<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
|
||||
) {
|
||||
for outlives_constraint in outlives_constraints {
|
||||
match outlives_constraint.locations {
|
||||
Locations::All(_) => {
|
||||
// For now, turn logical constraints holding at all points into physical edges at
|
||||
// every point in the graph.
|
||||
// FIXME: encode this into *traversal* instead.
|
||||
for (block, bb) in body.basic_blocks.iter_enumerated() {
|
||||
let statement_count = bb.statements.len();
|
||||
for statement_index in 0..=statement_count {
|
||||
let current_location = Location { block, statement_index };
|
||||
let current_point = liveness.point_from_location(current_location);
|
||||
|
||||
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
241
compiler/rustc_borrowck/src/polonius/typeck_constraints.rs
Normal file
241
compiler/rustc_borrowck/src/polonius/typeck_constraints.rs
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_middle::mir::{Body, Location, Statement, StatementKind, Terminator, TerminatorKind};
|
||||
use rustc_middle::ty::{TyCtxt, TypeVisitable};
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
|
||||
use super::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
|
||||
/// Propagate loans throughout the subset graph at a given point (with some subtleties around the
|
||||
/// location where effects start to be visible).
|
||||
pub(super) fn convert_typeck_constraints<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
localized_outlives_constraints: &mut LocalizedOutlivesConstraintSet,
|
||||
) {
|
||||
for outlives_constraint in outlives_constraints {
|
||||
match outlives_constraint.locations {
|
||||
Locations::All(_) => {
|
||||
// For now, turn logical constraints holding at all points into physical edges at
|
||||
// every point in the graph.
|
||||
// FIXME: encode this into *traversal* instead.
|
||||
for (block, bb) in body.basic_blocks.iter_enumerated() {
|
||||
let statement_count = bb.statements.len();
|
||||
for statement_index in 0..=statement_count {
|
||||
let current_location = Location { block, statement_index };
|
||||
let current_point = liveness.point_from_location(current_location);
|
||||
|
||||
localized_outlives_constraints.push(LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Locations::Single(location) => {
|
||||
// This constraint is marked as holding at one location, we localize it to that
|
||||
// location or its successor, depending on the corresponding MIR
|
||||
// statement/terminator. Unfortunately, they all show up from typeck as coming "on
|
||||
// entry", so for now we modify them to take effects that should apply "on exit"
|
||||
// into account.
|
||||
//
|
||||
// FIXME: this approach is subtle, complicated, and hard to test, so we should track
|
||||
// this information better in MIR typeck instead, for example with a new `Locations`
|
||||
// variant that contains which node is crossing over between entry and exit.
|
||||
let point = liveness.point_from_location(location);
|
||||
let localized_constraint = if let Some(stmt) =
|
||||
body[location.block].statements.get(location.statement_index)
|
||||
{
|
||||
localize_statement_constraint(
|
||||
tcx,
|
||||
body,
|
||||
stmt,
|
||||
liveness,
|
||||
&outlives_constraint,
|
||||
location,
|
||||
point,
|
||||
universal_regions,
|
||||
)
|
||||
} else {
|
||||
assert_eq!(location.statement_index, body[location.block].statements.len());
|
||||
let terminator = body[location.block].terminator();
|
||||
localize_terminator_constraint(
|
||||
tcx,
|
||||
body,
|
||||
terminator,
|
||||
liveness,
|
||||
&outlives_constraint,
|
||||
point,
|
||||
universal_regions,
|
||||
)
|
||||
};
|
||||
localized_outlives_constraints.push(localized_constraint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// For a given outlives constraint arising from a MIR statement, localize the constraint with the
|
||||
/// needed CFG `from`-`to` intra-block nodes.
|
||||
fn localize_statement_constraint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
stmt: &Statement<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||
current_location: Location,
|
||||
current_point: PointIndex,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> LocalizedOutlivesConstraint {
|
||||
match &stmt.kind {
|
||||
StatementKind::Assign(box (lhs, rhs)) => {
|
||||
// To create localized outlives constraints without midpoints, we rely on the property
|
||||
// that no input regions from the RHS of the assignment will flow into themselves: they
|
||||
// should not appear in the output regions in the LHS. We believe this to be true by
|
||||
// construction of the MIR, via temporaries, and assert it here.
|
||||
//
|
||||
// We think we don't need midpoints because:
|
||||
// - every LHS Place has a unique set of regions that don't appear elsewhere
|
||||
// - this implies that for them to be part of the RHS, the same Place must be read and
|
||||
// written
|
||||
// - and that should be impossible in MIR
|
||||
//
|
||||
// When we have a more complete implementation in the future, tested with crater, etc,
|
||||
// we can relax this to a debug assert instead, or remove it.
|
||||
assert!(
|
||||
{
|
||||
let mut lhs_regions = FxHashSet::default();
|
||||
tcx.for_each_free_region(lhs, |region| {
|
||||
let region = universal_regions.to_region_vid(region);
|
||||
lhs_regions.insert(region);
|
||||
});
|
||||
|
||||
let mut rhs_regions = FxHashSet::default();
|
||||
tcx.for_each_free_region(rhs, |region| {
|
||||
let region = universal_regions.to_region_vid(region);
|
||||
rhs_regions.insert(region);
|
||||
});
|
||||
|
||||
// The intersection between LHS and RHS regions should be empty.
|
||||
lhs_regions.is_disjoint(&rhs_regions)
|
||||
},
|
||||
"there should be no common regions between the LHS and RHS of an assignment"
|
||||
);
|
||||
|
||||
// As mentioned earlier, we should be tracking these better upstream but: we want to
|
||||
// relate the types on entry to the type of the place on exit. That is, outlives
|
||||
// constraints on the RHS are on entry, and outlives constraints to/from the LHS are on
|
||||
// exit (i.e. on entry to the successor location).
|
||||
let lhs_ty = body.local_decls[lhs.local].ty;
|
||||
let successor_location = Location {
|
||||
block: current_location.block,
|
||||
statement_index: current_location.statement_index + 1,
|
||||
};
|
||||
let successor_point = liveness.point_from_location(successor_location);
|
||||
compute_constraint_direction(
|
||||
tcx,
|
||||
outlives_constraint,
|
||||
&lhs_ty,
|
||||
current_point,
|
||||
successor_point,
|
||||
universal_regions,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// For the other cases, we localize an outlives constraint to where it arises.
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
|
||||
/// needed CFG `from`-`to` inter-block nodes.
|
||||
fn localize_terminator_constraint<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
terminator: &Terminator<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||
current_point: PointIndex,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> LocalizedOutlivesConstraint {
|
||||
// FIXME: check if other terminators need the same handling as `Call`s, in particular
|
||||
// Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some
|
||||
// coroutine tests, and that may be why.
|
||||
match &terminator.kind {
|
||||
// FIXME: also handle diverging calls.
|
||||
TerminatorKind::Call { destination, target: Some(target), .. } => {
|
||||
// Calls are similar to assignments, and thus follow the same pattern. If there is a
|
||||
// target for the call we also relate what flows into the destination here to entry to
|
||||
// that successor.
|
||||
let destination_ty = destination.ty(&body.local_decls, tcx);
|
||||
let successor_location = Location { block: *target, statement_index: 0 };
|
||||
let successor_point = liveness.point_from_location(successor_location);
|
||||
compute_constraint_direction(
|
||||
tcx,
|
||||
outlives_constraint,
|
||||
&destination_ty,
|
||||
current_point,
|
||||
successor_point,
|
||||
universal_regions,
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
// Typeck constraints guide loans between regions at the current point, so we do that in
|
||||
// the general case, and liveness will take care of making them flow to the terminator's
|
||||
// successors.
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from: current_point,
|
||||
target: outlives_constraint.sub,
|
||||
to: current_point,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// For a given outlives constraint and CFG edge, returns the localized constraint with the
|
||||
/// appropriate `from`-`to` direction. This is computed according to whether the constraint flows to
|
||||
/// or from a free region in the given `value`, some kind of result for an effectful operation, like
|
||||
/// the LHS of an assignment.
|
||||
fn compute_constraint_direction<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||
value: &impl TypeVisitable<TyCtxt<'tcx>>,
|
||||
current_point: PointIndex,
|
||||
successor_point: PointIndex,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> LocalizedOutlivesConstraint {
|
||||
let mut to = current_point;
|
||||
let mut from = current_point;
|
||||
tcx.for_each_free_region(value, |region| {
|
||||
let region = universal_regions.to_region_vid(region);
|
||||
if region == outlives_constraint.sub {
|
||||
// This constraint flows into the result, its effects start becoming visible on exit.
|
||||
to = successor_point;
|
||||
} else if region == outlives_constraint.sup {
|
||||
// This constraint flows from the result, its effects start becoming visible on exit.
|
||||
from = successor_point;
|
||||
}
|
||||
});
|
||||
|
||||
LocalizedOutlivesConstraint {
|
||||
source: outlives_constraint.sup,
|
||||
from,
|
||||
target: outlives_constraint.sub,
|
||||
to,
|
||||
}
|
||||
}
|
||||
|
|
@ -13,15 +13,16 @@ use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound,
|
|||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{
|
||||
BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
|
||||
ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
|
||||
TerminatorKind,
|
||||
AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject,
|
||||
ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location,
|
||||
ReturnConstraint, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::fold::fold_regions;
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
use crate::BorrowckInferCtxt;
|
||||
|
|
@ -315,11 +316,6 @@ enum Trace<'tcx> {
|
|||
NotVisited,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub(crate) enum ExtraConstraintInfo {
|
||||
PlaceholderFromPredicate(Span),
|
||||
}
|
||||
|
||||
#[instrument(skip(infcx, sccs), level = "debug")]
|
||||
fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
|
@ -396,7 +392,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
var_infos: VarInfos,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
) -> Self {
|
||||
let universal_regions = &universal_region_relations.universal_regions;
|
||||
let MirTypeckRegionConstraints {
|
||||
|
|
@ -440,7 +436,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
|
||||
let mut scc_values =
|
||||
RegionValues::new(elements, universal_regions.len(), placeholder_indices);
|
||||
RegionValues::new(location_map, universal_regions.len(), placeholder_indices);
|
||||
|
||||
for region in liveness_constraints.regions() {
|
||||
let scc = constraint_sccs.scc(region);
|
||||
|
|
@ -978,7 +974,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
propagated_outlives_requirements: &mut Vec<ClosureOutlivesRequirement<'tcx>>,
|
||||
) -> bool {
|
||||
let tcx = infcx.tcx;
|
||||
let TypeTest { generic_kind, lower_bound, span: blame_span, ref verify_bound } = *type_test;
|
||||
let TypeTest { generic_kind, lower_bound, span: blame_span, verify_bound: _ } = *type_test;
|
||||
|
||||
let generic_ty = generic_kind.to_ty(tcx);
|
||||
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
|
||||
|
|
@ -1016,25 +1012,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// For each region outlived by lower_bound find a non-local,
|
||||
// universal region (it may be the same region) and add it to
|
||||
// `ClosureOutlivesRequirement`.
|
||||
let mut found_outlived_universal_region = false;
|
||||
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
|
||||
found_outlived_universal_region = true;
|
||||
debug!("universal_region_outlived_by ur={:?}", ur);
|
||||
// Check whether we can already prove that the "subject" outlives `ur`.
|
||||
// If so, we don't have to propagate this requirement to our caller.
|
||||
//
|
||||
// To continue the example from the function, if we are trying to promote
|
||||
// a requirement that `T: 'X`, and we know that `'X = '1 + '2` (i.e., the union
|
||||
// `'1` and `'2`), then in this loop `ur` will be `'1` (and `'2`). So here
|
||||
// we check whether `T: '1` is something we *can* prove. If so, no need
|
||||
// to propagate that requirement.
|
||||
//
|
||||
// This is needed because -- particularly in the case
|
||||
// where `ur` is a local bound -- we are sometimes in a
|
||||
// position to prove things that our caller cannot. See
|
||||
// #53570 for an example.
|
||||
if self.eval_verify_bound(infcx, generic_ty, ur, &verify_bound) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
|
||||
debug!(?non_local_ub);
|
||||
|
||||
|
|
@ -1056,6 +1037,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
propagated_outlives_requirements.push(requirement);
|
||||
}
|
||||
}
|
||||
// If we succeed to promote the subject, i.e. it only contains non-local regions,
|
||||
// and fail to prove the type test inside of the closure, the `lower_bound` has to
|
||||
// also be at least as large as some universal region, as the type test is otherwise
|
||||
// trivial.
|
||||
assert!(found_outlived_universal_region);
|
||||
true
|
||||
}
|
||||
|
||||
|
|
@ -1948,7 +1934,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
from_region: RegionVid,
|
||||
from_region_origin: NllRegionVariableOrigin,
|
||||
target_test: impl Fn(RegionVid) -> bool,
|
||||
) -> (BlameConstraint<'tcx>, Vec<ExtraConstraintInfo>) {
|
||||
) -> (BlameConstraint<'tcx>, Vec<OutlivesConstraint<'tcx>>) {
|
||||
// Find all paths
|
||||
let (path, target_region) = self
|
||||
.find_constraint_paths_between_regions(from_region, target_test)
|
||||
|
|
@ -1970,25 +1956,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
.collect::<Vec<_>>()
|
||||
);
|
||||
|
||||
let mut extra_info = vec![];
|
||||
for constraint in path.iter() {
|
||||
let outlived = constraint.sub;
|
||||
let Some(origin) = self.var_infos.get(outlived) else {
|
||||
continue;
|
||||
};
|
||||
let RegionVariableOrigin::Nll(NllRegionVariableOrigin::Placeholder(p)) = origin.origin
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
debug!(?constraint, ?p);
|
||||
let ConstraintCategory::Predicate(span) = constraint.category else {
|
||||
continue;
|
||||
};
|
||||
extra_info.push(ExtraConstraintInfo::PlaceholderFromPredicate(span));
|
||||
// We only want to point to one
|
||||
break;
|
||||
}
|
||||
|
||||
// We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
|
||||
// Instead, we use it to produce an improved `ObligationCauseCode`.
|
||||
// FIXME - determine what we should do if we encounter multiple
|
||||
|
|
@ -2007,42 +1974,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
})
|
||||
.unwrap_or_else(|| ObligationCauseCode::Misc);
|
||||
|
||||
// Classify each of the constraints along the path.
|
||||
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
|
||||
.iter()
|
||||
.map(|constraint| BlameConstraint {
|
||||
category: constraint.category,
|
||||
from_closure: constraint.from_closure,
|
||||
cause: ObligationCause::new(constraint.span, CRATE_DEF_ID, cause_code.clone()),
|
||||
variance_info: constraint.variance_info,
|
||||
})
|
||||
.collect();
|
||||
debug!("categorized_path={:#?}", categorized_path);
|
||||
|
||||
// To find the best span to cite, we first try to look for the
|
||||
// final constraint that is interesting and where the `sup` is
|
||||
// not unified with the ultimate target region. The reason
|
||||
// for this is that we have a chain of constraints that lead
|
||||
// from the source to the target region, something like:
|
||||
//
|
||||
// '0: '1 ('0 is the source)
|
||||
// '1: '2
|
||||
// '2: '3
|
||||
// '3: '4
|
||||
// '4: '5
|
||||
// '5: '6 ('6 is the target)
|
||||
//
|
||||
// Some of those regions are unified with `'6` (in the same
|
||||
// SCC). We want to screen those out. After that point, the
|
||||
// "closest" constraint we have to the end is going to be the
|
||||
// most likely to be the point where the value escapes -- but
|
||||
// we still want to screen for an "interesting" point to
|
||||
// highlight (e.g., a call site or something).
|
||||
let target_scc = self.constraint_sccs.scc(target_region);
|
||||
let mut range = 0..path.len();
|
||||
|
||||
// As noted above, when reporting an error, there is typically a chain of constraints
|
||||
// leading from some "source" region which must outlive some "target" region.
|
||||
// When reporting an error, there is typically a chain of constraints leading from some
|
||||
// "source" region which must outlive some "target" region.
|
||||
// In most cases, we prefer to "blame" the constraints closer to the target --
|
||||
// but there is one exception. When constraints arise from higher-ranked subtyping,
|
||||
// we generally prefer to blame the source value,
|
||||
|
|
@ -2083,78 +2016,114 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
| NllRegionVariableOrigin::Existential { from_forall: true } => false,
|
||||
};
|
||||
|
||||
let find_region = |i: &usize| {
|
||||
let constraint = &path[*i];
|
||||
|
||||
let constraint_sup_scc = self.constraint_sccs.scc(constraint.sup);
|
||||
|
||||
if blame_source {
|
||||
match categorized_path[*i].category {
|
||||
ConstraintCategory::OpaqueType
|
||||
| ConstraintCategory::Boring
|
||||
| ConstraintCategory::BoringNoLocation
|
||||
| ConstraintCategory::Internal
|
||||
| ConstraintCategory::Predicate(_) => false,
|
||||
ConstraintCategory::TypeAnnotation
|
||||
| ConstraintCategory::Return(_)
|
||||
| ConstraintCategory::Yield => true,
|
||||
_ => constraint_sup_scc != target_scc,
|
||||
}
|
||||
// To pick a constraint to blame, we organize constraints by how interesting we expect them
|
||||
// to be in diagnostics, then pick the most interesting one closest to either the source or
|
||||
// the target on our constraint path.
|
||||
let constraint_interest = |constraint: &OutlivesConstraint<'tcx>| {
|
||||
// Try to avoid blaming constraints from desugarings, since they may not clearly match
|
||||
// match what users have written. As an exception, allow blaming returns generated by
|
||||
// `?` desugaring, since the correspondence is fairly clear.
|
||||
let category = if let Some(kind) = constraint.span.desugaring_kind()
|
||||
&& (kind != DesugaringKind::QuestionMark
|
||||
|| !matches!(constraint.category, ConstraintCategory::Return(_)))
|
||||
{
|
||||
ConstraintCategory::Boring
|
||||
} else {
|
||||
!matches!(
|
||||
categorized_path[*i].category,
|
||||
ConstraintCategory::OpaqueType
|
||||
| ConstraintCategory::Boring
|
||||
| ConstraintCategory::BoringNoLocation
|
||||
| ConstraintCategory::Internal
|
||||
| ConstraintCategory::Predicate(_)
|
||||
constraint.category
|
||||
};
|
||||
|
||||
match category {
|
||||
// Returns usually provide a type to blame and have specially written diagnostics,
|
||||
// so prioritize them.
|
||||
ConstraintCategory::Return(_) => 0,
|
||||
// Unsizing coercions are interesting, since we have a note for that:
|
||||
// `BorrowExplanation::add_object_lifetime_default_note`.
|
||||
// FIXME(dianne): That note shouldn't depend on a coercion being blamed; see issue
|
||||
// #131008 for an example of where we currently don't emit it but should.
|
||||
// Once the note is handled properly, this case should be removed. Until then, it
|
||||
// should be as limited as possible; the note is prone to false positives and this
|
||||
// constraint usually isn't best to blame.
|
||||
ConstraintCategory::Cast {
|
||||
unsize_to: Some(unsize_ty),
|
||||
is_implicit_coercion: true,
|
||||
} if target_region == self.universal_regions().fr_static
|
||||
// Mirror the note's condition, to minimize how often this diverts blame.
|
||||
&& let ty::Adt(_, args) = unsize_ty.kind()
|
||||
&& args.iter().any(|arg| arg.as_type().is_some_and(|ty| ty.is_trait()))
|
||||
// Mimic old logic for this, to minimize false positives in tests.
|
||||
&& !path
|
||||
.iter()
|
||||
.any(|c| matches!(c.category, ConstraintCategory::TypeAnnotation(_))) =>
|
||||
{
|
||||
1
|
||||
}
|
||||
// Between other interesting constraints, order by their position on the `path`.
|
||||
ConstraintCategory::Yield
|
||||
| ConstraintCategory::UseAsConst
|
||||
| ConstraintCategory::UseAsStatic
|
||||
| ConstraintCategory::TypeAnnotation(
|
||||
AnnotationSource::Ascription
|
||||
| AnnotationSource::Declaration
|
||||
| AnnotationSource::OpaqueCast,
|
||||
)
|
||||
| ConstraintCategory::Cast { .. }
|
||||
| ConstraintCategory::CallArgument(_)
|
||||
| ConstraintCategory::CopyBound
|
||||
| ConstraintCategory::SizedBound
|
||||
| ConstraintCategory::Assignment
|
||||
| ConstraintCategory::Usage
|
||||
| ConstraintCategory::ClosureUpvar(_) => 2,
|
||||
// Generic arguments are unlikely to be what relates regions together
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg) => 3,
|
||||
// We handle predicates and opaque types specially; don't prioritize them here.
|
||||
ConstraintCategory::Predicate(_) | ConstraintCategory::OpaqueType => 4,
|
||||
// `Boring` constraints can correspond to user-written code and have useful spans,
|
||||
// but don't provide any other useful information for diagnostics.
|
||||
ConstraintCategory::Boring => 5,
|
||||
// `BoringNoLocation` constraints can point to user-written code, but are less
|
||||
// specific, and are not used for relations that would make sense to blame.
|
||||
ConstraintCategory::BoringNoLocation => 6,
|
||||
// Do not blame internal constraints.
|
||||
ConstraintCategory::Internal => 7,
|
||||
ConstraintCategory::IllegalUniverse => 8,
|
||||
}
|
||||
};
|
||||
|
||||
let best_choice =
|
||||
if blame_source { range.rev().find(find_region) } else { range.find(find_region) };
|
||||
let best_choice = if blame_source {
|
||||
path.iter().enumerate().rev().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0
|
||||
} else {
|
||||
path.iter().enumerate().min_by_key(|(_, c)| constraint_interest(c)).unwrap().0
|
||||
};
|
||||
|
||||
debug!(?best_choice, ?blame_source, ?extra_info);
|
||||
debug!(?best_choice, ?blame_source);
|
||||
|
||||
if let Some(i) = best_choice {
|
||||
if let Some(next) = categorized_path.get(i + 1) {
|
||||
if matches!(categorized_path[i].category, ConstraintCategory::Return(_))
|
||||
&& next.category == ConstraintCategory::OpaqueType
|
||||
{
|
||||
// The return expression is being influenced by the return type being
|
||||
// impl Trait, point at the return type and not the return expr.
|
||||
return (next.clone(), extra_info);
|
||||
}
|
||||
let best_constraint = if let Some(next) = path.get(best_choice + 1)
|
||||
&& matches!(path[best_choice].category, ConstraintCategory::Return(_))
|
||||
&& next.category == ConstraintCategory::OpaqueType
|
||||
{
|
||||
// The return expression is being influenced by the return type being
|
||||
// impl Trait, point at the return type and not the return expr.
|
||||
*next
|
||||
} else if path[best_choice].category == ConstraintCategory::Return(ReturnConstraint::Normal)
|
||||
&& let Some(field) = path.iter().find_map(|p| {
|
||||
if let ConstraintCategory::ClosureUpvar(f) = p.category { Some(f) } else { None }
|
||||
})
|
||||
{
|
||||
OutlivesConstraint {
|
||||
category: ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field)),
|
||||
..path[best_choice]
|
||||
}
|
||||
} else {
|
||||
path[best_choice]
|
||||
};
|
||||
|
||||
if categorized_path[i].category == ConstraintCategory::Return(ReturnConstraint::Normal)
|
||||
{
|
||||
let field = categorized_path.iter().find_map(|p| {
|
||||
if let ConstraintCategory::ClosureUpvar(f) = p.category {
|
||||
Some(f)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(field) = field {
|
||||
categorized_path[i].category =
|
||||
ConstraintCategory::Return(ReturnConstraint::ClosureUpvar(field));
|
||||
}
|
||||
}
|
||||
|
||||
return (categorized_path[i].clone(), extra_info);
|
||||
}
|
||||
|
||||
// If that search fails, that is.. unusual. Maybe everything
|
||||
// is in the same SCC or something. In that case, find what
|
||||
// appears to be the most interesting point to report to the
|
||||
// user via an even more ad-hoc guess.
|
||||
categorized_path.sort_by_key(|p| p.category);
|
||||
debug!("sorted_path={:#?}", categorized_path);
|
||||
|
||||
(categorized_path.remove(0), extra_info)
|
||||
let blame_constraint = BlameConstraint {
|
||||
category: best_constraint.category,
|
||||
from_closure: best_constraint.from_closure,
|
||||
cause: ObligationCause::new(best_constraint.span, CRATE_DEF_ID, cause_code.clone()),
|
||||
variance_info: best_constraint.variance_info,
|
||||
};
|
||||
(blame_constraint, path)
|
||||
}
|
||||
|
||||
pub(crate) fn universe_info(&self, universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
|
||||
|
|
|
|||
|
|
@ -152,7 +152,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
let (Ok(e) | Err(e)) = prev
|
||||
.build_mismatch_error(
|
||||
&OpaqueHiddenType { ty, span: concrete_type.span },
|
||||
opaque_type_key.def_id,
|
||||
infcx.tcx,
|
||||
)
|
||||
.map(|d| d.emit());
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ pub(crate) enum RegionElement {
|
|||
/// an interval matrix storing liveness ranges for each region-vid.
|
||||
pub(crate) struct LivenessValues {
|
||||
/// The map from locations to points.
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
|
||||
/// Which regions are live. This is exclusive with the fine-grained tracking in `points`, and
|
||||
/// currently only used for validating promoteds (which don't care about more precise tracking).
|
||||
|
|
@ -77,11 +77,11 @@ impl LiveLoans {
|
|||
|
||||
impl LivenessValues {
|
||||
/// Create an empty map of regions to locations where they're live.
|
||||
pub(crate) fn with_specific_points(elements: Rc<DenseLocationMap>) -> Self {
|
||||
pub(crate) fn with_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
|
||||
LivenessValues {
|
||||
live_regions: None,
|
||||
points: Some(SparseIntervalMatrix::new(elements.num_points())),
|
||||
elements,
|
||||
points: Some(SparseIntervalMatrix::new(location_map.num_points())),
|
||||
location_map,
|
||||
loans: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -90,11 +90,11 @@ impl LivenessValues {
|
|||
///
|
||||
/// Unlike `with_specific_points`, does not track exact locations where something is live, only
|
||||
/// which regions are live.
|
||||
pub(crate) fn without_specific_points(elements: Rc<DenseLocationMap>) -> Self {
|
||||
pub(crate) fn without_specific_points(location_map: Rc<DenseLocationMap>) -> Self {
|
||||
LivenessValues {
|
||||
live_regions: Some(Default::default()),
|
||||
points: None,
|
||||
elements,
|
||||
location_map,
|
||||
loans: None,
|
||||
}
|
||||
}
|
||||
|
|
@ -122,11 +122,11 @@ impl LivenessValues {
|
|||
|
||||
/// Records `region` as being live at the given `location`.
|
||||
pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) {
|
||||
let point = self.elements.point_from_location(location);
|
||||
let point = self.location_map.point_from_location(location);
|
||||
debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location);
|
||||
if let Some(points) = &mut self.points {
|
||||
points.insert(region, point);
|
||||
} else if self.elements.point_in_range(point) {
|
||||
} else if self.location_map.point_in_range(point) {
|
||||
self.live_regions.as_mut().unwrap().insert(region);
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ impl LivenessValues {
|
|||
debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points);
|
||||
if let Some(this) = &mut self.points {
|
||||
this.union_row(region, points);
|
||||
} else if points.iter().any(|point| self.elements.point_in_range(point)) {
|
||||
} else if points.iter().any(|point| self.location_map.point_in_range(point)) {
|
||||
self.live_regions.as_mut().unwrap().insert(region);
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ impl LivenessValues {
|
|||
|
||||
/// Returns whether `region` is marked live at the given `location`.
|
||||
pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool {
|
||||
let point = self.elements.point_from_location(location);
|
||||
let point = self.location_map.point_from_location(location);
|
||||
if let Some(points) = &self.points {
|
||||
points.row(region).is_some_and(|r| r.contains(point))
|
||||
} else {
|
||||
|
|
@ -191,25 +191,26 @@ impl LivenessValues {
|
|||
.row(region)
|
||||
.into_iter()
|
||||
.flat_map(|set| set.iter())
|
||||
.take_while(|&p| self.elements.point_in_range(p))
|
||||
.take_while(|&p| self.location_map.point_in_range(p))
|
||||
}
|
||||
|
||||
/// For debugging purposes, returns a pretty-printed string of the points where the `region` is
|
||||
/// live.
|
||||
pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String {
|
||||
pretty_print_region_elements(
|
||||
self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))),
|
||||
self.live_points(region)
|
||||
.map(|p| RegionElement::Location(self.location_map.to_location(p))),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
|
||||
self.elements.point_from_location(location)
|
||||
self.location_map.point_from_location(location)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn location_from_point(&self, point: PointIndex) -> Location {
|
||||
self.elements.to_location(point)
|
||||
self.location_map.to_location(point)
|
||||
}
|
||||
|
||||
/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
|
||||
|
|
@ -272,7 +273,7 @@ impl PlaceholderIndices {
|
|||
/// because (since it is returned) it must live for at least `'a`. But
|
||||
/// it would also contain various points from within the function.
|
||||
pub(crate) struct RegionValues<N: Idx> {
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
placeholder_indices: PlaceholderIndices,
|
||||
points: SparseIntervalMatrix<N, PointIndex>,
|
||||
free_regions: SparseBitMatrix<N, RegionVid>,
|
||||
|
|
@ -287,14 +288,14 @@ impl<N: Idx> RegionValues<N> {
|
|||
/// Each of the regions in num_region_variables will be initialized with an
|
||||
/// empty set of points and no causal information.
|
||||
pub(crate) fn new(
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
num_universal_regions: usize,
|
||||
placeholder_indices: PlaceholderIndices,
|
||||
) -> Self {
|
||||
let num_points = elements.num_points();
|
||||
let num_points = location_map.num_points();
|
||||
let num_placeholders = placeholder_indices.len();
|
||||
Self {
|
||||
elements,
|
||||
location_map,
|
||||
points: SparseIntervalMatrix::new(num_points),
|
||||
placeholder_indices,
|
||||
free_regions: SparseBitMatrix::new(num_universal_regions),
|
||||
|
|
@ -336,7 +337,7 @@ impl<N: Idx> RegionValues<N> {
|
|||
end: usize,
|
||||
) -> Option<usize> {
|
||||
let row = self.points.row(r)?;
|
||||
let block = self.elements.entry_point(block);
|
||||
let block = self.location_map.entry_point(block);
|
||||
let start = block.plus(start);
|
||||
let end = block.plus(end);
|
||||
let first_unset = row.first_unset_in(start..=end)?;
|
||||
|
|
@ -375,8 +376,8 @@ impl<N: Idx> RegionValues<N> {
|
|||
pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator<Item = Location> + 'a {
|
||||
self.points.row(r).into_iter().flat_map(move |set| {
|
||||
set.iter()
|
||||
.take_while(move |&p| self.elements.point_in_range(p))
|
||||
.map(move |p| self.elements.to_location(p))
|
||||
.take_while(move |&p| self.location_map.point_in_range(p))
|
||||
.map(move |p| self.location_map.to_location(p))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -430,12 +431,12 @@ pub(crate) trait ToElementIndex: Debug + Copy {
|
|||
|
||||
impl ToElementIndex for Location {
|
||||
fn add_to_row<N: Idx>(self, values: &mut RegionValues<N>, row: N) -> bool {
|
||||
let index = values.elements.point_from_location(self);
|
||||
let index = values.location_map.point_from_location(self);
|
||||
values.points.insert(row, index)
|
||||
}
|
||||
|
||||
fn contained_in_row<N: Idx>(self, values: &RegionValues<N>, row: N) -> bool {
|
||||
let index = values.elements.point_from_location(self);
|
||||
let index = values.location_map.point_from_location(self);
|
||||
values.points.contains(row, index)
|
||||
}
|
||||
}
|
||||
|
|
@ -464,14 +465,14 @@ impl ToElementIndex for ty::PlaceholderRegion {
|
|||
|
||||
/// For debugging purposes, returns a pretty-printed string of the given points.
|
||||
pub(crate) fn pretty_print_points(
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
points: impl IntoIterator<Item = PointIndex>,
|
||||
) -> String {
|
||||
pretty_print_region_elements(
|
||||
points
|
||||
.into_iter()
|
||||
.take_while(|&p| elements.point_in_range(p))
|
||||
.map(|p| elements.to_location(p))
|
||||
.take_while(|&p| location_map.point_in_range(p))
|
||||
.map(|p| location_map.to_location(p))
|
||||
.map(RegionElement::Location),
|
||||
)
|
||||
}
|
||||
|
|
@ -544,12 +545,12 @@ fn pretty_print_region_elements(elements: impl IntoIterator<Item = RegionElement
|
|||
|
||||
return result;
|
||||
|
||||
fn push_location_range(str: &mut String, location1: Location, location2: Location) {
|
||||
fn push_location_range(s: &mut String, location1: Location, location2: Location) {
|
||||
if location1 == location2 {
|
||||
str.push_str(&format!("{location1:?}"));
|
||||
s.push_str(&format!("{location1:?}"));
|
||||
} else {
|
||||
assert_eq!(location1.block, location2.block);
|
||||
str.push_str(&format!(
|
||||
s.push_str(&format!(
|
||||
"{:?}[{}..={}]",
|
||||
location1.block, location1.statement_index, location2.statement_index
|
||||
));
|
||||
|
|
|
|||
|
|
@ -480,3 +480,10 @@ pub(crate) struct SimdIntrinsicArgConst {
|
|||
pub arg: usize,
|
||||
pub intrinsic: String,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(borrowck_tail_expr_drop_order)]
|
||||
pub(crate) struct TailExprDropOrder {
|
||||
#[label]
|
||||
pub borrowed: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ impl<'a> Iterator for AppearancesIter<'a> {
|
|||
impl LocalUseMap {
|
||||
pub(crate) fn build(
|
||||
live_locals: &[Local],
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
body: &Body<'_>,
|
||||
) -> Self {
|
||||
let nones = IndexVec::from_elem(None, &body.local_decls);
|
||||
|
|
@ -101,7 +101,7 @@ impl LocalUseMap {
|
|||
IndexVec::from_elem(false, &body.local_decls);
|
||||
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
|
||||
|
||||
LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data }
|
||||
LocalUseMapBuild { local_use_map: &mut local_use_map, location_map, locals_with_use_data }
|
||||
.visit_body(body);
|
||||
|
||||
local_use_map
|
||||
|
|
@ -125,7 +125,7 @@ impl LocalUseMap {
|
|||
|
||||
struct LocalUseMapBuild<'me> {
|
||||
local_use_map: &'me mut LocalUseMap,
|
||||
elements: &'me DenseLocationMap,
|
||||
location_map: &'me DenseLocationMap,
|
||||
|
||||
// Vector used in `visit_local` to signal which `Local`s do we need
|
||||
// def/use/drop information on, constructed from `live_locals` (that
|
||||
|
|
@ -147,7 +147,7 @@ impl Visitor<'_> for LocalUseMapBuild<'_> {
|
|||
DefUse::Use => &mut self.local_use_map.first_use_at[local],
|
||||
DefUse::Drop => &mut self.local_use_map.first_drop_at[local],
|
||||
};
|
||||
let point_index = self.elements.point_from_location(location);
|
||||
let point_index = self.location_map.point_from_location(location);
|
||||
let appearance_index = self
|
||||
.local_use_map
|
||||
.appearances
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ mod trace;
|
|||
pub(super) fn generate<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
) {
|
||||
|
|
@ -49,7 +49,7 @@ pub(super) fn generate<'a, 'tcx>(
|
|||
trace::trace(
|
||||
typeck,
|
||||
body,
|
||||
elements,
|
||||
location_map,
|
||||
flow_inits,
|
||||
move_data,
|
||||
relevant_live_locals,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::interval::IntervalSet;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives::for_liveness;
|
||||
|
|
@ -37,13 +37,13 @@ use crate::type_check::{NormalizeLocation, TypeChecker};
|
|||
pub(super) fn trace<'a, 'tcx>(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
relevant_live_locals: Vec<Local>,
|
||||
boring_locals: Vec<Local>,
|
||||
) {
|
||||
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);
|
||||
let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, body);
|
||||
|
||||
// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
|
||||
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
|
|
@ -79,7 +79,7 @@ pub(super) fn trace<'a, 'tcx>(
|
|||
typeck,
|
||||
body,
|
||||
flow_inits,
|
||||
elements,
|
||||
location_map,
|
||||
local_use_map,
|
||||
move_data,
|
||||
drop_data: FxIndexMap::default(),
|
||||
|
|
@ -100,7 +100,7 @@ struct LivenessContext<'a, 'typeck, 'b, 'tcx> {
|
|||
typeck: &'a mut TypeChecker<'typeck, 'tcx>,
|
||||
|
||||
/// Defines the `PointIndex` mapping
|
||||
elements: &'a DenseLocationMap,
|
||||
location_map: &'a DenseLocationMap,
|
||||
|
||||
/// MIR we are analyzing.
|
||||
body: &'a Body<'tcx>,
|
||||
|
|
@ -129,7 +129,7 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
cx: LivenessContext<'a, 'typeck, 'b, 'tcx>,
|
||||
|
||||
/// Set of points that define the current local.
|
||||
defs: BitSet<PointIndex>,
|
||||
defs: DenseBitSet<PointIndex>,
|
||||
|
||||
/// Points where the current variable is "use live" -- meaning
|
||||
/// that there is a future "full use" that may use its value.
|
||||
|
|
@ -149,10 +149,10 @@ struct LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
|
||||
impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
||||
fn new(cx: LivenessContext<'a, 'typeck, 'b, 'tcx>) -> Self {
|
||||
let num_points = cx.elements.num_points();
|
||||
let num_points = cx.location_map.num_points();
|
||||
LivenessResults {
|
||||
cx,
|
||||
defs: BitSet::new_empty(num_points),
|
||||
defs: DenseBitSet::new_empty(num_points),
|
||||
use_live_at: IntervalSet::new(num_points),
|
||||
drop_live_at: IntervalSet::new(num_points),
|
||||
drop_locations: vec![],
|
||||
|
|
@ -213,14 +213,14 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
fn add_extra_drop_facts(&mut self, relevant_live_locals: &[Local]) {
|
||||
// This collect is more necessary than immediately apparent
|
||||
// because these facts go into `add_drop_live_facts_for()`,
|
||||
// which also writes to `all_facts`, and so this is genuinely
|
||||
// which also writes to `polonius_facts`, and so this is genuinely
|
||||
// a simultaneous overlapping mutable borrow.
|
||||
// FIXME for future hackers: investigate whether this is
|
||||
// actually necessary; these facts come from Polonius
|
||||
// and probably maybe plausibly does not need to go back in.
|
||||
// It may be necessary to just pick out the parts of
|
||||
// `add_drop_live_facts_for()` that make sense.
|
||||
let Some(facts) = self.cx.typeck.all_facts.as_ref() else { return };
|
||||
let Some(facts) = self.cx.typeck.polonius_facts.as_ref() else { return };
|
||||
let facts_to_add: Vec<_> = {
|
||||
let relevant_live_locals: FxIndexSet<_> =
|
||||
relevant_live_locals.iter().copied().collect();
|
||||
|
|
@ -240,7 +240,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
.collect()
|
||||
};
|
||||
|
||||
let live_at = IntervalSet::new(self.cx.elements.num_points());
|
||||
let live_at = IntervalSet::new(self.cx.location_map.num_points());
|
||||
for (local, local_ty, location) in facts_to_add {
|
||||
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &live_at);
|
||||
}
|
||||
|
|
@ -279,7 +279,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
// * Inclusively, the block start
|
||||
// * Exclusively, the previous definition (if it's in this block)
|
||||
// * Exclusively, the previous live_at setting (an optimization)
|
||||
let block_start = self.cx.elements.to_block_start(p);
|
||||
let block_start = self.cx.location_map.to_block_start(p);
|
||||
let previous_defs = self.defs.last_set_in(block_start..=p);
|
||||
let previous_live_at = self.use_live_at.last_set_in(block_start..=p);
|
||||
|
||||
|
|
@ -303,12 +303,12 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
// terminators of predecessor basic blocks. Push those onto the
|
||||
// stack so that the next iteration(s) will process them.
|
||||
|
||||
let block = self.cx.elements.to_location(block_start).block;
|
||||
let block = self.cx.location_map.to_location(block_start).block;
|
||||
self.stack.extend(
|
||||
self.cx.body.basic_blocks.predecessors()[block]
|
||||
.iter()
|
||||
.map(|&pred_bb| self.cx.body.terminator_loc(pred_bb))
|
||||
.map(|pred_loc| self.cx.elements.point_from_location(pred_loc)),
|
||||
.map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -331,7 +331,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
|
||||
// Find the drops where `local` is initialized.
|
||||
for drop_point in self.cx.local_use_map.drops(local) {
|
||||
let location = self.cx.elements.to_location(drop_point);
|
||||
let location = self.cx.location_map.to_location(drop_point);
|
||||
debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
|
||||
|
||||
if self.cx.initialized_at_terminator(location.block, mpi)
|
||||
|
|
@ -367,7 +367,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
debug!(
|
||||
"compute_drop_live_points_for_block(mpi={:?}, term_point={:?})",
|
||||
self.cx.move_data.move_paths[mpi].place,
|
||||
self.cx.elements.to_location(term_point),
|
||||
self.cx.location_map.to_location(term_point),
|
||||
);
|
||||
|
||||
// We are only invoked with terminators where `mpi` is
|
||||
|
|
@ -377,12 +377,15 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
// Otherwise, scan backwards through the statements in the
|
||||
// block. One of them may be either a definition or use
|
||||
// live point.
|
||||
let term_location = self.cx.elements.to_location(term_point);
|
||||
let term_location = self.cx.location_map.to_location(term_point);
|
||||
debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
|
||||
let block = term_location.block;
|
||||
let entry_point = self.cx.elements.entry_point(term_location.block);
|
||||
let entry_point = self.cx.location_map.entry_point(term_location.block);
|
||||
for p in (entry_point..term_point).rev() {
|
||||
debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p));
|
||||
debug!(
|
||||
"compute_drop_live_points_for_block: p = {:?}",
|
||||
self.cx.location_map.to_location(p)
|
||||
);
|
||||
|
||||
if self.defs.contains(p) {
|
||||
debug!("compute_drop_live_points_for_block: def site");
|
||||
|
|
@ -428,7 +431,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> {
|
|||
}
|
||||
|
||||
let pred_term_loc = self.cx.body.terminator_loc(pred_block);
|
||||
let pred_term_point = self.cx.elements.point_from_location(pred_term_loc);
|
||||
let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc);
|
||||
|
||||
// If the terminator of this predecessor either *assigns*
|
||||
// our value or is a "normal use", then stop.
|
||||
|
|
@ -523,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
/// points `live_at`.
|
||||
fn add_use_live_facts_for(&mut self, value: Ty<'tcx>, live_at: &IntervalSet<PointIndex>) {
|
||||
debug!("add_use_live_facts_for(value={:?})", value);
|
||||
Self::make_all_regions_live(self.elements, self.typeck, value, live_at);
|
||||
Self::make_all_regions_live(self.location_map, self.typeck, value, live_at);
|
||||
}
|
||||
|
||||
/// Some variable with type `live_ty` is "drop live" at `location`
|
||||
|
|
@ -547,7 +550,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
dropped_local,
|
||||
dropped_ty,
|
||||
drop_locations,
|
||||
values::pretty_print_points(self.elements, live_at.iter()),
|
||||
values::pretty_print_points(self.location_map, live_at.iter()),
|
||||
);
|
||||
|
||||
let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({
|
||||
|
|
@ -574,19 +577,19 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
for &kind in &drop_data.dropck_result.kinds {
|
||||
Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
|
||||
Self::make_all_regions_live(self.location_map, self.typeck, kind, live_at);
|
||||
polonius::legacy::emit_drop_facts(
|
||||
self.typeck.tcx(),
|
||||
dropped_local,
|
||||
&kind,
|
||||
self.typeck.universal_regions,
|
||||
self.typeck.all_facts,
|
||||
self.typeck.polonius_facts,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn make_all_regions_live(
|
||||
elements: &DenseLocationMap,
|
||||
location_map: &DenseLocationMap,
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
value: impl TypeVisitable<TyCtxt<'tcx>> + Relate<TyCtxt<'tcx>>,
|
||||
live_at: &IntervalSet<PointIndex>,
|
||||
|
|
@ -594,7 +597,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
|
|||
debug!("make_all_regions_live(value={:?})", value);
|
||||
debug!(
|
||||
"make_all_regions_live: live_at={}",
|
||||
values::pretty_print_points(elements, live_at.iter()),
|
||||
values::pretty_print_points(location_map, live_at.iter()),
|
||||
);
|
||||
|
||||
value.visit_with(&mut for_liveness::FreeRegionsVisitor {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
|
|||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::member_constraints::MemberConstraintSet;
|
||||
use crate::polonius::PoloniusContext;
|
||||
use crate::polonius::legacy::{AllFacts, LocationTable};
|
||||
use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::region_infer::TypeTest;
|
||||
use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices};
|
||||
use crate::renumber::RegionCtxt;
|
||||
|
|
@ -98,29 +98,29 @@ mod relate_tys;
|
|||
/// - `body` -- MIR body to type-check
|
||||
/// - `promoted` -- map of promoted constants within `body`
|
||||
/// - `universal_regions` -- the universal regions from `body`s function signature
|
||||
/// - `location_table` -- MIR location map of `body`
|
||||
/// - `location_table` -- for datalog polonius, the map between `Location`s and `RichLocation`s
|
||||
/// - `borrow_set` -- information about borrows occurring in `body`
|
||||
/// - `all_facts` -- when using Polonius, this is the generated set of Polonius facts
|
||||
/// - `polonius_facts` -- when using Polonius, this is the generated set of Polonius facts
|
||||
/// - `flow_inits` -- results of a maybe-init dataflow analysis
|
||||
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
||||
/// - `elements` -- MIR region map
|
||||
/// - `location_map` -- map between MIR `Location` and `PointIndex`
|
||||
pub(crate) fn type_check<'a, 'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
location_table: &PoloniusLocationTable,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
all_facts: &mut Option<AllFacts>,
|
||||
polonius_facts: &mut Option<PoloniusFacts>,
|
||||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
elements: Rc<DenseLocationMap>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
) -> MirTypeckResults<'tcx> {
|
||||
let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
|
||||
let mut constraints = MirTypeckRegionConstraints {
|
||||
placeholder_indices: PlaceholderIndices::default(),
|
||||
placeholder_index_to_region: IndexVec::default(),
|
||||
liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&elements)),
|
||||
liveness_constraints: LivenessValues::with_specific_points(Rc::clone(&location_map)),
|
||||
outlives_constraints: OutlivesConstraintSet::default(),
|
||||
member_constraints: MemberConstraintSet::default(),
|
||||
type_tests: Vec::default(),
|
||||
|
|
@ -165,7 +165,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
reported_errors: Default::default(),
|
||||
universal_regions: &universal_region_relations.universal_regions,
|
||||
location_table,
|
||||
all_facts,
|
||||
polonius_facts,
|
||||
borrow_set,
|
||||
constraints: &mut constraints,
|
||||
polonius_context: &mut polonius_context,
|
||||
|
|
@ -180,7 +180,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output);
|
||||
typeck.check_signature_annotation(body);
|
||||
|
||||
liveness::generate(&mut typeck, body, &elements, flow_inits, move_data);
|
||||
liveness::generate(&mut typeck, body, &location_map, flow_inits, move_data);
|
||||
|
||||
let opaque_type_values =
|
||||
opaque_types::take_opaques_and_register_member_constraints(&mut typeck);
|
||||
|
|
@ -298,7 +298,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
context.ambient_variance(),
|
||||
base_ty.ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::OpaqueCast),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
|
@ -333,7 +333,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
ty::Invariant,
|
||||
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
||||
locations,
|
||||
ConstraintCategory::Boring,
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg),
|
||||
) {
|
||||
let annotation = &self.typeck.user_type_annotations[annotation_index];
|
||||
span_mirbug!(
|
||||
|
|
@ -455,7 +455,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||
ty::Invariant,
|
||||
user_ty,
|
||||
Locations::All(*span),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration),
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
|
@ -495,14 +495,14 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
|
|||
|
||||
// Use new sets of constraints and closure bounds so that we can
|
||||
// modify their locations.
|
||||
let all_facts = &mut None;
|
||||
let polonius_facts = &mut None;
|
||||
let mut constraints = Default::default();
|
||||
let mut liveness_constraints =
|
||||
LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body)));
|
||||
// Don't try to add borrow_region facts for the promoted MIR
|
||||
|
||||
let mut swap_constraints = |this: &mut Self| {
|
||||
mem::swap(this.typeck.all_facts, all_facts);
|
||||
mem::swap(this.typeck.polonius_facts, polonius_facts);
|
||||
mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints);
|
||||
mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints);
|
||||
};
|
||||
|
|
@ -560,8 +560,8 @@ struct TypeChecker<'a, 'tcx> {
|
|||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a LocationTable,
|
||||
all_facts: &'a mut Option<AllFacts>,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
polonius_facts: &'a mut Option<PoloniusFacts>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
/// When using `-Zpolonius=next`, the helper data used to create polonius constraints.
|
||||
|
|
@ -927,7 +927,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ty::Invariant,
|
||||
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg),
|
||||
) {
|
||||
let annotation = &self.user_type_annotations[annotation_index];
|
||||
span_mirbug!(
|
||||
|
|
@ -962,7 +962,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
*variance,
|
||||
projection,
|
||||
Locations::All(stmt.source_info.span),
|
||||
ConstraintCategory::TypeAnnotation,
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::Ascription),
|
||||
) {
|
||||
let annotation = &self.user_type_annotations[projection.base];
|
||||
span_mirbug!(
|
||||
|
|
@ -1226,6 +1226,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
Some(l) if !body.local_decls[l].is_user_variable() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
// The return type of a call is interesting for diagnostics.
|
||||
_ => ConstraintCategory::Assignment,
|
||||
};
|
||||
|
||||
|
|
@ -2169,7 +2170,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ty_left,
|
||||
common_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
ConstraintCategory::CallArgument(None),
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
bug!("Could not equate type variable with {:?}: {:?}", ty_left, err)
|
||||
|
|
@ -2178,7 +2179,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
ty_right,
|
||||
common_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
ConstraintCategory::CallArgument(None),
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
|
|
@ -2327,18 +2328,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
borrowed_place: &Place<'tcx>,
|
||||
) {
|
||||
// These constraints are only meaningful during borrowck:
|
||||
let Self { borrow_set, location_table, all_facts, constraints, .. } = self;
|
||||
let Self { borrow_set, location_table, polonius_facts, constraints, .. } = self;
|
||||
|
||||
// In Polonius mode, we also push a `loan_issued_at` fact
|
||||
// linking the loan to the region (in some cases, though,
|
||||
// there is no loan associated with this borrow expression --
|
||||
// that occurs when we are borrowing an unsafe place, for
|
||||
// example).
|
||||
if let Some(all_facts) = all_facts {
|
||||
if let Some(polonius_facts) = polonius_facts {
|
||||
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
|
||||
if let Some(borrow_index) = borrow_set.get_index_of(&location) {
|
||||
let region_vid = borrow_region.as_var();
|
||||
all_facts.loan_issued_at.push((
|
||||
polonius_facts.loan_issued_at.push((
|
||||
region_vid.into(),
|
||||
borrow_index,
|
||||
location_table.mid_index(location),
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{Body, Local, Location};
|
||||
|
||||
pub(crate) trait FindAssignments {
|
||||
// Finds all statements that assign directly to local (i.e., X = ...)
|
||||
// and returns their locations.
|
||||
fn find_assignments(&self, local: Local) -> Vec<Location>;
|
||||
}
|
||||
|
||||
impl<'tcx> FindAssignments for Body<'tcx> {
|
||||
fn find_assignments(&self, local: Local) -> Vec<Location> {
|
||||
let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] };
|
||||
visitor.visit_body(self);
|
||||
visitor.locations
|
||||
}
|
||||
}
|
||||
|
||||
// The Visitor walks the MIR to return the assignment statements corresponding
|
||||
// to a Local.
|
||||
struct FindLocalAssignmentVisitor {
|
||||
needle: Local,
|
||||
locations: Vec<Location>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor {
|
||||
fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {
|
||||
if self.needle != local {
|
||||
return;
|
||||
}
|
||||
|
||||
if place_context.is_place_assignment() {
|
||||
self.locations.push(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
mod collect_writes;
|
||||
|
||||
pub(crate) use collect_writes::FindAssignments;
|
||||
|
|
@ -56,11 +56,6 @@ jobs:
|
|||
- os: macos-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-apple-darwin
|
||||
# cross-compile from Linux to Windows using mingw
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
apt_deps: gcc-mingw-w64-x86-64 wine-stable
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: aarch64-unknown-linux-gnu
|
||||
|
|
@ -113,15 +108,6 @@ jobs:
|
|||
- name: Prepare dependencies
|
||||
run: ./y.sh prepare
|
||||
|
||||
# The Wine version shipped with Ubuntu 22.04 doesn't implement bcryptprimitives.dll
|
||||
- name: Build bcryptprimitives.dll shim for Wine
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: |
|
||||
rustup target add x86_64-pc-windows-gnu
|
||||
mkdir wine_shims
|
||||
rustc patches/bcryptprimitives.rs -Copt-level=3 -Clto=fat --out-dir wine_shims --target x86_64-pc-windows-gnu
|
||||
echo "WINEPATH=$(pwd)/wine_shims" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: ./y.sh build --sysroot none
|
||||
|
||||
|
|
@ -135,9 +121,6 @@ jobs:
|
|||
|
||||
# This is roughly config rust-lang/rust uses for testing
|
||||
- name: Test with LLVM sysroot
|
||||
# Skip native x86_64-pc-windows-gnu. It is way too slow and cross-compiled
|
||||
# x86_64-pc-windows-gnu covers at least part of the tests.
|
||||
if: matrix.os != 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
|
||||
env:
|
||||
TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
|
||||
run: ./y.sh test --sysroot llvm --no-unstable-features
|
||||
|
|
@ -215,10 +198,6 @@ jobs:
|
|||
- os: macos-latest
|
||||
env:
|
||||
TARGET_TRIPLE: aarch64-apple-darwin
|
||||
# cross-compile from Linux to Windows using mingw
|
||||
- os: ubuntu-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-gnu
|
||||
- os: windows-latest
|
||||
env:
|
||||
TARGET_TRIPLE: x86_64-pc-windows-msvc
|
||||
|
|
@ -243,12 +222,6 @@ jobs:
|
|||
if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
|
||||
run: rustup set default-host x86_64-apple-darwin
|
||||
|
||||
- name: Install MinGW toolchain
|
||||
if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc-mingw-w64-x86-64
|
||||
|
||||
- name: Prepare dependencies
|
||||
run: ./y.sh prepare
|
||||
|
||||
|
|
@ -262,19 +235,11 @@ jobs:
|
|||
run: tar cvfJ cg_clif.tar.xz dist
|
||||
|
||||
- name: Upload prebuilt cg_clif
|
||||
if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
|
||||
path: cg_clif.tar.xz
|
||||
|
||||
- name: Upload prebuilt cg_clif (cross compile)
|
||||
if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
|
||||
path: cg_clif.tar.xz
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
|
|
|||
|
|
@ -3,28 +3,22 @@
|
|||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
|
||||
[[package]]
|
||||
name = "arbitrary"
|
||||
version = "1.3.2"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
|
||||
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
|
|
@ -37,6 +31,9 @@ name = "bumpalo"
|
|||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
@ -46,24 +43,24 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ba4f80548f22dc9c43911907b5e322c5555544ee85f785115701e6a28c9abe1"
|
||||
checksum = "ac89549be94911dd0e839b4a7db99e9ed29c17517e1c026f61066884c168aa3c"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bitset"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "005884e3649c3e5ff2dc79e8a94b138f11569cc08a91244a292714d2a86e9156"
|
||||
checksum = "b9bd49369f76c77e34e641af85d0956869237832c118964d08bf5f51f210875a"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe4036255ec33ce9a37495dfbcfc4e1118fd34e693eff9a1e106336b7cd16a9b"
|
||||
checksum = "fd96ce9cf8efebd7f5ab8ced5a0ce44250280bbae9f593d74a6d7effc3582a35"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cranelift-bforest",
|
||||
|
|
@ -74,7 +71,7 @@ dependencies = [
|
|||
"cranelift-entity",
|
||||
"cranelift-isle",
|
||||
"gimli",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.5",
|
||||
"log",
|
||||
"regalloc2",
|
||||
"rustc-hash",
|
||||
|
|
@ -85,42 +82,42 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7ca74f4b68319da11d39e894437cb6e20ec7c2e11fbbda823c3bf207beedff7"
|
||||
checksum = "5a68e358827afe4bfb6239fcbf6fbd5ac56206ece8a99c8f5f9bbd518773281a"
|
||||
dependencies = [
|
||||
"cranelift-codegen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "897e54f433a0269c4187871aa06d452214d5515d228d5bdc22219585e9eef895"
|
||||
checksum = "e184c9767afbe73d50c55ec29abcf4c32f9baf0d9d22b86d58c4d55e06dee181"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-control"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29cb4018f5bf59fb53f515fa9d80e6f8c5ce19f198dc538984ebd23ecf8965ec"
|
||||
checksum = "5cc7664f2a66f053e33f149e952bb5971d138e3af637f5097727ed6dc0ed95dd"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "305399fd781a2953ac78c1396f02ff53144f39c33eb7fc7789cf4e8936d13a96"
|
||||
checksum = "118597e3a9cf86c3556fa579a7a23b955fa18231651a52a77a2475d305a9cf84"
|
||||
dependencies = [
|
||||
"cranelift-bitset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9230b460a128d53653456137751d27baf567947a3ab8c0c4d6e31fd08036d81e"
|
||||
checksum = "7638ea1efb069a0aa18d8ee67401b6b0d19f6bfe5de5e9ede348bfc80bb0d8c7"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
|
|
@ -130,15 +127,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b961e24ae3ec9813a24a15ae64bbd2a42e4de4d79a7f3225a412e3b94e78d1c8"
|
||||
checksum = "15c53e1152a0b01c4ed2b1e0535602b8e86458777dd9d18b28732b16325c7dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62699329d4ced20fe281fbaef45e11b473b7ab310491b4bdebcd8b818a8ef7fe"
|
||||
checksum = "36972cab12ff246afe8d45b6a427669cf814bd393c661e5e8a8dedc26a81c73f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -156,9 +153,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f20b0b51ba962dac30fc7e812b86e4390d908acd4f59bcc8ac7610a8f3e0977"
|
||||
checksum = "11841b3f54ac480db1e8e8d5678ba901a13b387012d315e3f8fba3e7b7a80447"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -167,9 +164,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d5bd76df6c9151188dfa428c863b33da5b34561b67f43c0cf3f24a794f9fa1f"
|
||||
checksum = "7b7d8f895444fa52dd7bdd0bed11bf007a7fb43af65a6deac8fcc4094c6372f7"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
|
|
@ -178,9 +175,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cranelift-object"
|
||||
version = "0.114.0"
|
||||
version = "0.115.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee231640a7ecceedd0f1f2782d9288db6a6908cc70675ed9427e3bf0ea6daacd"
|
||||
checksum = "8e235ddfd19f100855ad03358c7ae0a13070c38a000701054cab46458cca6e81"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
|
|
@ -212,6 +209,12 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "foldhash"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
|
|
@ -228,31 +231,37 @@ name = "hashbrown"
|
|||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.6"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.4"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets",
|
||||
|
|
@ -281,50 +290,45 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.2"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"hashbrown",
|
||||
"hashbrown 0.15.2",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.10.2"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0"
|
||||
checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"allocator-api2",
|
||||
"bumpalo",
|
||||
"hashbrown 0.15.2",
|
||||
"log",
|
||||
"rustc-hash",
|
||||
"slice-group-by",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
|
|
@ -342,9 +346,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
|
||||
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_codegen_cranelift"
|
||||
|
|
@ -366,30 +370,24 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.210"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.210"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slice-group-by"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
|
|
@ -404,9 +402,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.70"
|
||||
version = "2.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16"
|
||||
checksum = "46f71c0377baf4ef1cc3e3402ded576dccc315800fbc62dfc7fe04b009773b4a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -421,21 +419,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-jit-icache-coherence"
|
||||
version = "27.0.0"
|
||||
version = "28.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91b218a92866f74f35162f5d03a4e0f62cd0e1cc624285b1014275e5d4575fad"
|
||||
checksum = "d40d7722b9e1fbeae135715710a8a2570b1e6cf72b74dd653962d89831c6c70d"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
|
|
@ -524,23 +516,3 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.7.35"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ crate-type = ["dylib"]
|
|||
|
||||
[dependencies]
|
||||
# These have to be in sync with each other
|
||||
cranelift-codegen = { version = "0.114.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.114.0" }
|
||||
cranelift-module = { version = "0.114.0" }
|
||||
cranelift-native = { version = "0.114.0" }
|
||||
cranelift-jit = { version = "0.114.0", optional = true }
|
||||
cranelift-object = { version = "0.114.0" }
|
||||
cranelift-codegen = { version = "0.115.0", default-features = false, features = ["std", "unwind", "all-native-arch"] }
|
||||
cranelift-frontend = { version = "0.115.0" }
|
||||
cranelift-module = { version = "0.115.0" }
|
||||
cranelift-native = { version = "0.115.0" }
|
||||
cranelift-jit = { version = "0.115.0", optional = true }
|
||||
cranelift-object = { version = "0.115.0" }
|
||||
target-lexicon = "0.12.0"
|
||||
gimli = { version = "0.31", default-features = false, features = ["write"] }
|
||||
object = { version = "0.36", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
|
||||
|
|
@ -23,6 +23,14 @@ libloading = { version = "0.8.0", optional = true }
|
|||
smallvec = "1.8.1"
|
||||
|
||||
[patch.crates-io]
|
||||
# Uncomment to use an unreleased version of cranelift
|
||||
#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
|
||||
#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
|
||||
#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
|
||||
#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
|
||||
#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
|
||||
#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-28.0.0", version = "0.115.0" }
|
||||
|
||||
# Uncomment to use local checkout of cranelift
|
||||
#cranelift-codegen = { path = "../wasmtime/cranelift/codegen" }
|
||||
#cranelift-frontend = { path = "../wasmtime/cranelift/frontend" }
|
||||
|
|
|
|||
|
|
@ -16,11 +16,7 @@ static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
|
|||
"<none>",
|
||||
);
|
||||
|
||||
pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
||||
benchmark_simple_raytracer(dirs, bootstrap_host_compiler);
|
||||
}
|
||||
|
||||
fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
||||
pub(crate) fn benchmark(dirs: &Dirs, compiler: &Compiler) {
|
||||
if std::process::Command::new("hyperfine").output().is_err() {
|
||||
eprintln!("Hyperfine not installed");
|
||||
eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine");
|
||||
|
|
@ -39,9 +35,9 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
};
|
||||
|
||||
eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
|
||||
let cargo_clif = dirs
|
||||
.dist_dir
|
||||
.join(get_file_name(&bootstrap_host_compiler.rustc, "cargo_clif", "bin").replace('_', "-"));
|
||||
let cargo_clif = &compiler.cargo;
|
||||
let rustc_clif = &compiler.rustc;
|
||||
let rustflags = &compiler.rustflags.join("\x1f");
|
||||
let manifest_path = SIMPLE_RAYTRACER_REPO.source_dir().to_path(dirs).join("Cargo.toml");
|
||||
let target_dir = dirs.build_dir.join("simple_raytracer");
|
||||
|
||||
|
|
@ -56,22 +52,24 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
target_dir = target_dir.display(),
|
||||
);
|
||||
let clif_build_cmd = format!(
|
||||
"RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif",
|
||||
"RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} && (rm build/raytracer_cg_clif || true) && ln build/simple_raytracer/debug/main build/raytracer_cg_clif",
|
||||
cargo_clif = cargo_clif.display(),
|
||||
rustc_clif = rustc_clif.display(),
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
let clif_build_opt_cmd = format!(
|
||||
"RUSTC=rustc {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt",
|
||||
"RUSTC={rustc_clif} CARGO_ENCODED_RUSTFLAGS=\"{rustflags}\" {cargo_clif} build --manifest-path {manifest_path} --target-dir {target_dir} --release && (rm build/raytracer_cg_clif_opt || true) && ln build/simple_raytracer/release/main build/raytracer_cg_clif_opt",
|
||||
cargo_clif = cargo_clif.display(),
|
||||
rustc_clif = rustc_clif.display(),
|
||||
manifest_path = manifest_path.display(),
|
||||
target_dir = target_dir.display(),
|
||||
);
|
||||
|
||||
let bench_compile_markdown = dirs.dist_dir.join("bench_compile.md");
|
||||
let bench_compile_markdown = dirs.build_dir.join("bench_compile.md");
|
||||
|
||||
let bench_compile = hyperfine_command(
|
||||
1,
|
||||
0,
|
||||
bench_runs,
|
||||
Some(&clean_cmd),
|
||||
&[
|
||||
|
|
@ -92,23 +90,14 @@ fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
|
|||
|
||||
eprintln!("[BENCH RUN] ebobby/simple-raytracer");
|
||||
|
||||
let bench_run_markdown = dirs.dist_dir.join("bench_run.md");
|
||||
let bench_run_markdown = dirs.build_dir.join("bench_run.md");
|
||||
|
||||
let raytracer_cg_llvm = Path::new(".").join(get_file_name(
|
||||
&bootstrap_host_compiler.rustc,
|
||||
"raytracer_cg_llvm",
|
||||
"bin",
|
||||
));
|
||||
let raytracer_cg_clif = Path::new(".").join(get_file_name(
|
||||
&bootstrap_host_compiler.rustc,
|
||||
"raytracer_cg_clif",
|
||||
"bin",
|
||||
));
|
||||
let raytracer_cg_clif_opt = Path::new(".").join(get_file_name(
|
||||
&bootstrap_host_compiler.rustc,
|
||||
"raytracer_cg_clif_opt",
|
||||
"bin",
|
||||
));
|
||||
let raytracer_cg_llvm =
|
||||
Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_llvm", "bin"));
|
||||
let raytracer_cg_clif =
|
||||
Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif", "bin"));
|
||||
let raytracer_cg_clif_opt =
|
||||
Path::new(".").join(get_file_name(&compiler.rustc, "raytracer_cg_clif_opt", "bin"));
|
||||
let mut bench_run = hyperfine_command(
|
||||
0,
|
||||
bench_runs,
|
||||
|
|
|
|||
|
|
@ -33,14 +33,7 @@ pub(crate) fn build_sysroot(
|
|||
let cg_clif_dylib_path = match cg_clif_dylib_src {
|
||||
CodegenBackend::Local(src_path) => {
|
||||
// Copy the backend
|
||||
let cg_clif_dylib_path = if cfg!(windows) {
|
||||
// Windows doesn't have rpath support, so the cg_clif dylib needs to be next to the
|
||||
// binaries.
|
||||
dist_dir.join("bin")
|
||||
} else {
|
||||
dist_dir.join("lib")
|
||||
}
|
||||
.join(src_path.file_name().unwrap());
|
||||
let cg_clif_dylib_path = dist_dir.join("lib").join(src_path.file_name().unwrap());
|
||||
try_hard_link(src_path, &cg_clif_dylib_path);
|
||||
CodegenBackend::Local(cg_clif_dylib_path)
|
||||
}
|
||||
|
|
@ -102,19 +95,14 @@ pub(crate) fn build_sysroot(
|
|||
.install_into_sysroot(dist_dir);
|
||||
}
|
||||
|
||||
let mut target_compiler = {
|
||||
let rustc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustc-clif"));
|
||||
let rustdoc_clif = dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif"));
|
||||
|
||||
Compiler {
|
||||
cargo: bootstrap_host_compiler.cargo.clone(),
|
||||
rustc: rustc_clif.clone(),
|
||||
rustdoc: rustdoc_clif.clone(),
|
||||
rustflags: vec![],
|
||||
rustdocflags: vec![],
|
||||
triple: target_triple,
|
||||
runner: vec![],
|
||||
}
|
||||
let mut target_compiler = Compiler {
|
||||
cargo: bootstrap_host_compiler.cargo.clone(),
|
||||
rustc: dist_dir.join(wrapper_base_name.replace("____", "rustc-clif")),
|
||||
rustdoc: dist_dir.join(wrapper_base_name.replace("____", "rustdoc-clif")),
|
||||
rustflags: vec![],
|
||||
rustdocflags: vec![],
|
||||
triple: target_triple,
|
||||
runner: vec![],
|
||||
};
|
||||
if !is_native {
|
||||
target_compiler.set_cross_linker_and_runner();
|
||||
|
|
|
|||
|
|
@ -33,23 +33,3 @@ pub(crate) fn get_bool(name: &str) -> bool {
|
|||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_value(name: &str) -> Option<String> {
|
||||
let values = load_config_file()
|
||||
.into_iter()
|
||||
.filter(|(key, _)| key == name)
|
||||
.map(|(_, val)| val)
|
||||
.collect::<Vec<_>>();
|
||||
if values.is_empty() {
|
||||
None
|
||||
} else if values.len() == 1 {
|
||||
if values[0].is_none() {
|
||||
eprintln!("Config `{}` missing value", name);
|
||||
process::exit(1);
|
||||
}
|
||||
values.into_iter().next().unwrap()
|
||||
} else {
|
||||
eprintln!("Config `{}` given multiple values: {:?}", name, values);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,10 +156,8 @@ fn main() {
|
|||
let cargo = rustc_info::get_cargo_path();
|
||||
let rustc = rustc_info::get_rustc_path();
|
||||
let rustdoc = rustc_info::get_rustdoc_path();
|
||||
let triple = std::env::var("HOST_TRIPLE")
|
||||
.ok()
|
||||
.or_else(|| config::get_value("host"))
|
||||
.unwrap_or_else(|| rustc_info::get_host_triple(&rustc));
|
||||
let triple =
|
||||
std::env::var("HOST_TRIPLE").unwrap_or_else(|_| rustc_info::get_host_triple(&rustc));
|
||||
Compiler {
|
||||
cargo,
|
||||
rustc,
|
||||
|
|
@ -170,10 +168,8 @@ fn main() {
|
|||
runner: vec![],
|
||||
}
|
||||
};
|
||||
let target_triple = std::env::var("TARGET_TRIPLE")
|
||||
.ok()
|
||||
.or_else(|| config::get_value("target"))
|
||||
.unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
|
||||
let target_triple =
|
||||
std::env::var("TARGET_TRIPLE").unwrap_or_else(|_| bootstrap_host_compiler.triple.clone());
|
||||
|
||||
let dirs = path::Dirs {
|
||||
source_dir: current_dir.clone(),
|
||||
|
|
@ -247,7 +243,7 @@ fn main() {
|
|||
);
|
||||
}
|
||||
Command::Bench => {
|
||||
build_sysroot::build_sysroot(
|
||||
let compiler = build_sysroot::build_sysroot(
|
||||
&dirs,
|
||||
sysroot_kind,
|
||||
&cg_clif_dylib,
|
||||
|
|
@ -255,7 +251,7 @@ fn main() {
|
|||
rustup_toolchain_name.as_deref(),
|
||||
target_triple,
|
||||
);
|
||||
bench::benchmark(&dirs, &bootstrap_host_compiler);
|
||||
bench::benchmark(&dirs, &compiler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,20 +11,11 @@ pub(crate) struct Dirs {
|
|||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) enum PathBase {
|
||||
enum PathBase {
|
||||
Source,
|
||||
Build,
|
||||
}
|
||||
|
||||
impl PathBase {
|
||||
fn to_path(self, dirs: &Dirs) -> PathBuf {
|
||||
match self {
|
||||
PathBase::Source => dirs.source_dir.clone(),
|
||||
PathBase::Build => dirs.build_dir.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) struct RelPath {
|
||||
base: PathBase,
|
||||
|
|
@ -41,6 +32,9 @@ impl RelPath {
|
|||
}
|
||||
|
||||
pub(crate) fn to_path(&self, dirs: &Dirs) -> PathBuf {
|
||||
self.base.to_path(dirs).join(self.suffix)
|
||||
match self.base {
|
||||
PathBase::Source => dirs.source_dir.join(self.suffix),
|
||||
PathBase::Build => dirs.build_dir.join(self.suffix),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
"example/arbitrary_self_types_pointers_and_wrappers.rs",
|
||||
&[],
|
||||
),
|
||||
TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
|
||||
TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
|
||||
TestCase::jit_bin("jit.std_example", "example/std_example.rs", "arg"),
|
||||
TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
|
||||
TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
|
||||
|
|
@ -89,7 +87,6 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
&[],
|
||||
),
|
||||
TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
|
||||
TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
|
||||
TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
|
||||
TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
|
||||
TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]),
|
||||
|
|
|
|||
|
|
@ -1,15 +1,5 @@
|
|||
# This file allows configuring the build system.
|
||||
|
||||
# Which triple to produce a compiler toolchain for.
|
||||
#
|
||||
# Defaults to the default triple of rustc on the host system.
|
||||
#host = x86_64-unknown-linux-gnu
|
||||
|
||||
# Which triple to build libraries (core/alloc/std/test/proc_macro) for.
|
||||
#
|
||||
# Defaults to `host`.
|
||||
#target = x86_64-unknown-linux-gnu
|
||||
|
||||
# Disables cleaning of the sysroot dir. This will cause old compiled artifacts to be re-used when
|
||||
# the sysroot source hasn't changed. This is useful when the codegen backend hasn't been modified.
|
||||
# This option can be changed while the build system is already running for as long as sysroot
|
||||
|
|
@ -31,15 +21,12 @@ aot.mini_core_hello_world
|
|||
testsuite.base_sysroot
|
||||
aot.arbitrary_self_types_pointers_and_wrappers
|
||||
aot.issue_91827_extern_types
|
||||
build.alloc_system
|
||||
aot.alloc_example
|
||||
jit.std_example
|
||||
aot.std_example
|
||||
aot.dst_field_align
|
||||
aot.subslice-patterns-const-eval
|
||||
aot.track-caller-attribute
|
||||
aot.float-minmax-pass
|
||||
aot.mod_bench
|
||||
aot.issue-72793
|
||||
aot.issue-59326
|
||||
aot.neon
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
#![feature(start, core_intrinsics, alloc_error_handler, lang_items)]
|
||||
#![allow(internal_features)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate alloc_system;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
||||
use alloc_system::System;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOC: System = System;
|
||||
|
||||
#[cfg_attr(unix, link(name = "c"))]
|
||||
#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
|
||||
extern "C" {
|
||||
fn puts(s: *const u8) -> i32;
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
let world: Box<&str> = Box::new("Hello World!\0");
|
||||
unsafe {
|
||||
puts(*world as *const str as *const u8);
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
// SPDX-License-Identifier: MIT OR Apache-2.0
|
||||
// SPDX-FileCopyrightText: The Rust Project Developers (see https://thanks.rust-lang.org)
|
||||
|
||||
#![no_std]
|
||||
|
||||
pub struct System;
|
||||
|
||||
#[cfg(any(windows, unix, target_os = "redox"))]
|
||||
mod realloc_fallback {
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::{cmp, ptr};
|
||||
impl super::System {
|
||||
pub(crate) unsafe fn realloc_fallback(
|
||||
&self,
|
||||
ptr: *mut u8,
|
||||
old_layout: Layout,
|
||||
new_size: usize,
|
||||
) -> *mut u8 {
|
||||
// Docs for GlobalAlloc::realloc require this to be valid:
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
|
||||
let new_ptr = GlobalAlloc::alloc(self, new_layout);
|
||||
if !new_ptr.is_null() {
|
||||
let size = cmp::min(old_layout.size(), new_size);
|
||||
ptr::copy_nonoverlapping(ptr, new_ptr, size);
|
||||
GlobalAlloc::dealloc(self, ptr, old_layout);
|
||||
}
|
||||
new_ptr
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(any(unix, target_os = "redox"))]
|
||||
mod platform {
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
use core::ffi::c_void;
|
||||
use core::ptr;
|
||||
|
||||
use System;
|
||||
extern "C" {
|
||||
fn posix_memalign(memptr: *mut *mut c_void, align: usize, size: usize) -> i32;
|
||||
fn free(p: *mut c_void);
|
||||
}
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
aligned_malloc(&layout)
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
let ptr = self.alloc(layout.clone());
|
||||
if !ptr.is_null() {
|
||||
ptr::write_bytes(ptr, 0, layout.size());
|
||||
}
|
||||
ptr
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
free(ptr as *mut c_void)
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
self.realloc_fallback(ptr, layout, new_size)
|
||||
}
|
||||
}
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
let mut out = ptr::null_mut();
|
||||
let ret = posix_memalign(&mut out, layout.align(), layout.size());
|
||||
if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
#[allow(nonstandard_style)]
|
||||
mod platform {
|
||||
use core::alloc::{GlobalAlloc, Layout};
|
||||
|
||||
use System;
|
||||
type LPVOID = *mut u8;
|
||||
type HANDLE = LPVOID;
|
||||
type SIZE_T = usize;
|
||||
type DWORD = u32;
|
||||
type BOOL = i32;
|
||||
extern "system" {
|
||||
fn GetProcessHeap() -> HANDLE;
|
||||
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
|
||||
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
|
||||
fn GetLastError() -> DWORD;
|
||||
}
|
||||
#[repr(C)]
|
||||
struct Header(*mut u8);
|
||||
const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
|
||||
unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
|
||||
&mut *(ptr as *mut Header).sub(1)
|
||||
}
|
||||
unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
|
||||
let aligned = ptr.add(align - (ptr as usize & (align - 1)));
|
||||
*get_header(aligned) = Header(ptr);
|
||||
aligned
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
|
||||
let size = layout.size() + layout.align();
|
||||
let ptr = HeapAlloc(GetProcessHeap(), flags, size);
|
||||
(if ptr.is_null() { ptr } else { align_ptr(ptr, layout.align()) }) as *mut u8
|
||||
}
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
allocate_with_flags(layout, 0)
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
allocate_with_flags(layout, HEAP_ZERO_MEMORY)
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
let header = get_header(ptr);
|
||||
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
|
||||
debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
self.realloc_fallback(ptr, layout, new_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#![feature(start, core_intrinsics, lang_items)]
|
||||
#![allow(internal_features)]
|
||||
#![no_std]
|
||||
|
||||
#[cfg_attr(unix, link(name = "c"))]
|
||||
#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
|
||||
extern "C" {}
|
||||
|
||||
#[panic_handler]
|
||||
fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
fn eh_personality() {}
|
||||
|
||||
// Required for rustc_codegen_llvm
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _Unwind_Resume() {
|
||||
core::intrinsics::unreachable();
|
||||
}
|
||||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
for i in 2..10_000_000 {
|
||||
black_box((i + 1) % i);
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn black_box(i: u32) {
|
||||
if i != 1 {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Shim for bcryptprimitives.dll. The Wine version shipped with Ubuntu 22.04
|
||||
// doesn't support it yet. Authored by @ChrisDenton
|
||||
|
||||
#![crate_type = "cdylib"]
|
||||
#![allow(nonstandard_style)]
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn ProcessPrng(mut pbData: *mut u8, mut cbData: usize) -> i32 {
|
||||
while cbData > 0 {
|
||||
let size = core::cmp::min(cbData, u32::MAX as usize);
|
||||
RtlGenRandom(pbData, size as u32);
|
||||
cbData -= size;
|
||||
pbData = pbData.add(size);
|
||||
}
|
||||
1
|
||||
}
|
||||
|
||||
#[link(name = "advapi32")]
|
||||
extern "system" {
|
||||
#[link_name = "SystemFunction036"]
|
||||
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-12-06"
|
||||
channel = "nightly-2025-01-10"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools"]
|
||||
profile = "minimal"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ fn main() {
|
|||
if let Some(name) = option_env!("BUILTIN_BACKEND") {
|
||||
rustflags.push(format!("-Zcodegen-backend={name}"));
|
||||
} else {
|
||||
let dylib = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
|
||||
let dylib = sysroot.join("lib").join(
|
||||
env::consts::DLL_PREFIX.to_string()
|
||||
+ "rustc_codegen_cranelift"
|
||||
+ env::consts::DLL_SUFFIX,
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ fn main() {
|
|||
sysroot = sysroot.parent().unwrap();
|
||||
}
|
||||
|
||||
let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
|
||||
let cg_clif_dylib_path = sysroot.join("lib").join(
|
||||
env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ fn main() {
|
|||
sysroot = sysroot.parent().unwrap();
|
||||
}
|
||||
|
||||
let cg_clif_dylib_path = sysroot.join(if cfg!(windows) { "bin" } else { "lib" }).join(
|
||||
let cg_clif_dylib_path = sysroot.join("lib").join(
|
||||
env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,11 @@ rm tests/ui/abi/large-byval-align.rs # exceeds implementation limit of Cranelift
|
|||
# should work when using ./x.py test the way it is intended
|
||||
# ============================================================
|
||||
rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
|
||||
rm -r tests/run-make/strip # same
|
||||
rm -r tests/run-make/compiler-builtins # Expects lib/rustlib/src/rust to contains the standard library source
|
||||
rm -r tests/run-make/missing-unstable-trait-bound # This disables support for unstable features, but running cg_clif needs some unstable features
|
||||
rm -r tests/run-make/const-trait-stable-toolchain # same
|
||||
rm -r tests/run-make/incr-add-rust-src-component
|
||||
|
||||
# genuine bugs
|
||||
# ============
|
||||
|
|
@ -196,5 +200,5 @@ index e7ae773ffa1d3..04bc2d7787da7 100644
|
|||
EOF
|
||||
|
||||
echo "[TEST] rustc test suite"
|
||||
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,ui,incremental}
|
||||
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
|
||||
popd
|
||||
|
|
|
|||
|
|
@ -62,9 +62,8 @@ pub(crate) fn maybe_codegen<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn maybe_codegen_checked<'tcx>(
|
||||
pub(crate) fn maybe_codegen_mul_checked<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
bin_op: BinOp,
|
||||
lhs: CValue<'tcx>,
|
||||
rhs: CValue<'tcx>,
|
||||
) -> Option<CValue<'tcx>> {
|
||||
|
|
@ -78,32 +77,19 @@ pub(crate) fn maybe_codegen_checked<'tcx>(
|
|||
|
||||
let is_signed = type_sign(lhs.layout().ty);
|
||||
|
||||
match bin_op {
|
||||
BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
|
||||
BinOp::Add | BinOp::Sub => None,
|
||||
BinOp::Mul => {
|
||||
let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
|
||||
let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
|
||||
let param_types = vec![
|
||||
AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
|
||||
AbiParam::new(types::I128),
|
||||
AbiParam::new(types::I128),
|
||||
];
|
||||
let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
fx.lib_call(
|
||||
if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" },
|
||||
param_types,
|
||||
vec![],
|
||||
&args,
|
||||
);
|
||||
Some(out_place.to_cvalue(fx))
|
||||
}
|
||||
BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
|
||||
BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
|
||||
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
|
||||
BinOp::Div | BinOp::Rem => unreachable!(),
|
||||
BinOp::Cmp => unreachable!(),
|
||||
BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
|
||||
BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => unreachable!(),
|
||||
}
|
||||
let out_ty = Ty::new_tup(fx.tcx, &[lhs.layout().ty, fx.tcx.types.bool]);
|
||||
let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
|
||||
let param_types = vec![
|
||||
AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
|
||||
AbiParam::new(types::I128),
|
||||
AbiParam::new(types::I128),
|
||||
];
|
||||
let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
|
||||
fx.lib_call(
|
||||
if is_signed { "__rust_i128_mulo" } else { "__rust_u128_mulo" },
|
||||
param_types,
|
||||
vec![],
|
||||
&args,
|
||||
);
|
||||
Some(out_place.to_cvalue(fx))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -333,10 +333,9 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
|
|||
|
||||
let mut builder =
|
||||
ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
|
||||
// Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
|
||||
// is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
|
||||
// can easily double the amount of time necessary to perform linking.
|
||||
builder.per_function_section(sess.opts.unstable_opts.function_sections.unwrap_or(false));
|
||||
builder.per_function_section(
|
||||
sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections),
|
||||
);
|
||||
UnwindModule::new(ObjectModule::new(builder), true)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ fn dep_symbol_lookup_fn(
|
|||
|
||||
let mut dylib_paths = Vec::new();
|
||||
|
||||
let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable].1;
|
||||
let data = &crate_info.dependency_formats[&rustc_session::config::CrateType::Executable];
|
||||
// `used_crates` is in reverse postorder in terms of dependencies. Reverse the order here to
|
||||
// get a postorder which ensures that all dependencies of a dylib are loaded before the dylib
|
||||
// itself. This helps the dynamic linker to find dylibs not in the regular dynamic library
|
||||
|
|
|
|||
|
|
@ -73,12 +73,14 @@ impl Drop for TimingGuard {
|
|||
|
||||
impl cranelift_codegen::timing::Profiler for MeasuremeProfiler {
|
||||
fn start_pass(&self, pass: cranelift_codegen::timing::Pass) -> Box<dyn std::any::Any> {
|
||||
let mut timing_guard =
|
||||
TimingGuard { profiler: std::mem::ManuallyDrop::new(self.0.clone()), inner: None };
|
||||
let mut timing_guard = Box::new(TimingGuard {
|
||||
profiler: std::mem::ManuallyDrop::new(self.0.clone()),
|
||||
inner: None,
|
||||
});
|
||||
timing_guard.inner = Some(
|
||||
unsafe { &*(&*timing_guard.profiler as &SelfProfilerRef as *const SelfProfilerRef) }
|
||||
.generic_activity(pass.description()),
|
||||
);
|
||||
Box::new(timing_guard)
|
||||
timing_guard
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
|
|||
fx.bcx.ins().jump(destination_block, &[]);
|
||||
}
|
||||
None => {
|
||||
fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap());
|
||||
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1136,7 +1136,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
|
|||
_ => {
|
||||
fx.tcx.dcx().span_err(span, format!("Unknown SIMD intrinsic {}", intrinsic));
|
||||
// Prevent verifier error
|
||||
fx.bcx.ins().trap(TrapCode::user(0 /* unreachable */).unwrap());
|
||||
fx.bcx.ins().trap(TrapCode::user(1 /* unreachable */).unwrap());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ extern crate rustc_metadata;
|
|||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
extern crate rustc_target;
|
||||
#[macro_use]
|
||||
extern crate tracing;
|
||||
|
||||
// This prevents duplicating functions and statics that are already part of the host rustc process.
|
||||
#[allow(unused_extern_crates)]
|
||||
|
|
@ -208,6 +210,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
tcx.dcx().abort_if_errors();
|
||||
info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE));
|
||||
let config = self.config.clone().unwrap_or_else(|| {
|
||||
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
|
||||
.unwrap_or_else(|err| tcx.sess.dcx().fatal(err))
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
|
||||
pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> IntCC {
|
||||
use BinOp::*;
|
||||
use IntCC::*;
|
||||
Some(match bin_op {
|
||||
match bin_op {
|
||||
Eq => Equal,
|
||||
Lt => {
|
||||
if signed {
|
||||
|
|
@ -36,8 +36,8 @@ pub(crate) fn bin_op_to_intcc(bin_op: BinOp, signed: bool) -> Option<IntCC> {
|
|||
UnsignedGreaterThan
|
||||
}
|
||||
}
|
||||
_ => return None,
|
||||
})
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn codegen_three_way_compare<'tcx>(
|
||||
|
|
@ -48,8 +48,8 @@ fn codegen_three_way_compare<'tcx>(
|
|||
) -> CValue<'tcx> {
|
||||
// This emits `(lhs > rhs) - (lhs < rhs)`, which is cranelift's preferred form per
|
||||
// <https://github.com/bytecodealliance/wasmtime/blob/8052bb9e3b792503b225f2a5b2ba3bc023bff462/cranelift/codegen/src/prelude_opt.isle#L41-L47>
|
||||
let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed).unwrap();
|
||||
let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed).unwrap();
|
||||
let gt_cc = crate::num::bin_op_to_intcc(BinOp::Gt, signed);
|
||||
let lt_cc = crate::num::bin_op_to_intcc(BinOp::Lt, signed);
|
||||
let gt = fx.bcx.ins().icmp(gt_cc, lhs, rhs);
|
||||
let lt = fx.bcx.ins().icmp(lt_cc, lhs, rhs);
|
||||
let val = fx.bcx.ins().isub(gt, lt);
|
||||
|
|
@ -63,11 +63,7 @@ fn codegen_compare_bin_op<'tcx>(
|
|||
lhs: Value,
|
||||
rhs: Value,
|
||||
) -> CValue<'tcx> {
|
||||
if bin_op == BinOp::Cmp {
|
||||
return codegen_three_way_compare(fx, signed, lhs, rhs);
|
||||
}
|
||||
|
||||
let intcc = crate::num::bin_op_to_intcc(bin_op, signed).unwrap();
|
||||
let intcc = crate::num::bin_op_to_intcc(bin_op, signed);
|
||||
let val = fx.bcx.ins().icmp(intcc, lhs, rhs);
|
||||
CValue::by_val(val, fx.layout_of(fx.tcx.types.bool))
|
||||
}
|
||||
|
|
@ -79,7 +75,7 @@ pub(crate) fn codegen_binop<'tcx>(
|
|||
in_rhs: CValue<'tcx>,
|
||||
) -> CValue<'tcx> {
|
||||
match bin_op {
|
||||
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt | BinOp::Cmp => {
|
||||
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
|
||||
match in_lhs.layout().ty.kind() {
|
||||
ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
|
||||
let signed = type_sign(in_lhs.layout().ty);
|
||||
|
|
@ -91,6 +87,16 @@ pub(crate) fn codegen_binop<'tcx>(
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
BinOp::Cmp => match in_lhs.layout().ty.kind() {
|
||||
ty::Bool | ty::Uint(_) | ty::Int(_) | ty::Char => {
|
||||
let signed = type_sign(in_lhs.layout().ty);
|
||||
let lhs = in_lhs.load_scalar(fx);
|
||||
let rhs = in_rhs.load_scalar(fx);
|
||||
|
||||
return codegen_three_way_compare(fx, signed, lhs, rhs);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
@ -200,10 +206,6 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
|
|||
let lhs = in_lhs.load_scalar(fx);
|
||||
let rhs = in_rhs.load_scalar(fx);
|
||||
|
||||
if let Some(res) = crate::codegen_i128::maybe_codegen_checked(fx, bin_op, in_lhs, in_rhs) {
|
||||
return res;
|
||||
}
|
||||
|
||||
let signed = type_sign(in_lhs.layout().ty);
|
||||
|
||||
let (res, has_overflow) = match bin_op {
|
||||
|
|
@ -236,6 +238,10 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
|
|||
(val, has_overflow)
|
||||
}
|
||||
BinOp::Mul => {
|
||||
if let Some(res) = crate::codegen_i128::maybe_codegen_mul_checked(fx, in_lhs, in_rhs) {
|
||||
return res;
|
||||
}
|
||||
|
||||
let ty = fx.bcx.func.dfg.value_type(lhs);
|
||||
match ty {
|
||||
types::I8 | types::I16 | types::I32 if !signed => {
|
||||
|
|
@ -357,14 +363,12 @@ pub(crate) fn codegen_float_binop<'tcx>(
|
|||
_ => bug!(),
|
||||
};
|
||||
|
||||
let ret_val = fx.lib_call(
|
||||
fx.lib_call(
|
||||
name,
|
||||
vec![AbiParam::new(ty), AbiParam::new(ty)],
|
||||
vec![AbiParam::new(ty)],
|
||||
&[lhs, rhs],
|
||||
)[0];
|
||||
|
||||
return CValue::by_val(ret_val, in_lhs.layout());
|
||||
)[0]
|
||||
}
|
||||
BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => {
|
||||
let fltcc = match bin_op {
|
||||
|
|
@ -431,13 +435,9 @@ pub(crate) fn codegen_ptr_binop<'tcx>(
|
|||
BinOp::Lt | BinOp::Le | BinOp::Ge | BinOp::Gt => {
|
||||
let ptr_eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_ptr, rhs_ptr);
|
||||
|
||||
let ptr_cmp =
|
||||
fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false).unwrap(), lhs_ptr, rhs_ptr);
|
||||
let extra_cmp = fx.bcx.ins().icmp(
|
||||
bin_op_to_intcc(bin_op, false).unwrap(),
|
||||
lhs_extra,
|
||||
rhs_extra,
|
||||
);
|
||||
let ptr_cmp = fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false), lhs_ptr, rhs_ptr);
|
||||
let extra_cmp =
|
||||
fx.bcx.ins().icmp(bin_op_to_intcc(bin_op, false), lhs_extra, rhs_extra);
|
||||
|
||||
fx.bcx.ins().select(ptr_eq, extra_cmp, ptr_cmp)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ fn inline_attr<'gcc, 'tcx>(
|
|||
) -> Option<FnAttribute<'gcc>> {
|
||||
match inline {
|
||||
InlineAttr::Hint => Some(FnAttribute::Inline),
|
||||
InlineAttr::Always => Some(FnAttribute::AlwaysInline),
|
||||
InlineAttr::Always | InlineAttr::Force { .. } => Some(FnAttribute::AlwaysInline),
|
||||
InlineAttr::Never => {
|
||||
if cx.sess().target.arch != "amdgpu" {
|
||||
Some(FnAttribute::NoInline)
|
||||
|
|
|
|||
|
|
@ -660,9 +660,7 @@ pub unsafe fn optimize_thin_module(
|
|||
{
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
|
||||
if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
|
||||
return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule));
|
||||
}
|
||||
unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) };
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use gccjit::{Location, RValue};
|
|||
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
|
||||
use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoCodegenMethods};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::mir::{self, Body, SourceScope};
|
||||
use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
|
||||
|
|
@ -69,7 +69,7 @@ fn compute_mir_scopes<'gcc, 'tcx>(
|
|||
) {
|
||||
// Find all scopes with variables defined in them.
|
||||
let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
|
||||
let mut vars = BitSet::new_empty(mir.source_scopes.len());
|
||||
let mut vars = DenseBitSet::new_empty(mir.source_scopes.len());
|
||||
// FIXME(eddyb) take into account that arguments always have debuginfo,
|
||||
// irrespective of their name (assuming full debuginfo is enabled).
|
||||
// NOTE(eddyb) actually, on second thought, those are always in the
|
||||
|
|
@ -82,7 +82,7 @@ fn compute_mir_scopes<'gcc, 'tcx>(
|
|||
// Nothing to emit, of course.
|
||||
None
|
||||
};
|
||||
let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
|
||||
let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len());
|
||||
// Instantiate all scopes.
|
||||
for idx in 0..mir.source_scopes.len() {
|
||||
let scope = SourceScope::new(idx);
|
||||
|
|
@ -101,9 +101,9 @@ fn make_mir_scope<'gcc, 'tcx>(
|
|||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
_instance: Instance<'tcx>,
|
||||
mir: &Body<'tcx>,
|
||||
variables: &Option<BitSet<SourceScope>>,
|
||||
variables: &Option<DenseBitSet<SourceScope>>,
|
||||
debug_context: &mut FunctionDebugContext<'tcx, (), Location<'gcc>>,
|
||||
instantiated: &mut BitSet<SourceScope>,
|
||||
instantiated: &mut DenseBitSet<SourceScope>,
|
||||
scope: SourceScope,
|
||||
) {
|
||||
if instantiated.contains(scope) {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
|
|||
#[diag(codegen_gcc_forbidden_ctarget_feature)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use std::iter::FromIterator;
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
use gccjit::Context;
|
||||
use rustc_codegen_ssa::codegen_attrs::check_tied_features;
|
||||
use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::bug;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
|
@ -37,82 +39,137 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
let mut features = vec![];
|
||||
|
||||
// Features implied by an implicit or explicit `--target`.
|
||||
features.extend(
|
||||
sess.target
|
||||
.features
|
||||
.split(',')
|
||||
.filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
|
||||
.map(String::from),
|
||||
);
|
||||
features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from));
|
||||
|
||||
// -Ctarget-features
|
||||
let known_features = sess.target.rust_target_features();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
let feats = sess
|
||||
.opts
|
||||
.cg
|
||||
.target_feature
|
||||
.split(',')
|
||||
.filter_map(|s| {
|
||||
let enable_disable = match s.chars().next() {
|
||||
None => return None,
|
||||
Some(c @ ('+' | '-')) => c,
|
||||
Some(_) => {
|
||||
if diagnostics {
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the backend feature name, if any.
|
||||
// This excludes rustc-specific features, that do not get passed down to GCC.
|
||||
let feature = backend_feature_name(s)?;
|
||||
// Warn against use of GCC specific feature names on the CLI.
|
||||
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
||||
// are disabled.
|
||||
let abi_feature_constraints = sess.target.abi_required_features();
|
||||
let abi_incompatible_set =
|
||||
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
|
||||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
|
||||
.to_sorted_stable_ord()
|
||||
.iter()
|
||||
.map(|&&s| (true, s)),
|
||||
)
|
||||
} else if let Some(feature) = feature.strip_prefix('-') {
|
||||
// FIXME: Why do we not remove implied features on "-" here?
|
||||
// We do the equivalent above in `target_features_cfg`.
|
||||
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||
all_rust_features.push((false, feature));
|
||||
} else if !feature.is_empty() {
|
||||
if diagnostics {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature =
|
||||
known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let gcc_features = to_gcc_features(sess, rust_feature);
|
||||
if gcc_features.contains(&feature)
|
||||
&& !gcc_features.contains(&rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) =
|
||||
stability.toggle_allowed(&sess.target, enable_disable == '+')
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove features that are meant for rustc, not codegen.
|
||||
all_rust_features.retain(|(_, feature)| {
|
||||
// Retain if it is not a rustc feature
|
||||
!RUSTC_SPECIFIC_FEATURES.contains(feature)
|
||||
});
|
||||
|
||||
// Check feature validity.
|
||||
if diagnostics {
|
||||
for &(enable, feature) in &all_rust_features {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature = known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let gcc_features = to_gcc_features(sess, rust_feature);
|
||||
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature)
|
||||
{
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. (It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above).
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. (It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above).
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable_disable == '+');
|
||||
}
|
||||
|
||||
// ... otherwise though we run through `to_gcc_features` when
|
||||
// Ensure that the features we enable/disable are compatible with the ABI.
|
||||
if enable {
|
||||
if abi_incompatible_set.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "enabled",
|
||||
reason: "this feature is incompatible with the target ABI",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// FIXME: we have to request implied features here since
|
||||
// negative features do not handle implied features above.
|
||||
for &required in abi_feature_constraints.required.iter() {
|
||||
let implied = sess.target.implied_target_features(std::iter::once(required));
|
||||
if implied.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "disabled",
|
||||
reason: "this feature is required by the target ABI",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable);
|
||||
}
|
||||
}
|
||||
|
||||
// To be sure the ABI-relevant features are all in the right state, we explicitly
|
||||
// (un)set them here. This means if the target spec sets those features wrong,
|
||||
// we will silently correct them rather than silently producing wrong code.
|
||||
// (The target sanity check tries to catch this, but we can't know which features are
|
||||
// enabled in GCC by default so we can't be fully sure about that check.)
|
||||
// We add these at the beginning of the list so that `-Ctarget-features` can
|
||||
// still override it... that's unsound, but more compatible with past behavior.
|
||||
all_rust_features.splice(
|
||||
0..0,
|
||||
abi_feature_constraints
|
||||
.required
|
||||
.iter()
|
||||
.map(|&f| (true, f))
|
||||
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
|
||||
);
|
||||
|
||||
// Translate this into GCC features.
|
||||
let feats = all_rust_features
|
||||
.iter()
|
||||
.filter_map(|&(enable, feature)| {
|
||||
let enable_disable = if enable { '+' } else { '-' };
|
||||
// We run through `to_gcc_features` when
|
||||
// passing requests down to GCC. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
// different names when the GCC name and the Rust name differ.
|
||||
|
|
@ -146,26 +203,12 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
features
|
||||
}
|
||||
|
||||
/// Returns a feature name for the given `+feature` or `-feature` string.
|
||||
///
|
||||
/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
|
||||
fn backend_feature_name(s: &str) -> Option<&str> {
|
||||
// features must start with a `+` or `-`.
|
||||
let feature = s.strip_prefix(&['+', '-'][..]).unwrap_or_else(|| {
|
||||
bug!("target feature `{}` must begin with a `+` or `-`", s);
|
||||
});
|
||||
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
|
||||
// are not passed down to GCC.
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
Some(feature)
|
||||
}
|
||||
|
||||
// To find a list of GCC's names, check https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||
pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
|
||||
let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
|
||||
match (arch, s) {
|
||||
// FIXME: seems like x87 does not exist?
|
||||
("x86", "x87") => smallvec![],
|
||||
("x86", "sse4.2") => smallvec!["sse4.2", "crc32"],
|
||||
("x86", "pclmulqdq") => smallvec!["pclmul"],
|
||||
("x86", "rdrand") => smallvec!["rdrnd"],
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ test = false
|
|||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
bitflags = "2.4.1"
|
||||
gimli = "0.30"
|
||||
itertools = "0.12"
|
||||
libc = "0.2"
|
||||
measureme = "11"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ codegen_llvm_dynamic_linking_with_lto =
|
|||
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||
|
||||
codegen_llvm_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
|
||||
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
|
||||
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
|
|
@ -24,8 +24,6 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two =
|
|||
codegen_llvm_invalid_minimum_alignment_too_large =
|
||||
invalid minimum global alignment: {$align} is too large
|
||||
|
||||
codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`"
|
||||
|
||||
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
|
||||
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,9 @@ fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll
|
|||
}
|
||||
match inline {
|
||||
InlineAttr::Hint => Some(AttributeKind::InlineHint.create_attr(cx.llcx)),
|
||||
InlineAttr::Always => Some(AttributeKind::AlwaysInline.create_attr(cx.llcx)),
|
||||
InlineAttr::Always | InlineAttr::Force { .. } => {
|
||||
Some(AttributeKind::AlwaysInline.create_attr(cx.llcx))
|
||||
}
|
||||
InlineAttr::Never => {
|
||||
if cx.sess().target.arch != "amdgpu" {
|
||||
Some(AttributeKind::NoInline.create_attr(cx.llcx))
|
||||
|
|
@ -472,7 +474,11 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
|
|||
let allocated_pointer = AttributeKind::AllocatedPointer.create_attr(cx.llcx);
|
||||
attributes::apply_to_llfn(llfn, AttributePlace::Argument(0), &[allocated_pointer]);
|
||||
}
|
||||
if let Some(align) = codegen_fn_attrs.alignment {
|
||||
// function alignment can be set globally with the `-Zmin-function-alignment=<n>` flag;
|
||||
// the alignment from a `#[repr(align(<n>))]` is used if it specifies a higher alignment.
|
||||
if let Some(align) =
|
||||
Ord::max(cx.tcx.sess.opts.unstable_opts.min_function_alignment, codegen_fn_attrs.alignment)
|
||||
{
|
||||
llvm::set_alignment(llfn, align);
|
||||
}
|
||||
if let Some(backchain) = backchain_attr(cx) {
|
||||
|
|
|
|||
|
|
@ -737,11 +737,7 @@ pub(crate) unsafe fn optimize_thin_module(
|
|||
{
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
|
||||
if unsafe {
|
||||
!llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target)
|
||||
} {
|
||||
return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule));
|
||||
}
|
||||
unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) };
|
||||
save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
|
|||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::mir::{Body, SourceScope};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
|
||||
use rustc_middle::ty::{self, Instance};
|
||||
|
|
@ -27,7 +27,7 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
|
|||
) {
|
||||
// Find all scopes with variables defined in them.
|
||||
let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
|
||||
let mut vars = BitSet::new_empty(mir.source_scopes.len());
|
||||
let mut vars = DenseBitSet::new_empty(mir.source_scopes.len());
|
||||
// FIXME(eddyb) take into account that arguments always have debuginfo,
|
||||
// irrespective of their name (assuming full debuginfo is enabled).
|
||||
// NOTE(eddyb) actually, on second thought, those are always in the
|
||||
|
|
@ -40,7 +40,7 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
|
|||
// Nothing to emit, of course.
|
||||
None
|
||||
};
|
||||
let mut instantiated = BitSet::new_empty(mir.source_scopes.len());
|
||||
let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len());
|
||||
let mut discriminators = FxHashMap::default();
|
||||
// Instantiate all scopes.
|
||||
for idx in 0..mir.source_scopes.len() {
|
||||
|
|
@ -63,9 +63,9 @@ fn make_mir_scope<'ll, 'tcx>(
|
|||
cx: &CodegenCx<'ll, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
mir: &Body<'tcx>,
|
||||
variables: &Option<BitSet<SourceScope>>,
|
||||
variables: &Option<DenseBitSet<SourceScope>>,
|
||||
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>,
|
||||
instantiated: &mut BitSet<SourceScope>,
|
||||
instantiated: &mut DenseBitSet<SourceScope>,
|
||||
discriminators: &mut FxHashMap<BytePos, u32>,
|
||||
scope: SourceScope,
|
||||
) {
|
||||
|
|
|
|||
37
compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
Normal file
37
compiler/rustc_codegen_llvm/src/debuginfo/dwarf_const.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
//! Definitions of various DWARF-related constants.
|
||||
|
||||
use libc::c_uint;
|
||||
|
||||
/// Helper macro to let us redeclare gimli's constants as our own constants
|
||||
/// with a different type, with less risk of copy-paste errors.
|
||||
macro_rules! declare_constant {
|
||||
(
|
||||
$name:ident : $type:ty
|
||||
) => {
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub(crate) const $name: $type = ::gimli::constants::$name.0 as $type;
|
||||
|
||||
// Assert that as-cast probably hasn't changed the value.
|
||||
const _: () = assert!($name as i128 == ::gimli::constants::$name.0 as i128);
|
||||
};
|
||||
}
|
||||
|
||||
declare_constant!(DW_TAG_const_type: c_uint);
|
||||
|
||||
// DWARF languages.
|
||||
declare_constant!(DW_LANG_Rust: c_uint);
|
||||
|
||||
// DWARF attribute type encodings.
|
||||
declare_constant!(DW_ATE_boolean: c_uint);
|
||||
declare_constant!(DW_ATE_float: c_uint);
|
||||
declare_constant!(DW_ATE_signed: c_uint);
|
||||
declare_constant!(DW_ATE_unsigned: c_uint);
|
||||
declare_constant!(DW_ATE_UTF: c_uint);
|
||||
|
||||
// DWARF expression operators.
|
||||
declare_constant!(DW_OP_deref: u64);
|
||||
declare_constant!(DW_OP_plus_uconst: u64);
|
||||
/// Defined by LLVM in `llvm/include/llvm/BinaryFormat/Dwarf.h`.
|
||||
/// Double-checked by a static assertion in `RustWrapper.cpp`.
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub(crate) const DW_OP_LLVM_fragment: u64 = 0x1000;
|
||||
|
|
@ -22,6 +22,7 @@ use rustc_target::spec::DebuginfoKind;
|
|||
use smallvec::smallvec;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
pub(crate) use self::type_map::TypeMap;
|
||||
use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId};
|
||||
use super::CodegenUnitDebugContext;
|
||||
use super::namespace::mangled_name_of_instance;
|
||||
|
|
@ -30,6 +31,7 @@ use super::utils::{
|
|||
DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit,
|
||||
};
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::dwarf_const;
|
||||
use crate::debuginfo::metadata::type_map::build_type_with_children;
|
||||
use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind};
|
||||
use crate::llvm::debuginfo::{
|
||||
|
|
@ -59,23 +61,6 @@ impl fmt::Debug for llvm::Metadata {
|
|||
}
|
||||
}
|
||||
|
||||
// From DWARF 5.
|
||||
// See http://www.dwarfstd.org/ShowIssue.php?issue=140129.1.
|
||||
const DW_LANG_RUST: c_uint = 0x1c;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_ATE_boolean: c_uint = 0x02;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_ATE_float: c_uint = 0x04;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_ATE_signed: c_uint = 0x05;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_ATE_unsigned: c_uint = 0x07;
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_ATE_UTF: c_uint = 0x10;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_TAG_const_type: c_uint = 0x26;
|
||||
|
||||
pub(super) const UNKNOWN_LINE_NUMBER: c_uint = 0;
|
||||
pub(super) const UNKNOWN_COLUMN_NUMBER: c_uint = 0;
|
||||
|
||||
|
|
@ -90,8 +75,6 @@ type SmallVec<T> = smallvec::SmallVec<[T; 16]>;
|
|||
mod enums;
|
||||
mod type_map;
|
||||
|
||||
pub(crate) use type_map::TypeMap;
|
||||
|
||||
/// Returns from the enclosing function if the type debuginfo node with the given
|
||||
/// unique ID can be found in the type map.
|
||||
macro_rules! return_if_di_node_created_in_meantime {
|
||||
|
|
@ -522,7 +505,7 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D
|
|||
name.as_c_char_ptr(),
|
||||
name.len(),
|
||||
cx.tcx.data_layout.pointer_size.bits(),
|
||||
DW_ATE_unsigned,
|
||||
dwarf_const::DW_ATE_unsigned,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
@ -781,6 +764,8 @@ fn build_basic_type_di_node<'ll, 'tcx>(
|
|||
// .natvis visualizers (and perhaps other existing native debuggers?)
|
||||
let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
|
||||
|
||||
use dwarf_const::{DW_ATE_UTF, DW_ATE_boolean, DW_ATE_float, DW_ATE_signed, DW_ATE_unsigned};
|
||||
|
||||
let (name, encoding) = match t.kind() {
|
||||
ty::Never => ("!", DW_ATE_unsigned),
|
||||
ty::Tuple(elements) if elements.is_empty() => {
|
||||
|
|
@ -961,7 +946,7 @@ pub(crate) fn build_compile_unit_di_node<'ll, 'tcx>(
|
|||
|
||||
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit(
|
||||
debug_context.builder,
|
||||
DW_LANG_RUST,
|
||||
dwarf_const::DW_LANG_Rust,
|
||||
compile_unit_file,
|
||||
producer.as_c_char_ptr(),
|
||||
producer.len(),
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ use rustc_middle::ty::{self, AdtDef, CoroutineArgs, CoroutineArgsExt, Ty};
|
|||
use smallvec::smallvec;
|
||||
|
||||
use crate::common::{AsCCharPtr, CodegenCx};
|
||||
use crate::debuginfo::dwarf_const::DW_TAG_const_type;
|
||||
use crate::debuginfo::metadata::enums::DiscrResult;
|
||||
use crate::debuginfo::metadata::type_map::{self, Stub, UniqueTypeId};
|
||||
use crate::debuginfo::metadata::{
|
||||
DINodeCreationResult, DW_TAG_const_type, NO_GENERICS, NO_SCOPE_METADATA, SmallVec,
|
||||
UNKNOWN_LINE_NUMBER, build_field_di_node, file_metadata, file_metadata_from_def_id,
|
||||
size_and_align_of, type_di_node, unknown_file_metadata, visibility_di_flags,
|
||||
DINodeCreationResult, NO_GENERICS, NO_SCOPE_METADATA, SmallVec, UNKNOWN_LINE_NUMBER,
|
||||
build_field_di_node, file_metadata, file_metadata_from_def_id, size_and_align_of, type_di_node,
|
||||
unknown_file_metadata, visibility_di_flags,
|
||||
};
|
||||
use crate::debuginfo::utils::DIB;
|
||||
use crate::llvm::debuginfo::{DIFile, DIFlags, DIType};
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use crate::llvm::debuginfo::{
|
|||
use crate::value::Value;
|
||||
|
||||
mod create_scope_map;
|
||||
mod dwarf_const;
|
||||
mod gdb;
|
||||
pub(crate) mod metadata;
|
||||
mod namespace;
|
||||
|
|
@ -47,6 +48,10 @@ mod utils;
|
|||
use self::create_scope_map::compute_mir_scopes;
|
||||
pub(crate) use self::metadata::build_global_var_di_node;
|
||||
|
||||
// FIXME(Zalathar): These `DW_TAG_*` constants are fake values that were
|
||||
// removed from LLVM in 2015, and are only used by our own `RustWrapper.cpp`
|
||||
// to decide which C++ API to call. Instead, we should just have two separate
|
||||
// FFI functions and choose the correct one on the Rust side.
|
||||
#[allow(non_upper_case_globals)]
|
||||
const DW_TAG_auto_variable: c_uint = 0x100;
|
||||
#[allow(non_upper_case_globals)]
|
||||
|
|
@ -152,29 +157,26 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> {
|
|||
indirect_offsets: &[Size],
|
||||
fragment: Option<Range<Size>>,
|
||||
) {
|
||||
use dwarf_const::{DW_OP_LLVM_fragment, DW_OP_deref, DW_OP_plus_uconst};
|
||||
|
||||
// Convert the direct and indirect offsets and fragment byte range to address ops.
|
||||
// FIXME(eddyb) use `const`s instead of getting the values via FFI,
|
||||
// the values should match the ones in the DWARF standard anyway.
|
||||
let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
|
||||
let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
|
||||
let op_llvm_fragment = || unsafe { llvm::LLVMRustDIBuilderCreateOpLLVMFragment() };
|
||||
let mut addr_ops = SmallVec::<[u64; 8]>::new();
|
||||
|
||||
if direct_offset.bytes() > 0 {
|
||||
addr_ops.push(op_plus_uconst());
|
||||
addr_ops.push(DW_OP_plus_uconst);
|
||||
addr_ops.push(direct_offset.bytes() as u64);
|
||||
}
|
||||
for &offset in indirect_offsets {
|
||||
addr_ops.push(op_deref());
|
||||
addr_ops.push(DW_OP_deref);
|
||||
if offset.bytes() > 0 {
|
||||
addr_ops.push(op_plus_uconst());
|
||||
addr_ops.push(DW_OP_plus_uconst);
|
||||
addr_ops.push(offset.bytes() as u64);
|
||||
}
|
||||
}
|
||||
if let Some(fragment) = fragment {
|
||||
// `DW_OP_LLVM_fragment` takes as arguments the fragment's
|
||||
// offset and size, both of them in bits.
|
||||
addr_ops.push(op_llvm_fragment());
|
||||
addr_ops.push(DW_OP_LLVM_fragment);
|
||||
addr_ops.push(fragment.start.bits() as u64);
|
||||
addr_ops.push((fragment.end - fragment.start).bits() as u64);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
|
|||
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
|
|
@ -213,12 +214,6 @@ pub(crate) struct MismatchedDataLayout<'a> {
|
|||
pub llvm_layout: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_invalid_target_feature_prefix)]
|
||||
pub(crate) struct InvalidTargetFeaturePrefix<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_fixed_x18_invalid_arch)]
|
||||
pub(crate) struct FixedX18InvalidArch<'a> {
|
||||
|
|
|
|||
|
|
@ -2177,9 +2177,6 @@ unsafe extern "C" {
|
|||
Location: &'a DILocation,
|
||||
BD: c_uint,
|
||||
) -> Option<&'a DILocation>;
|
||||
pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
|
||||
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
|
||||
pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
|
||||
|
||||
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
|
||||
pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
|
||||
|
|
@ -2377,7 +2374,7 @@ unsafe extern "C" {
|
|||
Data: &ThinLTOData,
|
||||
Module: &Module,
|
||||
Target: &TargetMachine,
|
||||
) -> bool;
|
||||
);
|
||||
pub fn LLVMRustPrepareThinLTOResolveWeak(Data: &ThinLTOData, Module: &Module) -> bool;
|
||||
pub fn LLVMRustPrepareThinLTOInternalize(Data: &ThinLTOData, Module: &Module) -> bool;
|
||||
pub fn LLVMRustPrepareThinLTOImport(
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU
|
|||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
FixedX18InvalidArch, ForbiddenCTargetFeature, InvalidTargetFeaturePrefix, PossibleFeature,
|
||||
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
|
||||
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
};
|
||||
use crate::llvm;
|
||||
|
||||
|
|
@ -109,7 +109,10 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||
add("-wasm-enable-eh", false);
|
||||
}
|
||||
|
||||
if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
|
||||
if sess.target.os == "emscripten"
|
||||
&& !sess.opts.unstable_opts.emscripten_wasm_eh
|
||||
&& sess.panic_strategy() == PanicStrategy::Unwind
|
||||
{
|
||||
add("-enable-emscripten-cxx-exceptions", false);
|
||||
}
|
||||
|
||||
|
|
@ -348,7 +351,16 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
|
|||
{
|
||||
if enabled {
|
||||
// Also add all transitively implied features.
|
||||
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
|
||||
|
||||
// We don't care about the order in `features` since the only thing we use it for is the
|
||||
// `features.contains` below.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
features.extend(
|
||||
sess.target
|
||||
.implied_target_features(std::iter::once(feature.as_str()))
|
||||
.iter()
|
||||
.map(|s| Symbol::intern(s)),
|
||||
);
|
||||
} else {
|
||||
// Remove transitively reverse-implied features.
|
||||
|
||||
|
|
@ -356,7 +368,11 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
|
|||
// `features.contains` below.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
features.retain(|f| {
|
||||
if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) {
|
||||
if sess
|
||||
.target
|
||||
.implied_target_features(std::iter::once(f.as_str()))
|
||||
.contains(&feature.as_str())
|
||||
{
|
||||
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
|
||||
// remove `f`. (This is the standard logical contraposition principle.)
|
||||
false
|
||||
|
|
@ -638,7 +654,7 @@ pub(crate) fn global_llvm_features(
|
|||
sess.target
|
||||
.features
|
||||
.split(',')
|
||||
.filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
|
||||
.filter(|v| !v.is_empty())
|
||||
// Drop +v8plus feature introduced in LLVM 20.
|
||||
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
|
||||
.map(String::from),
|
||||
|
|
@ -651,89 +667,136 @@ pub(crate) fn global_llvm_features(
|
|||
// -Ctarget-features
|
||||
if !only_base_features {
|
||||
let known_features = sess.target.rust_target_features();
|
||||
// Will only be filled when `diagnostics` is set!
|
||||
let mut featsmap = FxHashMap::default();
|
||||
|
||||
// insert implied features
|
||||
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
||||
// are disabled.
|
||||
let abi_feature_constraints = sess.target.abi_required_features();
|
||||
let abi_incompatible_set =
|
||||
FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
|
||||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
match feature.strip_prefix('+') {
|
||||
Some(feature) => all_rust_features.extend(
|
||||
UnordSet::from(
|
||||
sess.target
|
||||
.implied_target_features(std::iter::once(Symbol::intern(feature))),
|
||||
)
|
||||
.to_sorted_stable_ord()
|
||||
.iter()
|
||||
.map(|s| format!("+{}", s.as_str())),
|
||||
),
|
||||
_ => all_rust_features.push(feature.to_string()),
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
|
||||
.to_sorted_stable_ord()
|
||||
.iter()
|
||||
.map(|&&s| (true, s)),
|
||||
)
|
||||
} else if let Some(feature) = feature.strip_prefix('-') {
|
||||
// FIXME: Why do we not remove implied features on "-" here?
|
||||
// We do the equivalent above in `target_features_cfg`.
|
||||
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||
all_rust_features.push((false, feature));
|
||||
} else if !feature.is_empty() {
|
||||
if diagnostics {
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove features that are meant for rustc, not LLVM.
|
||||
all_rust_features.retain(|(_, feature)| {
|
||||
// Retain if it is not a rustc feature
|
||||
!RUSTC_SPECIFIC_FEATURES.contains(feature)
|
||||
});
|
||||
|
||||
// Check feature validity.
|
||||
if diagnostics {
|
||||
for &(enable, feature) in &all_rust_features {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature =
|
||||
known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let llvm_features = to_llvm_features(sess, rust_feature)?;
|
||||
if llvm_features.contains(feature)
|
||||
&& !llvm_features.contains(rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the features we enable/disable are compatible with the ABI.
|
||||
if enable {
|
||||
if abi_incompatible_set.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "enabled",
|
||||
reason: "this feature is incompatible with the target ABI",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// FIXME: we have to request implied features here since
|
||||
// negative features do not handle implied features above.
|
||||
for &required in abi_feature_constraints.required.iter() {
|
||||
let implied =
|
||||
sess.target.implied_target_features(std::iter::once(required));
|
||||
if implied.contains(feature) {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: "disabled",
|
||||
reason: "this feature is required by the target ABI",
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable);
|
||||
}
|
||||
}
|
||||
|
||||
// To be sure the ABI-relevant features are all in the right state, we explicitly
|
||||
// (un)set them here. This means if the target spec sets those features wrong,
|
||||
// we will silently correct them rather than silently producing wrong code.
|
||||
// (The target sanity check tries to catch this, but we can't know which features are
|
||||
// enabled in LLVM by default so we can't be fully sure about that check.)
|
||||
// We add these at the beginning of the list so that `-Ctarget-features` can
|
||||
// still override it... that's unsound, but more compatible with past behavior.
|
||||
all_rust_features.splice(
|
||||
0..0,
|
||||
abi_feature_constraints
|
||||
.required
|
||||
.iter()
|
||||
.map(|&f| (true, f))
|
||||
.chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
|
||||
);
|
||||
|
||||
// Translate this into LLVM features.
|
||||
let feats = all_rust_features
|
||||
.iter()
|
||||
.filter_map(|s| {
|
||||
let enable_disable = match s.chars().next() {
|
||||
None => return None,
|
||||
Some(c @ ('+' | '-')) => c,
|
||||
Some(_) => {
|
||||
if diagnostics {
|
||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
|
||||
}
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the backend feature name, if any.
|
||||
// This excludes rustc-specific features, which do not get passed to LLVM.
|
||||
let feature = backend_feature_name(sess, s)?;
|
||||
// Warn against use of LLVM specific feature names and unstable features on the CLI.
|
||||
if diagnostics {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature =
|
||||
known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let llvm_features = to_llvm_features(sess, rust_feature)?;
|
||||
if llvm_features.contains(feature)
|
||||
&& !llvm_features.contains(rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::None,
|
||||
}
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) =
|
||||
stability.toggle_allowed(&sess.target, enable_disable == '+')
|
||||
{
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable_disable == '+');
|
||||
}
|
||||
|
||||
.filter_map(|&(enable, feature)| {
|
||||
let enable_disable = if enable { '+' } else { '-' };
|
||||
// We run through `to_llvm_features` when
|
||||
// passing requests down to LLVM. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
|
|
@ -746,9 +809,9 @@ pub(crate) fn global_llvm_features(
|
|||
enable_disable, llvm_feature.llvm_feature_name
|
||||
))
|
||||
.chain(llvm_feature.dependency.into_iter().filter_map(
|
||||
move |feat| match (enable_disable, feat) {
|
||||
('-' | '+', TargetFeatureFoldStrength::Both(f))
|
||||
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
|
||||
move |feat| match (enable, feat) {
|
||||
(_, TargetFeatureFoldStrength::Both(f))
|
||||
| (true, TargetFeatureFoldStrength::EnableOnly(f)) => {
|
||||
Some(format!("{enable_disable}{f}"))
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -780,22 +843,6 @@ pub(crate) fn global_llvm_features(
|
|||
features
|
||||
}
|
||||
|
||||
/// Returns a feature name for the given `+feature` or `-feature` string.
|
||||
///
|
||||
/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
|
||||
fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
|
||||
// features must start with a `+` or `-`.
|
||||
let feature = s
|
||||
.strip_prefix(&['+', '-'][..])
|
||||
.unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
|
||||
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
|
||||
// are not passed down to LLVM.
|
||||
if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
Some(feature)
|
||||
}
|
||||
|
||||
pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> {
|
||||
let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
|
||||
Some(handle_native(name))
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
|
|||
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
|
||||
|
||||
codegen_ssa_forbidden_target_feature_attr =
|
||||
target feature `{$feature}` cannot be toggled with `#[target_feature]`: {$reason}
|
||||
target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason}
|
||||
|
||||
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
|
||||
|
||||
|
|
|
|||
|
|
@ -2451,10 +2451,12 @@ fn add_order_independent_options(
|
|||
}
|
||||
|
||||
if sess.target.os == "emscripten" {
|
||||
cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
||||
"DISABLE_EXCEPTION_CATCHING=1"
|
||||
cmd.cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
||||
"-sDISABLE_EXCEPTION_CATCHING=1"
|
||||
} else if sess.opts.unstable_opts.emscripten_wasm_eh {
|
||||
"-fwasm-exceptions"
|
||||
} else {
|
||||
"DISABLE_EXCEPTION_CATCHING=0"
|
||||
"-sDISABLE_EXCEPTION_CATCHING=0"
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -388,7 +388,8 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// exceptions. This means that the VM does the unwinding for
|
||||
// us
|
||||
pub fn wants_wasm_eh(sess: &Session) -> bool {
|
||||
sess.target.is_like_wasm && sess.target.os != "emscripten"
|
||||
sess.target.is_like_wasm
|
||||
&& (sess.target.os != "emscripten" || sess.opts.unstable_opts.emscripten_wasm_eh)
|
||||
}
|
||||
|
||||
/// Returns `true` if this session's target will use SEH-based unwinding.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use rustc_session::parse::feature_err;
|
|||
use rustc_session::{Session, lint};
|
||||
use rustc_span::{Ident, Span, sym};
|
||||
use rustc_target::spec::{SanitizerSet, abi};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::errors;
|
||||
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
|
||||
|
|
@ -525,6 +526,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
if !attr.has_name(sym::inline) {
|
||||
return ia;
|
||||
}
|
||||
|
||||
if attr.is_word() {
|
||||
InlineAttr::Hint
|
||||
} else if let Some(ref items) = attr.meta_item_list() {
|
||||
|
|
@ -547,6 +549,20 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
ia
|
||||
}
|
||||
});
|
||||
codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| {
|
||||
if !attr.has_name(sym::rustc_force_inline) || !tcx.features().rustc_attrs() {
|
||||
return ia;
|
||||
}
|
||||
|
||||
if attr.is_word() {
|
||||
InlineAttr::Force { attr_span: attr.span, reason: None }
|
||||
} else if let Some(val) = attr.value_str() {
|
||||
InlineAttr::Force { attr_span: attr.span, reason: Some(val) }
|
||||
} else {
|
||||
debug!("`rustc_force_inline` not checked by attribute validation");
|
||||
ia
|
||||
}
|
||||
});
|
||||
|
||||
// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
|
||||
// but not for the code generation backend because at that point the naked function will just be
|
||||
|
|
@ -596,7 +612,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// is probably a poor usage of `#[inline(always)]` and easily avoided by not using the attribute.
|
||||
if tcx.features().target_feature_11()
|
||||
&& tcx.is_closure_like(did.to_def_id())
|
||||
&& codegen_fn_attrs.inline != InlineAttr::Always
|
||||
&& !codegen_fn_attrs.inline.always()
|
||||
{
|
||||
let owner_id = tcx.parent(did.to_def_id());
|
||||
if tcx.def_kind(owner_id).has_codegen_attrs() {
|
||||
|
|
@ -606,22 +622,28 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
// If a function uses #[target_feature] it can't be inlined into general
|
||||
// If a function uses `#[target_feature]` it can't be inlined into general
|
||||
// purpose functions as they wouldn't have the right target features
|
||||
// enabled. For that reason we also forbid #[inline(always)] as it can't be
|
||||
// enabled. For that reason we also forbid `#[inline(always)]` as it can't be
|
||||
// respected.
|
||||
if !codegen_fn_attrs.target_features.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always
|
||||
//
|
||||
// `#[rustc_force_inline]` doesn't need to be prohibited here, only
|
||||
// `#[inline(always)]`, as forced inlining is implemented entirely within
|
||||
// rustc (and so the MIR inliner can do any necessary checks for compatible target
|
||||
// features).
|
||||
//
|
||||
// This sidesteps the LLVM blockers in enabling `target_features` +
|
||||
// `inline(always)` to be used together (see rust-lang/rust#116573 and
|
||||
// llvm/llvm-project#70563).
|
||||
if !codegen_fn_attrs.target_features.is_empty()
|
||||
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
|
||||
{
|
||||
if let Some(span) = inline_span {
|
||||
tcx.dcx().span_err(
|
||||
span,
|
||||
"cannot use `#[inline(always)]` with \
|
||||
`#[target_feature]`",
|
||||
);
|
||||
tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
|
||||
}
|
||||
}
|
||||
|
||||
if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline == InlineAttr::Always {
|
||||
if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline.always() {
|
||||
if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) {
|
||||
let hir_id = tcx.local_def_id_to_hir_id(did);
|
||||
tcx.node_span_lint(
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
//! which do not.
|
||||
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::{self, DefLocation, Location, TerminatorKind, traversal};
|
||||
|
|
@ -16,7 +16,7 @@ use crate::traits::*;
|
|||
pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
fx: &FunctionCx<'a, 'tcx, Bx>,
|
||||
traversal_order: &[mir::BasicBlock],
|
||||
) -> BitSet<mir::Local> {
|
||||
) -> DenseBitSet<mir::Local> {
|
||||
let mir = fx.mir;
|
||||
let dominators = mir.basic_blocks.dominators();
|
||||
let locals = mir
|
||||
|
|
@ -44,7 +44,7 @@ pub(crate) fn non_ssa_locals<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
analyzer.visit_basic_block_data(bb, data);
|
||||
}
|
||||
|
||||
let mut non_ssa_locals = BitSet::new_empty(analyzer.locals.len());
|
||||
let mut non_ssa_locals = DenseBitSet::new_empty(analyzer.locals.len());
|
||||
for (local, kind) in analyzer.locals.iter_enumerated() {
|
||||
if matches!(kind, LocalKind::Memory) {
|
||||
non_ssa_locals.insert(local);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
use rustc_middle::mir::{UnwindTerminateReason, traversal};
|
||||
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
|
||||
|
|
@ -293,7 +293,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// So drop the builder of `start_llbb` to avoid having two at the same time.
|
||||
drop(start_bx);
|
||||
|
||||
let mut unreached_blocks = BitSet::new_filled(mir.basic_blocks.len());
|
||||
let mut unreached_blocks = DenseBitSet::new_filled(mir.basic_blocks.len());
|
||||
// Codegen the body of each reachable block using our reverse postorder list.
|
||||
for bb in traversal_order {
|
||||
fx.codegen_block(bb);
|
||||
|
|
@ -316,7 +316,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
fx: &mut FunctionCx<'a, 'tcx, Bx>,
|
||||
memory_locals: &BitSet<mir::Local>,
|
||||
memory_locals: &DenseBitSet<mir::Local>,
|
||||
) -> Vec<LocalRef<'tcx, Bx::Value>> {
|
||||
let mir = fx.mir;
|
||||
let mut idx = 0;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue