Merge from rustc

This commit is contained in:
Ralf Jung 2025-01-08 09:23:40 +01:00
commit 2d180714e1
1351 changed files with 53386 additions and 14824 deletions

View file

@ -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 -->

View file

@ -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

View file

@ -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",
]

View file

@ -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/)

View file

@ -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,
})
}

View file

@ -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()
}
}

View file

@ -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();
}
}
}

View file

@ -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>),

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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,

View file

@ -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| {

View file

@ -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)]

View file

@ -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,
})
}
}

View file

@ -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"),

View file

@ -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());

View file

@ -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)]

View file

@ -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:
///

View file

@ -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

View file

@ -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;
}

View file

@ -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`].

View file

@ -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) {

View file

@ -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);

View file

@ -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, .. } => {

View file

@ -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
}

View file

@ -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:

View file

@ -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);
}

View file

@ -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) => {

View file

@ -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))

View file

@ -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, &regioncx, 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,

View file

@ -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;
}
}

View file

@ -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> {

View file

@ -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))
}
}

View file

@ -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(())
},
);
}

View file

@ -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>,
}

View file

@ -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 }
}

View file

@ -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(

View file

@ -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,
});
}
}
}
_ => {}
}
}
}

View 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,
}
}

View file

@ -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> {

View file

@ -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());

View file

@ -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
));

View file

@ -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,
}

View file

@ -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

View file

@ -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,

View file

@ -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 {

View file

@ -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),

View file

@ -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);
}
}
}

View file

@ -1,3 +0,0 @@
mod collect_writes;
pub(crate) use collect_writes::FindAssignments;

View file

@ -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

View file

@ -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",
]

View file

@ -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" }

View file

@ -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,

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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),
}
}
}

View file

@ -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", &[]),

View file

@ -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

View file

@ -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
}

View file

@ -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)
}
}
}

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -1,4 +1,4 @@
[toolchain]
channel = "nightly-2024-12-06"
channel = "nightly-2025-01-10"
components = ["rust-src", "rustc-dev", "llvm-tools"]
profile = "minimal"

View file

@ -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,

View file

@ -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,
);

View file

@ -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,
);

View file

@ -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

View file

@ -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))
}

View file

@ -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)
}

View file

@ -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

View file

@ -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
}
}

View file

@ -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());
}
}
}

View file

@ -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;
}
}

View file

@ -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))

View file

@ -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)
}

View file

@ -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)

View file

@ -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");
}

View file

@ -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) {

View file

@ -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,
}

View file

@ -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"],

View file

@ -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"

View file

@ -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}

View file

@ -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) {

View file

@ -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");
}

View file

@ -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,
) {

View 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;

View file

@ -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(),

View file

@ -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};

View file

@ -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);
}

View file

@ -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> {

View file

@ -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(

View file

@ -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))

View file

@ -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

View file

@ -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"
});
}

View file

@ -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.

View file

@ -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(

View file

@ -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);

View file

@ -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