commit
b886a8e654
2332 changed files with 28714 additions and 17322 deletions
|
|
@ -31,3 +31,5 @@ ec2cc761bc7067712ecc7734502f703fe3b024c8
|
|||
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
|
||||
# reformat with updated edition 2024
|
||||
1fcae03369abb4c2cc180cd5a49e1f4440a81300
|
||||
# Breaking up of compiletest runtest.rs
|
||||
60600a6fa403216bfd66e04f948b1822f6450af7
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
name: Library Tracking Issue
|
||||
about: A tracking issue for an unstable library feature.
|
||||
title: Tracking Issue for XXX
|
||||
labels: C-tracking-issue, T-libs-api
|
||||
labels: C-tracking-issue, T-libs-api, S-tracking-unimplemented
|
||||
---
|
||||
<!--
|
||||
Thank you for creating a tracking issue!
|
||||
|
|
@ -49,6 +49,8 @@ For larger features, more steps might be involved.
|
|||
If the feature is changed later, please add those PRs here as well.
|
||||
-->
|
||||
|
||||
(Remember to update the `S-tracking-*` label when checking boxes.)
|
||||
|
||||
- [ ] Implementation: #...
|
||||
- [ ] Final comment period (FCP)[^1]
|
||||
- [ ] Stabilization PR
|
||||
|
|
|
|||
5
.github/ISSUE_TEMPLATE/tracking_issue.md
vendored
5
.github/ISSUE_TEMPLATE/tracking_issue.md
vendored
|
|
@ -41,7 +41,10 @@ for larger features an implementation could be broken up into multiple PRs.
|
|||
- [ ] Implement the RFC (cc @rust-lang/XXX -- can anyone write up mentoring
|
||||
instructions?)
|
||||
- [ ] Adjust documentation ([see instructions on rustc-dev-guide][doc-guide])
|
||||
- [ ] Formatting for new syntax has been added to the [Style Guide] ([nightly-style-procedure])
|
||||
- [ ] Style updates for any new syntax ([nightly-style-procedure])
|
||||
- [ ] Style team decision on new formatting
|
||||
- [ ] Formatting for new syntax has been added to the [Style Guide]
|
||||
- [ ] (non-blocking) Formatting has been implemented in `rustfmt`
|
||||
- [ ] Stabilization PR ([see instructions on rustc-dev-guide][stabilization-guide])
|
||||
|
||||
[stabilization-guide]: https://rustc-dev-guide.rust-lang.org/stabilization_guide.html#stabilization-pr
|
||||
|
|
|
|||
7
.github/workflows/ci.yml
vendored
7
.github/workflows/ci.yml
vendored
|
|
@ -53,6 +53,13 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout the source code
|
||||
uses: actions/checkout@v4
|
||||
# Cache citool to make its build faster, as it's in the critical path.
|
||||
# The rust-cache doesn't bleed into the main `job`, so it should not affect any other
|
||||
# Rust compilation.
|
||||
- name: Cache citool
|
||||
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||
with:
|
||||
workspaces: src/ci/citool
|
||||
- name: Calculate the CI job matrix
|
||||
env:
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -292,6 +292,7 @@ James Hinshelwood <jameshinshelwood1@gmail.com> <james.hinshelwood@bigpayme.com>
|
|||
James Miller <bladeon@gmail.com> <james@aatch.net>
|
||||
James Perry <james.austin.perry@gmail.com>
|
||||
James Sanderson <zofrex@gmail.com>
|
||||
Jamie Hill-Daniel <jamie@hill-daniel.co.uk> <clubby789@gmail.com>
|
||||
Jana Dönszelmann <jana@donsz.nl>
|
||||
Jana Dönszelmann <jana@donsz.nl> <jonathan@donsz.nl>
|
||||
Jana Dönszelmann <jana@donsz.nl> <jonabent@gmail.com>
|
||||
|
|
|
|||
236
Cargo.lock
236
Cargo.lock
|
|
@ -186,6 +186,48 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "askama"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543"
|
||||
dependencies = [
|
||||
"askama_derive",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_derive"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6"
|
||||
dependencies = [
|
||||
"askama_parser",
|
||||
"basic-toml",
|
||||
"memchr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 2.0.100",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "askama_parser"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"winnow 0.7.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.4.0"
|
||||
|
|
@ -337,7 +379,7 @@ dependencies = [
|
|||
name = "cargo-miri"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cargo_metadata 0.18.1",
|
||||
"cargo_metadata 0.19.2",
|
||||
"directories",
|
||||
"rustc-build-sysroot",
|
||||
"rustc_tools_util 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
|
@ -676,8 +718,8 @@ name = "compiletest"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"anstyle-svg",
|
||||
"anyhow",
|
||||
"build_helper",
|
||||
"camino",
|
||||
"colored",
|
||||
"diff",
|
||||
"getopts",
|
||||
|
|
@ -890,15 +932,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
version = "1.2.7"
|
||||
|
|
@ -971,11 +1004,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "directories"
|
||||
version = "5.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35"
|
||||
checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
"dirs-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -984,7 +1017,7 @@ version = "5.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1005,10 +1038,22 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"redox_users 0.4.6",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
|
|
@ -1016,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"redox_users 0.4.6",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
|
|
@ -1168,7 +1213,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.8.7",
|
||||
"miniz_oxide 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1345,8 +1390,8 @@ name = "generate-copyright"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"askama",
|
||||
"cargo_metadata 0.18.1",
|
||||
"rinja",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 1.0.69",
|
||||
|
|
@ -1977,9 +2022,9 @@ checksum = "9fa0e2a1fcbe2f6be6c42e342259976206b383122fc152e872795338b5a3f3a7"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
|
|
@ -1993,9 +2038,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libffi"
|
||||
version = "3.2.0"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2"
|
||||
checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libffi-sys",
|
||||
|
|
@ -2003,9 +2048,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libffi-sys"
|
||||
version = "2.3.0"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c"
|
||||
checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
|
@ -2170,20 +2215,6 @@ dependencies = [
|
|||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "measureme"
|
||||
version = "11.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dfa4a40f09af7aa6faef38285402a78847d0d72bf8827006cd2a332e1e6e4a8d"
|
||||
dependencies = [
|
||||
"log",
|
||||
"memmap2",
|
||||
"parking_lot",
|
||||
"perf-event-open-sys",
|
||||
"rustc-hash 1.1.0",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "measureme"
|
||||
version = "12.0.1"
|
||||
|
|
@ -2252,9 +2283,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
|
@ -2273,6 +2304,7 @@ name = "miri"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"colored",
|
||||
|
|
@ -2281,7 +2313,7 @@ dependencies = [
|
|||
"libc",
|
||||
"libffi",
|
||||
"libloading",
|
||||
"measureme 11.0.1",
|
||||
"measureme",
|
||||
"rand 0.9.0",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
|
|
@ -2289,7 +2321,7 @@ dependencies = [
|
|||
"tempfile",
|
||||
"tikv-jemalloc-sys",
|
||||
"ui_test",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2385,12 +2417,6 @@ dependencies = [
|
|||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-conv"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
|
|
@ -2546,16 +2572,6 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
|
@ -2768,12 +2784,6 @@ dependencies = [
|
|||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.21"
|
||||
|
|
@ -2988,6 +2998,17 @@ dependencies = [
|
|||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
dependencies = [
|
||||
"getrandom 0.2.15",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
|
|
@ -3069,9 +3090,7 @@ version = "0.3.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5"
|
||||
dependencies = [
|
||||
"humansize",
|
||||
"itoa",
|
||||
"percent-encoding",
|
||||
"rinja_derive",
|
||||
]
|
||||
|
||||
|
|
@ -3113,7 +3132,6 @@ dependencies = [
|
|||
"gimli 0.31.1",
|
||||
"libc",
|
||||
"object 0.36.7",
|
||||
"os_pipe",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"similar",
|
||||
|
|
@ -3169,26 +3187,13 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-rayon"
|
||||
name = "rustc-rayon-core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cd9fb077db982d7ceb42a90471e5a69a990b58f71e06f0d8340bb2cf35eb751"
|
||||
checksum = "2f42932dcd3bcbe484b38a3ccf79b7906fac41c02d408b5b1bac26da3416efdb"
|
||||
dependencies = [
|
||||
"either",
|
||||
"indexmap",
|
||||
"rustc-rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-rayon-core"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3430,7 +3435,7 @@ dependencies = [
|
|||
"gimli 0.31.1",
|
||||
"itertools",
|
||||
"libc",
|
||||
"measureme 12.0.1",
|
||||
"measureme",
|
||||
"object 0.36.7",
|
||||
"rustc-demangle",
|
||||
"rustc_abi",
|
||||
|
|
@ -3545,12 +3550,12 @@ dependencies = [
|
|||
"indexmap",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"measureme 12.0.1",
|
||||
"measureme",
|
||||
"memmap2",
|
||||
"parking_lot",
|
||||
"portable-atomic",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustc-rayon",
|
||||
"rustc-rayon-core",
|
||||
"rustc-stable-hash",
|
||||
"rustc_arena",
|
||||
"rustc_graphviz",
|
||||
|
|
@ -3578,6 +3583,7 @@ name = "rustc_driver_impl"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ctrlc",
|
||||
"jiff",
|
||||
"libc",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
|
|
@ -3624,7 +3630,6 @@ dependencies = [
|
|||
"rustc_ty_utils",
|
||||
"serde_json",
|
||||
"shlex",
|
||||
"time",
|
||||
"tracing",
|
||||
"windows 0.59.0",
|
||||
]
|
||||
|
|
@ -3896,7 +3901,6 @@ dependencies = [
|
|||
name = "rustc_interface"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc-rayon",
|
||||
"rustc-rayon-core",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
|
|
@ -4305,7 +4309,7 @@ dependencies = [
|
|||
name = "rustc_query_impl"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"measureme 12.0.1",
|
||||
"measureme",
|
||||
"rustc_data_structures",
|
||||
"rustc_hashes",
|
||||
"rustc_hir",
|
||||
|
|
@ -4360,7 +4364,6 @@ dependencies = [
|
|||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_metadata",
|
||||
"rustc_middle",
|
||||
|
|
@ -4407,6 +4410,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"getopts",
|
||||
"libc",
|
||||
"rand 0.9.0",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4589,6 +4593,7 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"derive-where",
|
||||
"ena",
|
||||
"indexmap",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc_ast_ir",
|
||||
|
|
@ -4627,6 +4632,7 @@ name = "rustdoc"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"askama",
|
||||
"base64",
|
||||
"expect-test",
|
||||
"indexmap",
|
||||
|
|
@ -4635,7 +4641,6 @@ dependencies = [
|
|||
"pulldown-cmark 0.9.6",
|
||||
"pulldown-cmark-escape",
|
||||
"regex",
|
||||
"rinja",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -4654,6 +4659,7 @@ name = "rustdoc-gui-test"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"build_helper",
|
||||
"camino",
|
||||
"compiletest",
|
||||
"getopts",
|
||||
"walkdir",
|
||||
|
|
@ -5318,37 +5324,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa",
|
||||
"num-conv",
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
|
||||
dependencies = [
|
||||
"num-conv",
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.6"
|
||||
|
|
@ -5425,7 +5400,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
"winnow 0.5.40",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6073,11 +6048,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.59.0"
|
||||
version = "0.61.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b7fb600834d7e868f6e5bb748a86101427330fafbf9485c331b9d5f562d54a5"
|
||||
checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6436,6 +6413,15 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winsplit"
|
||||
version = "0.1.0"
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
# - A new option
|
||||
# - A change in the default values
|
||||
#
|
||||
# If the change-id does not match the version currently in use, x.py will
|
||||
# If the change-id does not match the version currently in use, x.py will
|
||||
# display the changes made to the bootstrap.
|
||||
# To suppress these warnings, you can set change-id = "ignore".
|
||||
#change-id = <latest change id in src/bootstrap/src/utils/change_tracker.rs>
|
||||
|
|
@ -442,6 +442,9 @@
|
|||
# What custom diff tool to use for displaying compiletest tests.
|
||||
#compiletest-diff-tool = <none>
|
||||
|
||||
# Whether to use the precompiled stage0 libtest with compiletest.
|
||||
#compiletest-use-stage0-libtest = true
|
||||
|
||||
# Indicates whether ccache is used when building certain artifacts (e.g. LLVM).
|
||||
# Set to `true` to use the first `ccache` in PATH, or set an absolute path to use
|
||||
# a specific version.
|
||||
|
|
|
|||
|
|
@ -60,7 +60,6 @@ pub enum ExternAbi {
|
|||
System {
|
||||
unwind: bool,
|
||||
},
|
||||
RustIntrinsic,
|
||||
RustCall,
|
||||
/// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even
|
||||
/// normally ABI-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
|
|
@ -128,7 +127,6 @@ abi_impls! {
|
|||
RiscvInterruptS =><= "riscv-interrupt-s",
|
||||
RustCall =><= "rust-call",
|
||||
RustCold =><= "rust-cold",
|
||||
RustIntrinsic =><= "rust-intrinsic",
|
||||
Stdcall { unwind: false } =><= "stdcall",
|
||||
Stdcall { unwind: true } =><= "stdcall-unwind",
|
||||
System { unwind: false } =><= "system",
|
||||
|
|
@ -199,7 +197,7 @@ impl ExternAbi {
|
|||
/// - are subject to change between compiler versions
|
||||
pub fn is_rustic_abi(self) -> bool {
|
||||
use ExternAbi::*;
|
||||
matches!(self, Rust | RustCall | RustIntrinsic | RustCold)
|
||||
matches!(self, Rust | RustCall | RustCold)
|
||||
}
|
||||
|
||||
pub fn supports_varargs(self) -> bool {
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
is_enum: bool,
|
||||
is_unsafe_cell: bool,
|
||||
is_special_no_niche: bool,
|
||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
|
||||
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
|
||||
|
|
@ -348,7 +348,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr,
|
||||
variants,
|
||||
is_enum,
|
||||
is_unsafe_cell,
|
||||
is_special_no_niche,
|
||||
scalar_valid_range,
|
||||
always_sized,
|
||||
present_first,
|
||||
|
|
@ -505,7 +505,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
repr: &ReprOptions,
|
||||
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
|
||||
is_enum: bool,
|
||||
is_unsafe_cell: bool,
|
||||
is_special_no_niche: bool,
|
||||
scalar_valid_range: (Bound<u128>, Bound<u128>),
|
||||
always_sized: bool,
|
||||
present_first: VariantIdx,
|
||||
|
|
@ -524,7 +524,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
let mut st = self.univariant(&variants[v], repr, kind)?;
|
||||
st.variants = Variants::Single { index: v };
|
||||
|
||||
if is_unsafe_cell {
|
||||
if is_special_no_niche {
|
||||
let hide_niches = |scalar: &mut _| match scalar {
|
||||
Scalar::Initialized { value, valid_range } => {
|
||||
*valid_range = WrappingRange::full(value.size(dl))
|
||||
|
|
|
|||
|
|
@ -1829,7 +1829,7 @@ pub struct PointeeInfo {
|
|||
pub safe: Option<PointerKind>,
|
||||
/// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes.
|
||||
/// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration
|
||||
/// of this function call", i.e. it is UB for the memory that this pointer points to to be freed
|
||||
/// of this function call", i.e. it is UB for the memory that this pointer points to be freed
|
||||
/// while this function is still running.
|
||||
/// The size can be zero if the pointer is not dereferenceable.
|
||||
pub size: Size,
|
||||
|
|
|
|||
|
|
@ -120,6 +120,17 @@ impl Path {
|
|||
Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None }
|
||||
}
|
||||
|
||||
pub fn is_ident(&self, name: Symbol) -> bool {
|
||||
if let [segment] = self.segments.as_ref()
|
||||
&& segment.args.is_none()
|
||||
&& segment.ident.name == name
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_global(&self) -> bool {
|
||||
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
|
||||
}
|
||||
|
|
@ -563,6 +574,7 @@ impl Pat {
|
|||
/// This is intended for use by diagnostics.
|
||||
pub fn to_ty(&self) -> Option<P<Ty>> {
|
||||
let kind = match &self.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
// In a type expression `_` is an inference variable.
|
||||
PatKind::Wild => TyKind::Infer,
|
||||
// An IDENT pattern with no binding mode would be valid as path to a type. E.g. `u32`.
|
||||
|
|
@ -625,7 +637,8 @@ impl Pat {
|
|||
| PatKind::Guard(s, _) => s.walk(it),
|
||||
|
||||
// These patterns do not contain subpatterns, skip.
|
||||
PatKind::Wild
|
||||
PatKind::Missing
|
||||
| PatKind::Wild
|
||||
| PatKind::Rest
|
||||
| PatKind::Never
|
||||
| PatKind::Expr(_)
|
||||
|
|
@ -676,6 +689,7 @@ impl Pat {
|
|||
/// Return a name suitable for diagnostics.
|
||||
pub fn descr(&self) -> Option<String> {
|
||||
match &self.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => Some("_".to_string()),
|
||||
PatKind::Ident(BindingMode::NONE, ident, None) => Some(format!("{ident}")),
|
||||
PatKind::Ref(pat, mutbl) => pat.descr().map(|d| format!("&{}{d}", mutbl.prefix_str())),
|
||||
|
|
@ -769,6 +783,9 @@ pub enum RangeSyntax {
|
|||
// Adding a new variant? Please update `test_pat` in `tests/ui/macros/stringify.rs`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum PatKind {
|
||||
/// A missing pattern, e.g. for an anonymous param in a bare fn like `fn f(u32)`.
|
||||
Missing,
|
||||
|
||||
/// Represents a wildcard pattern (`_`).
|
||||
Wild,
|
||||
|
||||
|
|
@ -1169,6 +1186,7 @@ pub enum MacStmtStyle {
|
|||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Local {
|
||||
pub id: NodeId,
|
||||
pub super_: Option<Span>,
|
||||
pub pat: P<Pat>,
|
||||
pub ty: Option<P<Ty>>,
|
||||
pub kind: LocalKind,
|
||||
|
|
@ -3926,7 +3944,7 @@ mod size_asserts {
|
|||
static_assert_size!(Item, 144);
|
||||
static_assert_size!(ItemKind, 80);
|
||||
static_assert_size!(LitKind, 24);
|
||||
static_assert_size!(Local, 80);
|
||||
static_assert_size!(Local, 96);
|
||||
static_assert_size!(MetaItemLit, 40);
|
||||
static_assert_size!(Param, 40);
|
||||
static_assert_size!(Pat, 72);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::fmt;
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use crate::ptr::P;
|
||||
use crate::token::Nonterminal;
|
||||
use crate::tokenstream::LazyAttrTokenStream;
|
||||
use crate::{
|
||||
Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField,
|
||||
|
|
@ -206,19 +205,6 @@ impl HasTokens for Attribute {
|
|||
}
|
||||
}
|
||||
|
||||
impl HasTokens for Nonterminal {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
match self {
|
||||
Nonterminal::NtBlock(block) => block.tokens(),
|
||||
}
|
||||
}
|
||||
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
|
||||
match self {
|
||||
Nonterminal::NtBlock(block) => block.tokens_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for AST nodes having (or not having) attributes.
|
||||
pub trait HasAttrs {
|
||||
/// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner
|
||||
|
|
|
|||
|
|
@ -305,8 +305,8 @@ impl MetaItem {
|
|||
if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
|
||||
}
|
||||
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
pub fn name(&self) -> Option<Symbol> {
|
||||
self.ident().map(|ident| ident.name)
|
||||
}
|
||||
|
||||
pub fn has_name(&self, name: Symbol) -> bool {
|
||||
|
|
@ -511,13 +511,14 @@ impl MetaItemInner {
|
|||
}
|
||||
}
|
||||
|
||||
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
|
||||
/// For a single-segment meta item, returns its identifier; otherwise, returns `None`.
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
self.meta_item().and_then(|meta_item| meta_item.ident())
|
||||
}
|
||||
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
/// For a single-segment meta item, returns its name; otherwise, returns `None`.
|
||||
pub fn name(&self) -> Option<Symbol> {
|
||||
self.ident().map(|ident| ident.name)
|
||||
}
|
||||
|
||||
/// Returns `true` if this list item is a MetaItem with a name of `name`.
|
||||
|
|
@ -627,7 +628,7 @@ pub fn mk_doc_comment(
|
|||
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
|
||||
}
|
||||
|
||||
pub fn mk_attr(
|
||||
fn mk_attr(
|
||||
g: &AttrIdGenerator,
|
||||
style: AttrStyle,
|
||||
unsafety: Safety,
|
||||
|
|
@ -738,9 +739,9 @@ pub trait AttributeExt: Debug {
|
|||
fn id(&self) -> AttrId;
|
||||
|
||||
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
|
||||
/// return the name of the attribute, else return the empty identifier.
|
||||
fn name_or_empty(&self) -> Symbol {
|
||||
self.ident().unwrap_or_else(Ident::empty).name
|
||||
/// return the name of the attribute; otherwise, returns `None`.
|
||||
fn name(&self) -> Option<Symbol> {
|
||||
self.ident().map(|ident| ident.name)
|
||||
}
|
||||
|
||||
/// Get the meta item list, `#[attr(meta item list)]`
|
||||
|
|
@ -752,7 +753,7 @@ pub trait AttributeExt: Debug {
|
|||
/// Gets the span of the value literal, as string, when using `#[attr = value]`
|
||||
fn value_span(&self) -> Option<Span>;
|
||||
|
||||
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
|
||||
/// For a single-segment attribute, returns its ident; otherwise, returns `None`.
|
||||
fn ident(&self) -> Option<Ident>;
|
||||
|
||||
/// Checks whether the path of this attribute matches the name.
|
||||
|
|
@ -770,6 +771,11 @@ pub trait AttributeExt: Debug {
|
|||
self.ident().map(|x| x.name == name).unwrap_or(false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn has_any_name(&self, names: &[Symbol]) -> bool {
|
||||
names.iter().any(|&name| self.has_name(name))
|
||||
}
|
||||
|
||||
/// get the span of the entire attribute
|
||||
fn span(&self) -> Span;
|
||||
|
||||
|
|
@ -813,8 +819,8 @@ impl Attribute {
|
|||
AttributeExt::id(self)
|
||||
}
|
||||
|
||||
pub fn name_or_empty(&self) -> Symbol {
|
||||
AttributeExt::name_or_empty(self)
|
||||
pub fn name(&self) -> Option<Symbol> {
|
||||
AttributeExt::name(self)
|
||||
}
|
||||
|
||||
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
|
||||
|
|
@ -846,6 +852,11 @@ impl Attribute {
|
|||
AttributeExt::has_name(self, name)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_any_name(&self, names: &[Symbol]) -> bool {
|
||||
AttributeExt::has_any_name(self, names)
|
||||
}
|
||||
|
||||
pub fn span(&self) -> Span {
|
||||
AttributeExt::span(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,16 @@ pub enum DiffActivity {
|
|||
/// with it.
|
||||
Dual,
|
||||
/// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
|
||||
/// with it. It expects the shadow argument to be `width` times larger than the original
|
||||
/// input/output.
|
||||
Dualv,
|
||||
/// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
|
||||
/// with it. Drop the code which updates the original input/output for maximum performance.
|
||||
DualOnly,
|
||||
/// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
|
||||
/// with it. Drop the code which updates the original input/output for maximum performance.
|
||||
/// It expects the shadow argument to be `width` times larger than the original input/output.
|
||||
DualvOnly,
|
||||
/// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument.
|
||||
Duplicated,
|
||||
/// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument.
|
||||
|
|
@ -59,7 +67,15 @@ pub enum DiffActivity {
|
|||
DuplicatedOnly,
|
||||
/// All Integers must be Const, but these are used to mark the integer which represents the
|
||||
/// length of a slice/vec. This is used for safety checks on slices.
|
||||
FakeActivitySize,
|
||||
/// The integer (if given) specifies the size of the slice element in bytes.
|
||||
FakeActivitySize(Option<u32>),
|
||||
}
|
||||
|
||||
impl DiffActivity {
|
||||
pub fn is_dual_or_const(&self) -> bool {
|
||||
use DiffActivity::*;
|
||||
matches!(self, |Dual| DualOnly | Dualv | DualvOnly | Const)
|
||||
}
|
||||
}
|
||||
/// We generate one of these structs for each `#[autodiff(...)]` attribute.
|
||||
#[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
|
|
@ -92,6 +108,12 @@ pub struct AutoDiffAttrs {
|
|||
pub input_activity: Vec<DiffActivity>,
|
||||
}
|
||||
|
||||
impl AutoDiffAttrs {
|
||||
pub fn has_primal_ret(&self) -> bool {
|
||||
matches!(self.ret_activity, DiffActivity::Active | DiffActivity::Dual)
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffMode {
|
||||
pub fn is_rev(&self) -> bool {
|
||||
matches!(self, DiffMode::Reverse)
|
||||
|
|
@ -125,11 +147,7 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
|
|||
match mode {
|
||||
DiffMode::Error => false,
|
||||
DiffMode::Source => false,
|
||||
DiffMode::Forward => {
|
||||
activity == DiffActivity::Dual
|
||||
|| activity == DiffActivity::DualOnly
|
||||
|| activity == DiffActivity::Const
|
||||
}
|
||||
DiffMode::Forward => activity.is_dual_or_const(),
|
||||
DiffMode::Reverse => {
|
||||
activity == DiffActivity::Const
|
||||
|| activity == DiffActivity::Active
|
||||
|
|
@ -147,10 +165,8 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
|
|||
pub fn valid_ty_for_activity(ty: &P<Ty>, activity: DiffActivity) -> bool {
|
||||
use DiffActivity::*;
|
||||
// It's always allowed to mark something as Const, since we won't compute derivatives wrt. it.
|
||||
if matches!(activity, Const) {
|
||||
return true;
|
||||
}
|
||||
if matches!(activity, Dual | DualOnly) {
|
||||
// Dual variants also support all types.
|
||||
if activity.is_dual_or_const() {
|
||||
return true;
|
||||
}
|
||||
// FIXME(ZuseZ4) We should make this more robust to also
|
||||
|
|
@ -166,9 +182,7 @@ pub fn valid_input_activity(mode: DiffMode, activity: DiffActivity) -> bool {
|
|||
return match mode {
|
||||
DiffMode::Error => false,
|
||||
DiffMode::Source => false,
|
||||
DiffMode::Forward => {
|
||||
matches!(activity, Dual | DualOnly | Const)
|
||||
}
|
||||
DiffMode::Forward => activity.is_dual_or_const(),
|
||||
DiffMode::Reverse => {
|
||||
matches!(activity, Active | ActiveOnly | Duplicated | DuplicatedOnly | Const)
|
||||
}
|
||||
|
|
@ -183,10 +197,12 @@ impl Display for DiffActivity {
|
|||
DiffActivity::Active => write!(f, "Active"),
|
||||
DiffActivity::ActiveOnly => write!(f, "ActiveOnly"),
|
||||
DiffActivity::Dual => write!(f, "Dual"),
|
||||
DiffActivity::Dualv => write!(f, "Dualv"),
|
||||
DiffActivity::DualOnly => write!(f, "DualOnly"),
|
||||
DiffActivity::DualvOnly => write!(f, "DualvOnly"),
|
||||
DiffActivity::Duplicated => write!(f, "Duplicated"),
|
||||
DiffActivity::DuplicatedOnly => write!(f, "DuplicatedOnly"),
|
||||
DiffActivity::FakeActivitySize => write!(f, "FakeActivitySize"),
|
||||
DiffActivity::FakeActivitySize(s) => write!(f, "FakeActivitySize({:?})", s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -214,7 +230,9 @@ impl FromStr for DiffActivity {
|
|||
"ActiveOnly" => Ok(DiffActivity::ActiveOnly),
|
||||
"Const" => Ok(DiffActivity::Const),
|
||||
"Dual" => Ok(DiffActivity::Dual),
|
||||
"Dualv" => Ok(DiffActivity::Dualv),
|
||||
"DualOnly" => Ok(DiffActivity::DualOnly),
|
||||
"DualvOnly" => Ok(DiffActivity::DualvOnly),
|
||||
"Duplicated" => Ok(DiffActivity::Duplicated),
|
||||
"DuplicatedOnly" => Ok(DiffActivity::DuplicatedOnly),
|
||||
_ => Err(()),
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ pub mod typetree;
|
|||
#[derive(Debug, Clone, Encodable, Decodable, HashStable_Generic)]
|
||||
pub struct StrippedCfgItem<ModId = DefId> {
|
||||
pub parent_module: ModId,
|
||||
pub name: Ident,
|
||||
pub ident: Ident,
|
||||
pub cfg: MetaItem,
|
||||
}
|
||||
|
||||
impl<ModId> StrippedCfgItem<ModId> {
|
||||
pub fn map_mod_id<New>(self, f: impl FnOnce(ModId) -> New) -> StrippedCfgItem<New> {
|
||||
StrippedCfgItem { parent_module: f(self.parent_module), name: self.name, cfg: self.cfg }
|
||||
StrippedCfgItem { parent_module: f(self.parent_module), ident: self.ident, cfg: self.cfg }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
|
||||
test(attr(deny(warnings)))
|
||||
|
|
|
|||
|
|
@ -704,7 +704,8 @@ fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut Pare
|
|||
}
|
||||
|
||||
fn walk_local<T: MutVisitor>(vis: &mut T, local: &mut P<Local>) {
|
||||
let Local { id, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
|
||||
let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens } = local.deref_mut();
|
||||
visit_opt(super_, |sp| vis.visit_span(sp));
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_pat(pat);
|
||||
|
|
@ -843,9 +844,9 @@ fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrToke
|
|||
visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut());
|
||||
}
|
||||
|
||||
/// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
|
||||
/// In practice the ident part is not actually used by specific visitors right now,
|
||||
/// but there's a test below checking that it works.
|
||||
/// Applies ident visitor if it's an ident. In practice this is not actually
|
||||
/// used by specific visitors right now, but there's a test below checking that
|
||||
/// it works.
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
|
||||
let Token { kind, span } = t;
|
||||
|
|
@ -863,45 +864,11 @@ pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
|
|||
token::NtLifetime(ident, _is_raw) => {
|
||||
vis.visit_ident(ident);
|
||||
}
|
||||
token::Interpolated(nt) => {
|
||||
let nt = Arc::make_mut(nt);
|
||||
visit_nonterminal(vis, nt);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
/// Applies the visitor to elements of interpolated nodes.
|
||||
//
|
||||
// N.B., this can occur only when applying a visitor to partially expanded
|
||||
// code, where parsed pieces have gotten implanted ito *other* macro
|
||||
// invocations. This is relevant for macro hygiene, but possibly not elsewhere.
|
||||
//
|
||||
// One problem here occurs because the types for flat_map_item, flat_map_stmt,
|
||||
// etc., allow the visitor to return *multiple* items; this is a problem for the
|
||||
// nodes here, because they insist on having exactly one piece. One solution
|
||||
// would be to mangle the MutVisitor trait to include one-to-many and
|
||||
// one-to-one versions of these entry points, but that would probably confuse a
|
||||
// lot of people and help very few. Instead, I'm just going to put in dynamic
|
||||
// checks. I think the performance impact of this will be pretty much
|
||||
// nonexistent. The danger is that someone will apply a `MutVisitor` to a
|
||||
// partially expanded node, and will be confused by the fact that their
|
||||
// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt`
|
||||
// nodes. Hopefully they'll wind up reading this comment, and doing something
|
||||
// appropriate.
|
||||
//
|
||||
// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to
|
||||
// contain multiple items, but decided against it when I looked at
|
||||
// `parse_item_or_view_item` and tried to figure out what I would do with
|
||||
// multiple items there....
|
||||
fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
|
||||
match nt {
|
||||
token::NtBlock(block) => vis.visit_block(block),
|
||||
}
|
||||
}
|
||||
|
||||
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
|
||||
fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness) {
|
||||
match defaultness {
|
||||
|
|
@ -1587,7 +1554,7 @@ pub fn walk_pat<T: MutVisitor>(vis: &mut T, pat: &mut P<Pat>) {
|
|||
vis.visit_id(id);
|
||||
match kind {
|
||||
PatKind::Err(_guar) => {}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Ident(_binding_mode, ident, sub) => {
|
||||
vis.visit_ident(ident);
|
||||
visit_opt(sub, |sub| vis.visit_pat(sub));
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use LitKind::*;
|
||||
pub use Nonterminal::*;
|
||||
pub use NtExprKind::*;
|
||||
pub use NtPatKind::*;
|
||||
pub use TokenKind::*;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
|
||||
|
|
@ -16,7 +13,6 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
|
|||
use rustc_span::{Ident, Symbol};
|
||||
|
||||
use crate::ast;
|
||||
use crate::ptr::P;
|
||||
use crate::util::case::Case;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
|
|
@ -34,10 +30,6 @@ pub enum InvisibleOrigin {
|
|||
// Converted from `proc_macro::Delimiter` in
|
||||
// `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
|
||||
ProcMacro,
|
||||
|
||||
// Converted from `TokenKind::Interpolated` in
|
||||
// `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
|
||||
FlattenToken,
|
||||
}
|
||||
|
||||
impl PartialEq for InvisibleOrigin {
|
||||
|
|
@ -134,9 +126,7 @@ impl Delimiter {
|
|||
match self {
|
||||
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
|
||||
Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
|
||||
Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
|
||||
true
|
||||
}
|
||||
Delimiter::Invisible(InvisibleOrigin::ProcMacro) => true,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -337,9 +327,7 @@ impl From<IdentIsRaw> for bool {
|
|||
}
|
||||
}
|
||||
|
||||
// SAFETY: due to the `Clone` impl below, all fields of all variants other than
|
||||
// `Interpolated` must impl `Copy`.
|
||||
#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub enum TokenKind {
|
||||
/* Expression-operator symbols. */
|
||||
/// `=`
|
||||
|
|
@ -468,21 +456,6 @@ pub enum TokenKind {
|
|||
/// the `lifetime` metavariable in the macro's RHS.
|
||||
NtLifetime(Ident, IdentIsRaw),
|
||||
|
||||
/// An embedded AST node, as produced by a macro. This only exists for
|
||||
/// historical reasons. We'd like to get rid of it, for multiple reasons.
|
||||
/// - It's conceptually very strange. Saying a token can contain an AST
|
||||
/// node is like saying, in natural language, that a word can contain a
|
||||
/// sentence.
|
||||
/// - It requires special handling in a bunch of places in the parser.
|
||||
/// - It prevents `Token` from implementing `Copy`.
|
||||
/// It adds complexity and likely slows things down. Please don't add new
|
||||
/// occurrences of this token kind!
|
||||
///
|
||||
/// The span in the surrounding `Token` is that of the metavariable in the
|
||||
/// macro's RHS. The span within the Nonterminal is that of the fragment
|
||||
/// passed to the macro at the call site.
|
||||
Interpolated(Arc<Nonterminal>),
|
||||
|
||||
/// A doc comment token.
|
||||
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
|
||||
/// similarly to symbols in string literal tokens.
|
||||
|
|
@ -492,20 +465,7 @@ pub enum TokenKind {
|
|||
Eof,
|
||||
}
|
||||
|
||||
impl Clone for TokenKind {
|
||||
fn clone(&self) -> Self {
|
||||
// `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So
|
||||
// for all other variants, this implementation of `clone` is just like
|
||||
// a copy. This is faster than the `derive(Clone)` version which has a
|
||||
// separate path for every variant.
|
||||
match self {
|
||||
Interpolated(nt) => Interpolated(Arc::clone(nt)),
|
||||
_ => unsafe { std::ptr::read(self) },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
pub struct Token {
|
||||
pub kind: TokenKind,
|
||||
pub span: Span,
|
||||
|
|
@ -600,7 +560,7 @@ impl Token {
|
|||
| FatArrow | Pound | Dollar | Question | SingleQuote => true,
|
||||
|
||||
OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
|
||||
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
|
||||
| NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -631,7 +591,6 @@ impl Token {
|
|||
PathSep | // global path
|
||||
Lifetime(..) | // labeled loop
|
||||
Pound => true, // expression attributes
|
||||
Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Block |
|
||||
MetaVarKind::Expr { .. } |
|
||||
|
|
@ -703,7 +662,6 @@ impl Token {
|
|||
match self.kind {
|
||||
OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true,
|
||||
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
|
||||
Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
|
||||
OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
|
||||
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
|
||||
))) => true,
|
||||
|
|
@ -831,31 +789,20 @@ impl Token {
|
|||
/// Is this a pre-parsed expression dropped into the token stream
|
||||
/// (which happens while parsing the result of macro expansion)?
|
||||
pub fn is_metavar_expr(&self) -> bool {
|
||||
#[allow(irrefutable_let_patterns)] // FIXME: temporary
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtBlock(_) = &**nt
|
||||
{
|
||||
true
|
||||
} else if matches!(
|
||||
matches!(
|
||||
self.is_metavar_seq(),
|
||||
Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path)
|
||||
) {
|
||||
true
|
||||
} else {
|
||||
matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
|
||||
}
|
||||
Some(
|
||||
MetaVarKind::Expr { .. }
|
||||
| MetaVarKind::Literal
|
||||
| MetaVarKind::Path
|
||||
| MetaVarKind::Block
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/// Is the token an interpolated block (`$b:block`)?
|
||||
pub fn is_whole_block(&self) -> bool {
|
||||
#[allow(irrefutable_let_patterns)] // FIXME: temporary
|
||||
if let Interpolated(nt) = &self.kind
|
||||
&& let NtBlock(..) = &**nt
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
/// Are we at a block from a metavar (`$b:block`)?
|
||||
pub fn is_metavar_block(&self) -> bool {
|
||||
matches!(self.is_metavar_seq(), Some(MetaVarKind::Block))
|
||||
}
|
||||
|
||||
/// Returns `true` if the token is either the `mut` or `const` keyword.
|
||||
|
|
@ -1024,7 +971,7 @@ impl Token {
|
|||
| PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq
|
||||
| Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question
|
||||
| OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
|
||||
| Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof,
|
||||
| Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof,
|
||||
_,
|
||||
) => {
|
||||
return None;
|
||||
|
|
@ -1063,12 +1010,6 @@ pub enum NtExprKind {
|
|||
Expr2021 { inferred: bool },
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable)]
|
||||
/// For interpolation during macro expansion.
|
||||
pub enum Nonterminal {
|
||||
NtBlock(P<ast::Block>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
|
||||
pub enum NonterminalKind {
|
||||
Item,
|
||||
|
|
@ -1152,47 +1093,6 @@ impl fmt::Display for NonterminalKind {
|
|||
}
|
||||
}
|
||||
|
||||
impl Nonterminal {
|
||||
pub fn use_span(&self) -> Span {
|
||||
match self {
|
||||
NtBlock(block) => block.span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn descr(&self) -> &'static str {
|
||||
match self {
|
||||
NtBlock(..) => "block",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Nonterminal {
|
||||
fn eq(&self, _rhs: &Self) -> bool {
|
||||
// FIXME: Assume that all nonterminals are not equal, we can't compare them
|
||||
// correctly based on data from AST. This will prevent them from matching each other
|
||||
// in macros. The comparison will become possible only when each nonterminal has an
|
||||
// attached token stream from which it was parsed.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Nonterminal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
NtBlock(..) => f.pad("NtBlock(..)"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX> HashStable<CTX> for Nonterminal
|
||||
where
|
||||
CTX: crate::HashStableContext,
|
||||
{
|
||||
fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
|
||||
panic!("interpolated tokens should not be present in the HIR")
|
||||
}
|
||||
}
|
||||
|
||||
// Some types are used a lot. Make sure they don't unintentionally get bigger.
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
mod size_asserts {
|
||||
|
|
@ -1202,7 +1102,6 @@ mod size_asserts {
|
|||
// tidy-alphabetical-start
|
||||
static_assert_size!(Lit, 12);
|
||||
static_assert_size!(LitKind, 2);
|
||||
static_assert_size!(Nonterminal, 8);
|
||||
static_assert_size!(Token, 24);
|
||||
static_assert_size!(TokenKind, 16);
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
|
|||
|
||||
use crate::ast::AttrStyle;
|
||||
use crate::ast_traits::{HasAttrs, HasTokens};
|
||||
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
|
||||
use crate::token::{self, Delimiter, Token, TokenKind};
|
||||
use crate::{AttrVec, Attribute};
|
||||
|
||||
/// Part of a `TokenStream`.
|
||||
|
|
@ -305,11 +305,6 @@ pub struct AttrsTarget {
|
|||
}
|
||||
|
||||
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
|
||||
///
|
||||
/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
|
||||
/// instead of a representation of the abstract syntax tree.
|
||||
/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for
|
||||
/// backwards compatibility.
|
||||
#[derive(Clone, Debug, Default, Encodable, Decodable)]
|
||||
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
|
||||
|
||||
|
|
@ -476,61 +471,6 @@ impl TokenStream {
|
|||
TokenStream::new(tts)
|
||||
}
|
||||
|
||||
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
|
||||
match nt {
|
||||
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
|
||||
match token.kind {
|
||||
token::NtIdent(ident, is_raw) => {
|
||||
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
|
||||
}
|
||||
token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
|
||||
DelimSpan::from_single(token.span),
|
||||
DelimSpacing::new(Spacing::JointHidden, spacing),
|
||||
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
|
||||
TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
|
||||
),
|
||||
token::Interpolated(ref nt) => TokenTree::Delimited(
|
||||
DelimSpan::from_single(token.span),
|
||||
DelimSpacing::new(Spacing::JointHidden, spacing),
|
||||
Delimiter::Invisible(InvisibleOrigin::FlattenToken),
|
||||
TokenStream::from_nonterminal_ast(&nt).flattened(),
|
||||
),
|
||||
_ => TokenTree::Token(token.clone(), spacing),
|
||||
}
|
||||
}
|
||||
|
||||
fn flatten_token_tree(tree: &TokenTree) -> TokenTree {
|
||||
match tree {
|
||||
TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing),
|
||||
TokenTree::Delimited(span, spacing, delim, tts) => {
|
||||
TokenTree::Delimited(*span, *spacing, *delim, tts.flattened())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn flattened(&self) -> TokenStream {
|
||||
fn can_skip(stream: &TokenStream) -> bool {
|
||||
stream.iter().all(|tree| match tree {
|
||||
TokenTree::Token(token, _) => !matches!(
|
||||
token.kind,
|
||||
token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
|
||||
),
|
||||
TokenTree::Delimited(.., inner) => can_skip(inner),
|
||||
})
|
||||
}
|
||||
|
||||
if can_skip(self) {
|
||||
return self.clone();
|
||||
}
|
||||
|
||||
self.iter().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
|
||||
}
|
||||
|
||||
// If `vec` is not empty, try to glue `tt` onto its last token. The return
|
||||
// value indicates if gluing took place.
|
||||
fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ pub fn walk_crate<'a, V: Visitor<'a>>(visitor: &mut V, krate: &'a Crate) -> V::R
|
|||
}
|
||||
|
||||
pub fn walk_local<'a, V: Visitor<'a>>(visitor: &mut V, local: &'a Local) -> V::Result {
|
||||
let Local { id: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local;
|
||||
let Local { id: _, super_: _, pat, ty, kind, span: _, colon_sp: _, attrs, tokens: _ } = local;
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
try_visit!(visitor.visit_pat(pat));
|
||||
visit_opt!(visitor, visit_ty, ty);
|
||||
|
|
@ -750,7 +750,7 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
|
|||
try_visit!(visitor.visit_pat(subpattern));
|
||||
try_visit!(visitor.visit_expr(guard_condition));
|
||||
}
|
||||
PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Missing | PatKind::Wild | PatKind::Rest | PatKind::Never => {}
|
||||
PatKind::Err(_guar) => {}
|
||||
PatKind::Tuple(elems) | PatKind::Slice(elems) | PatKind::Or(elems) => {
|
||||
walk_list!(visitor, visit_pat, elems);
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
fn lower_local(&mut self, l: &Local) -> &'hir hir::LetStmt<'hir> {
|
||||
// Let statements are allowed to have impl trait in bindings.
|
||||
let super_ = l.super_;
|
||||
let ty = l.ty.as_ref().map(|t| {
|
||||
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
});
|
||||
|
|
@ -109,7 +110,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let span = self.lower_span(l.span);
|
||||
let source = hir::LocalSource::Normal;
|
||||
self.lower_attrs(hir_id, &l.attrs, l.span);
|
||||
self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source })
|
||||
self.arena.alloc(hir::LetStmt { hir_id, super_, ty, pat, init, els, span, source })
|
||||
}
|
||||
|
||||
fn lower_block_check_mode(&mut self, b: &BlockCheckMode) -> hir::BlockCheckMode {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ use rustc_errors::ErrorGuaranteed;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{Asyncness, ResolverAstLowering};
|
||||
use rustc_span::{Ident, Span};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
use {rustc_ast as ast, rustc_hir as hir};
|
||||
|
||||
use super::{GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode};
|
||||
|
|
@ -85,7 +85,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
.delegation_fn_sigs
|
||||
.get(&local_def_id)
|
||||
.is_some_and(|sig| sig.has_self),
|
||||
None => self.tcx.associated_item(def_id).fn_has_self_parameter,
|
||||
None => self.tcx.associated_item(def_id).is_method(),
|
||||
},
|
||||
_ => span_bug!(span, "unexpected DefKind for delegation item"),
|
||||
}
|
||||
|
|
@ -234,12 +234,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::FnSig { decl, header, span }
|
||||
}
|
||||
|
||||
fn generate_param(&mut self, span: Span) -> (hir::Param<'hir>, NodeId) {
|
||||
fn generate_param(&mut self, idx: usize, span: Span) -> (hir::Param<'hir>, NodeId) {
|
||||
let pat_node_id = self.next_node_id();
|
||||
let pat_id = self.lower_node_id(pat_node_id);
|
||||
let ident = Ident::with_dummy_span(Symbol::intern(&format!("arg{idx}")));
|
||||
let pat = self.arena.alloc(hir::Pat {
|
||||
hir_id: pat_id,
|
||||
kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, Ident::empty(), None),
|
||||
kind: hir::PatKind::Binding(hir::BindingMode::NONE, pat_id, ident, None),
|
||||
span,
|
||||
default_binding_modes: false,
|
||||
});
|
||||
|
|
@ -247,9 +248,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(hir::Param { hir_id: self.next_id(), pat, ty_span: span, span }, pat_node_id)
|
||||
}
|
||||
|
||||
fn generate_arg(&mut self, param_id: HirId, span: Span) -> hir::Expr<'hir> {
|
||||
fn generate_arg(&mut self, idx: usize, param_id: HirId, span: Span) -> hir::Expr<'hir> {
|
||||
let segments = self.arena.alloc_from_iter(iter::once(hir::PathSegment {
|
||||
ident: Ident::empty(),
|
||||
ident: Ident::with_dummy_span(Symbol::intern(&format!("arg{idx}"))),
|
||||
hir_id: self.next_id(),
|
||||
res: Res::Local(param_id),
|
||||
args: None,
|
||||
|
|
@ -273,7 +274,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let mut args: Vec<hir::Expr<'_>> = Vec::with_capacity(param_count);
|
||||
|
||||
for idx in 0..param_count {
|
||||
let (param, pat_node_id) = this.generate_param(span);
|
||||
let (param, pat_node_id) = this.generate_param(idx, span);
|
||||
parameters.push(param);
|
||||
|
||||
let arg = if let Some(block) = block
|
||||
|
|
@ -289,7 +290,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
this.ident_and_label_to_local_id.insert(pat_node_id, param.pat.hir_id.local_id);
|
||||
this.lower_target_expr(&block)
|
||||
} else {
|
||||
this.generate_arg(param.pat.hir_id, span)
|
||||
this.generate_arg(idx, param.pat.hir_id, span)
|
||||
};
|
||||
args.push(arg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,12 +399,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
expr: &'hir hir::Expr<'hir>,
|
||||
span: Span,
|
||||
check_ident: Ident,
|
||||
check_hir_id: HirId,
|
||||
cond_ident: Ident,
|
||||
cond_hir_id: HirId,
|
||||
) -> &'hir hir::Expr<'hir> {
|
||||
let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
|
||||
let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
|
||||
self.expr_call(span, checker_fn, std::slice::from_ref(expr))
|
||||
let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
|
||||
let call_expr = self.expr_call_lang_item_fn_mut(
|
||||
span,
|
||||
hir::LangItem::ContractCheckEnsures,
|
||||
arena_vec![self; *cond_fn, *expr],
|
||||
);
|
||||
self.arena.alloc(call_expr)
|
||||
}
|
||||
|
||||
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
|
||||
|
|
|
|||
|
|
@ -645,7 +645,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(
|
||||
// Disallow `impl Trait` in foreign items.
|
||||
this.lower_fn_decl(fdec, i.id, sig.span, FnDeclKind::ExternFn, None),
|
||||
this.lower_fn_params_to_names(fdec),
|
||||
this.lower_fn_params_to_idents(fdec),
|
||||
)
|
||||
});
|
||||
|
||||
|
|
@ -833,7 +833,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}) => {
|
||||
// FIXME(contracts): Deny contract here since it won't apply to
|
||||
// any impl method or callees.
|
||||
let names = self.lower_fn_params_to_names(&sig.decl);
|
||||
let idents = self.lower_fn_params_to_idents(&sig.decl);
|
||||
let (generics, sig) = self.lower_method_sig(
|
||||
generics,
|
||||
sig,
|
||||
|
|
@ -851,7 +851,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
(
|
||||
*ident,
|
||||
generics,
|
||||
hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)),
|
||||
hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(idents)),
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
|
@ -1206,8 +1206,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let precond = if let Some(req) = &contract.requires {
|
||||
// Lower the precondition check intrinsic.
|
||||
let lowered_req = this.lower_expr_mut(&req);
|
||||
let req_span = this.mark_span_with_reason(
|
||||
DesugaringKind::Contract,
|
||||
lowered_req.span,
|
||||
None,
|
||||
);
|
||||
let precond = this.expr_call_lang_item_fn_mut(
|
||||
req.span,
|
||||
req_span,
|
||||
hir::LangItem::ContractCheckRequires,
|
||||
&*arena_vec![this; lowered_req],
|
||||
);
|
||||
|
|
@ -1217,6 +1222,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
};
|
||||
let (postcond, body) = if let Some(ens) = &contract.ensures {
|
||||
let ens_span = this.lower_span(ens.span);
|
||||
let ens_span =
|
||||
this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
|
||||
// Set up the postcondition `let` statement.
|
||||
let check_ident: Ident =
|
||||
Ident::from_str_and_span("__ensures_checker", ens_span);
|
||||
|
|
@ -1303,7 +1310,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// create a fake body so that the entire rest of the compiler doesn't have to deal with
|
||||
// this as a special case.
|
||||
return self.lower_fn_body(decl, contract, |this| {
|
||||
if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) {
|
||||
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) {
|
||||
let span = this.lower_span(span);
|
||||
let empty_block = hir::Block {
|
||||
hir_id: this.next_id(),
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
@ -917,7 +916,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs {
|
||||
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() }
|
||||
DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() }
|
||||
}
|
||||
|
||||
/// Lower an associated item constraint.
|
||||
|
|
@ -1247,7 +1246,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
safety: self.lower_safety(f.safety, hir::Safety::Safe),
|
||||
abi: self.lower_extern(f.ext),
|
||||
decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
|
||||
param_names: self.lower_fn_params_to_names(&f.decl),
|
||||
param_idents: self.lower_fn_params_to_idents(&f.decl),
|
||||
}))
|
||||
}
|
||||
TyKind::UnsafeBinder(f) => {
|
||||
|
|
@ -1494,20 +1493,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}))
|
||||
}
|
||||
|
||||
fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] {
|
||||
fn lower_fn_params_to_idents(&mut self, decl: &FnDecl) -> &'hir [Option<Ident>] {
|
||||
self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind {
|
||||
PatKind::Ident(_, ident, _) => {
|
||||
if ident.name != kw::Empty {
|
||||
Some(self.lower_ident(ident))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
PatKind::Missing => None,
|
||||
PatKind::Ident(_, ident, _) => Some(self.lower_ident(ident)),
|
||||
PatKind::Wild => Some(Ident::new(kw::Underscore, self.lower_span(param.pat.span))),
|
||||
_ => {
|
||||
self.dcx().span_delayed_bug(
|
||||
param.pat.span,
|
||||
"non-ident/wild param pat must trigger an error",
|
||||
"non-missing/ident/wild param pat must trigger an error",
|
||||
);
|
||||
None
|
||||
}
|
||||
|
|
@ -1771,24 +1765,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ident: Ident,
|
||||
is_anon_in_path: IsAnonInPath,
|
||||
) -> &'hir hir::Lifetime {
|
||||
debug_assert_ne!(ident.name, kw::Empty);
|
||||
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
|
||||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeName::Param(param)
|
||||
hir::LifetimeKind::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
hir::LifetimeName::Infer
|
||||
hir::LifetimeKind::Infer
|
||||
}
|
||||
LifetimeRes::Static { .. } => {
|
||||
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
hir::LifetimeName::Static
|
||||
hir::LifetimeKind::Static
|
||||
}
|
||||
LifetimeRes::Error => hir::LifetimeName::Error,
|
||||
LifetimeRes::Error => hir::LifetimeKind::Error,
|
||||
LifetimeRes::ElidedAnchor { .. } => {
|
||||
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
|
||||
}
|
||||
|
|
@ -2039,7 +2032,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_array_length_to_const_arg(&mut self, c: &AnonConst) -> &'hir hir::ConstArg<'hir> {
|
||||
match c.value.kind {
|
||||
// We cannot just match on `ExprKind::Underscore` as `(_)` is represented as
|
||||
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
|
||||
match c.value.peel_parens().kind {
|
||||
ExprKind::Underscore => {
|
||||
if !self.tcx.features().generic_arg_infer() {
|
||||
feature_err(
|
||||
|
|
@ -2223,6 +2218,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.attrs.insert(hir_id.local_id, a);
|
||||
}
|
||||
let local = hir::LetStmt {
|
||||
super_: None,
|
||||
hir_id,
|
||||
init,
|
||||
pat,
|
||||
|
|
@ -2392,7 +2388,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let r = hir::Lifetime::new(
|
||||
self.next_id(),
|
||||
Ident::new(kw::UnderscoreLifetime, self.lower_span(span)),
|
||||
hir::LifetimeName::ImplicitObjectLifetimeDefault,
|
||||
hir::LifetimeKind::ImplicitObjectLifetimeDefault,
|
||||
IsAnonInPath::No,
|
||||
);
|
||||
debug!("elided_dyn_bound: r={:?}", r);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let pat_hir_id = self.lower_node_id(pattern.id);
|
||||
let node = loop {
|
||||
match &pattern.kind {
|
||||
PatKind::Missing => break hir::PatKind::Missing,
|
||||
PatKind::Wild => break hir::PatKind::Wild,
|
||||
PatKind::Never => break hir::PatKind::Never,
|
||||
PatKind::Ident(binding_mode, ident, sub) => {
|
||||
|
|
|
|||
|
|
@ -448,8 +448,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
generic_args.args.insert_many(
|
||||
0,
|
||||
(start.as_u32()..end.as_u32()).map(|i| {
|
||||
let id = NodeId::from_u32(i);
|
||||
(start..end).map(|id| {
|
||||
let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span);
|
||||
GenericArg::Lifetime(l)
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -79,10 +79,6 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
| ExternAbi::SysV64 { .. }
|
||||
| ExternAbi::System { .. }
|
||||
| ExternAbi::EfiApi => Ok(()),
|
||||
// implementation details
|
||||
ExternAbi::RustIntrinsic => {
|
||||
Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail })
|
||||
}
|
||||
ExternAbi::Unadjusted => {
|
||||
Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@ ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$de
|
|||
.suggestion = remove the {$remove_descr}
|
||||
.label = `extern` block begins here
|
||||
|
||||
ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed
|
||||
.suggestion = specify an ABI
|
||||
.help = prior to Rust 2024, a default ABI was inferred
|
||||
|
||||
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
|
||||
.suggestion = remove the attribute
|
||||
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ impl<'a> AstValidator<'a> {
|
|||
fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
|
||||
for Param { pat, .. } in &decl.inputs {
|
||||
match pat.kind {
|
||||
PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
|
||||
PatKind::Missing | PatKind::Ident(BindingMode::NONE, _, None) | PatKind::Wild => {}
|
||||
PatKind::Ident(BindingMode::MUT, ident, None) => {
|
||||
report_err(pat.span, Some(ident), true)
|
||||
}
|
||||
|
|
@ -347,7 +347,7 @@ impl<'a> AstValidator<'a> {
|
|||
sym::forbid,
|
||||
sym::warn,
|
||||
];
|
||||
!arr.contains(&attr.name_or_empty()) && rustc_attr_parsing::is_builtin_attr(*attr)
|
||||
!attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)
|
||||
})
|
||||
.for_each(|attr| {
|
||||
if attr.is_doc_comment() {
|
||||
|
|
@ -684,7 +684,7 @@ impl<'a> AstValidator<'a> {
|
|||
self.dcx().emit_err(errors::PatternFnPointer { span });
|
||||
});
|
||||
if let Extern::Implicit(extern_span) = bfty.ext {
|
||||
self.maybe_lint_missing_abi(extern_span, ty.id);
|
||||
self.handle_missing_abi(extern_span, ty.id);
|
||||
}
|
||||
}
|
||||
TyKind::TraitObject(bounds, ..) => {
|
||||
|
|
@ -717,10 +717,12 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
|
||||
fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
|
||||
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
|
||||
// call site which do not have a macro backtrace. See #61963.
|
||||
if self
|
||||
if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {
|
||||
self.dcx().emit_err(errors::MissingAbi { span });
|
||||
} else if self
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_snippet(span)
|
||||
|
|
@ -945,8 +947,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
|
||||
let is_intrinsic =
|
||||
item.attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic);
|
||||
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
|
||||
if body.is_none() && !is_intrinsic {
|
||||
self.dcx().emit_err(errors::FnWithoutBody {
|
||||
span: item.span,
|
||||
|
|
@ -996,7 +997,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
if abi.is_none() {
|
||||
self.maybe_lint_missing_abi(*extern_span, item.id);
|
||||
self.handle_missing_abi(*extern_span, item.id);
|
||||
}
|
||||
self.with_in_extern_mod(*safety, |this| {
|
||||
visit::walk_item(this, item);
|
||||
|
|
@ -1370,7 +1371,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
},
|
||||
) = fk
|
||||
{
|
||||
self.maybe_lint_missing_abi(*extern_span, id);
|
||||
self.handle_missing_abi(*extern_span, id);
|
||||
}
|
||||
|
||||
// Functions without bodies cannot have patterns.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use rustc_ast::ParamKindOrd;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
|
||||
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
|
|
@ -394,11 +394,7 @@ pub(crate) struct EmptyLabelManySpans(pub Vec<Span>);
|
|||
|
||||
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
|
||||
impl Subdiagnostic for EmptyLabelManySpans {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.span_labels(self.0, "");
|
||||
}
|
||||
}
|
||||
|
|
@ -749,11 +745,7 @@ pub(crate) struct StableFeature {
|
|||
}
|
||||
|
||||
impl Subdiagnostic for StableFeature {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
_: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.arg("name", self.name);
|
||||
diag.arg("since", self.since);
|
||||
diag.help(fluent::ast_passes_stable_since);
|
||||
|
|
@ -823,3 +815,12 @@ pub(crate) struct DuplicatePreciseCapturing {
|
|||
#[label]
|
||||
pub bound2: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_extern_without_abi)]
|
||||
#[help]
|
||||
pub(crate) struct MissingAbi {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,10 @@ pub mod state;
|
|||
use std::borrow::Cow;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::token::{Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::token::{Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
|
||||
|
||||
pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
|
||||
State::new().nonterminal_to_string(nt)
|
||||
}
|
||||
|
||||
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
|
||||
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
|
||||
State::new().token_kind_to_string(tok)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::sync::Arc;
|
|||
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::comments::{Comment, CommentStyle};
|
||||
|
|
@ -876,14 +876,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
}
|
||||
|
||||
fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
|
||||
// We extract the token stream from the AST fragment and pretty print
|
||||
// it, rather than using AST pretty printing, because `Nonterminal` is
|
||||
// slated for removal in #124141. (This method will also then be
|
||||
// removed.)
|
||||
self.tts_to_string(&TokenStream::from_nonterminal_ast(nt))
|
||||
}
|
||||
|
||||
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
|
||||
fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
|
||||
self.token_kind_to_string_ext(tok, None)
|
||||
|
|
@ -976,8 +968,6 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
doc_comment_to_string(comment_kind, attr_style, data).into()
|
||||
}
|
||||
token::Eof => "<eof>".into(),
|
||||
|
||||
token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1336,6 +1326,9 @@ impl<'a> State<'a> {
|
|||
self.print_outer_attributes(&loc.attrs);
|
||||
self.space_if_not_bol();
|
||||
self.ibox(INDENT_UNIT);
|
||||
if loc.super_.is_some() {
|
||||
self.word_nbsp("super");
|
||||
}
|
||||
self.word_nbsp("let");
|
||||
|
||||
self.ibox(INDENT_UNIT);
|
||||
|
|
@ -1622,9 +1615,9 @@ impl<'a> State<'a> {
|
|||
fn print_pat(&mut self, pat: &ast::Pat) {
|
||||
self.maybe_print_comment(pat.span.lo());
|
||||
self.ann.pre(self, AnnNode::Pat(pat));
|
||||
/* Pat isn't normalized, but the beauty of it
|
||||
is that it doesn't matter */
|
||||
/* Pat isn't normalized, but the beauty of it is that it doesn't matter */
|
||||
match &pat.kind {
|
||||
PatKind::Missing => unreachable!(),
|
||||
PatKind::Wild => self.word("_"),
|
||||
PatKind::Never => self.word("!"),
|
||||
PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
|
||||
|
|
@ -1946,12 +1939,7 @@ impl<'a> State<'a> {
|
|||
if let Some(eself) = input.to_self() {
|
||||
self.print_explicit_self(&eself);
|
||||
} else {
|
||||
let invalid = if let PatKind::Ident(_, ident, _) = input.pat.kind {
|
||||
ident.name == kw::Empty
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if !invalid {
|
||||
if !matches!(input.pat.kind, PatKind::Missing) {
|
||||
self.print_pat(&input.pat);
|
||||
self.word(":");
|
||||
self.space();
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ use super::*;
|
|||
fn fun_to_string(
|
||||
decl: &ast::FnDecl,
|
||||
header: ast::FnHeader,
|
||||
name: Ident,
|
||||
ident: Ident,
|
||||
generics: &ast::Generics,
|
||||
) -> String {
|
||||
to_string(|s| {
|
||||
s.head("");
|
||||
s.print_fn(decl, header, Some(name), generics);
|
||||
s.print_fn(decl, header, Some(ident), generics);
|
||||
s.end(); // Close the head box.
|
||||
s.end(); // Close the outer box.
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use rustc_session::config::ExpectedValues;
|
|||
use rustc_session::lint::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
|
||||
|
|
@ -89,20 +88,6 @@ pub fn eval_condition(
|
|||
let cfg = match cfg {
|
||||
MetaItemInner::MetaItem(meta_item) => meta_item,
|
||||
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
|
||||
if let Some(features) = features {
|
||||
// we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
|
||||
// and `true`, and we want to keep the former working without feature gate
|
||||
gate_cfg(
|
||||
&(
|
||||
if *b { kw::True } else { kw::False },
|
||||
sym::cfg_boolean_literals,
|
||||
|features: &Features| features.cfg_boolean_literals(),
|
||||
),
|
||||
cfg.span(),
|
||||
sess,
|
||||
features,
|
||||
);
|
||||
}
|
||||
return *b;
|
||||
}
|
||||
_ => {
|
||||
|
|
@ -117,7 +102,7 @@ pub fn eval_condition(
|
|||
};
|
||||
|
||||
match &cfg.kind {
|
||||
MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
|
||||
MetaItemKind::List(mis) if cfg.has_name(sym::version) => {
|
||||
try_gate_cfg(sym::version, cfg.span, sess, features);
|
||||
let (min_version, span) = match &mis[..] {
|
||||
[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
|
||||
|
|
@ -164,18 +149,18 @@ pub fn eval_condition(
|
|||
|
||||
// The unwraps below may look dangerous, but we've already asserted
|
||||
// that they won't fail with the loop above.
|
||||
match cfg.name_or_empty() {
|
||||
sym::any => mis
|
||||
match cfg.name() {
|
||||
Some(sym::any) => mis
|
||||
.iter()
|
||||
// We don't use any() here, because we want to evaluate all cfg condition
|
||||
// as eval_condition can (and does) extra checks
|
||||
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
|
||||
sym::all => mis
|
||||
Some(sym::all) => mis
|
||||
.iter()
|
||||
// We don't use all() here, because we want to evaluate all cfg condition
|
||||
// as eval_condition can (and does) extra checks
|
||||
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
|
||||
sym::not => {
|
||||
Some(sym::not) => {
|
||||
let [mi] = mis.as_slice() else {
|
||||
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
|
||||
return false;
|
||||
|
|
@ -183,7 +168,7 @@ pub fn eval_condition(
|
|||
|
||||
!eval_condition(mi, sess, features, eval)
|
||||
}
|
||||
sym::target => {
|
||||
Some(sym::target) => {
|
||||
if let Some(features) = features
|
||||
&& !features.cfg_target_compact()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ impl SingleAttributeParser for TransparencyParser {
|
|||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args.name_value().and_then(|nv| nv.value_as_str()) {
|
||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||
Some(sym::semitransparent) => Some(Transparency::SemiTransparent),
|
||||
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||
Some(sym::opaque) => Some(Transparency::Opaque),
|
||||
Some(other) => {
|
||||
cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ impl<'sess> AttributeParser<'sess> {
|
|||
// if we're only looking for a single attribute,
|
||||
// skip all the ones we don't care about
|
||||
if let Some(expected) = self.parse_only {
|
||||
if attr.name_or_empty() != expected {
|
||||
if !attr.has_name(expected) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -232,7 +232,7 @@ impl<'sess> AttributeParser<'sess> {
|
|||
// that's expanded right? But no, sometimes, when parsing attributes on macros,
|
||||
// we already use the lowering logic and these are still there. So, when `omit_doc`
|
||||
// is set we *also* want to ignore these
|
||||
if omit_doc == OmitDoc::Skip && attr.name_or_empty() == sym::doc {
|
||||
if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +250,7 @@ impl<'sess> AttributeParser<'sess> {
|
|||
}))
|
||||
}
|
||||
// // FIXME: make doc attributes go through a proper attribute parser
|
||||
// ast::AttrKind::Normal(n) if n.name_or_empty() == sym::doc => {
|
||||
// ast::AttrKind::Normal(n) if n.has_name(sym::doc) => {
|
||||
// let p = GenericMetaItemParser::from_attr(&n, self.dcx());
|
||||
//
|
||||
// attributes.push(Attribute::Parsed(AttributeKind::DocComment {
|
||||
|
|
@ -320,7 +320,7 @@ impl<'sess> AttributeParser<'sess> {
|
|||
ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs {
|
||||
dspan: args.dspan,
|
||||
delim: args.delim,
|
||||
tokens: args.tokens.flattened(),
|
||||
tokens: args.tokens.clone(),
|
||||
}),
|
||||
// This is an inert key-value attribute - it will never be visible to macros
|
||||
// after it gets lowered to HIR. Therefore, we can extract literals to handle
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(rustdoc_internals)]
|
||||
|
|
|
|||
|
|
@ -485,25 +485,7 @@ impl<'a> MetaItemListParserContext<'a> {
|
|||
}
|
||||
|
||||
// or a path.
|
||||
let path =
|
||||
if let Some(TokenTree::Token(Token { kind: token::Interpolated(_), span, .. }, _)) =
|
||||
self.inside_delimiters.peek()
|
||||
{
|
||||
self.inside_delimiters.next();
|
||||
// We go into this path if an expr ended up in an attribute that
|
||||
// expansion did not turn into a literal. Say, `#[repr(align(macro!()))]`
|
||||
// where the macro didn't expand to a literal. An error is already given
|
||||
// for this at this point, and then we do continue. This makes this path
|
||||
// reachable...
|
||||
let e = self.dcx.span_delayed_bug(
|
||||
*span,
|
||||
"expr in place where literal is expected (builtin attr parsing)",
|
||||
);
|
||||
|
||||
return Some(MetaItemOrLitParser::Err(*span, e));
|
||||
} else {
|
||||
self.next_path()?
|
||||
};
|
||||
let path = self.next_path()?;
|
||||
|
||||
// Paths can be followed by:
|
||||
// - `(more meta items)` (another list)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub use super::polonius::legacy::{
|
|||
RichLocation, RustcFacts,
|
||||
};
|
||||
pub use super::region_infer::RegionInferenceContext;
|
||||
use crate::{BorrowCheckRootCtxt, do_mir_borrowck};
|
||||
|
||||
/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
|
||||
///
|
||||
|
|
@ -97,8 +98,9 @@ pub struct BodyWithBorrowckFacts<'tcx> {
|
|||
/// * Polonius is highly unstable, so expect regular changes in its signature or other details.
|
||||
pub fn get_body_with_borrowck_facts(
|
||||
tcx: TyCtxt<'_>,
|
||||
def: LocalDefId,
|
||||
def_id: LocalDefId,
|
||||
options: ConsumerOptions,
|
||||
) -> BodyWithBorrowckFacts<'_> {
|
||||
*super::do_mir_borrowck(tcx, def, Some(options)).1.unwrap()
|
||||
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def_id);
|
||||
*do_mir_borrowck(&mut root_cx, def_id, Some(options)).1.unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,6 +77,9 @@ pub(crate) fn categorize(context: PlaceContext) -> Option<DefUse> {
|
|||
// Debug info is neither def nor use.
|
||||
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
|
||||
|
||||
// Backwards incompatible drop hint is not a use, just a marker for linting.
|
||||
PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None,
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => {
|
||||
bug!("These statements are not allowed in this MIR phase")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -406,8 +406,8 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
|
|||
// started MIR borrowchecking with, so the region
|
||||
// constraints have already been taken. Use the data from
|
||||
// our `mbcx` instead.
|
||||
|vid| mbcx.regioncx.var_infos[vid].origin,
|
||||
|vid| mbcx.regioncx.var_infos[vid].universe,
|
||||
|vid| RegionVariableOrigin::Nll(mbcx.regioncx.definitions[vid].origin),
|
||||
|vid| mbcx.regioncx.definitions[vid].universe,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -487,7 +487,7 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
|
|||
let (sub_region, cause) = info?;
|
||||
|
||||
debug!(?sub_region, "cause = {:#?}", cause);
|
||||
let error = match (error_region, *sub_region) {
|
||||
let error = match (error_region, sub_region.kind()) {
|
||||
(Some(error_region), ty::ReVar(vid)) => RegionResolutionError::SubSupConflict(
|
||||
vid,
|
||||
region_var_origin(vid),
|
||||
|
|
|
|||
|
|
@ -647,7 +647,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
&& tc.polarity() == ty::PredicatePolarity::Positive
|
||||
&& supertrait_def_ids(tcx, tc.def_id())
|
||||
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
|
||||
.any(|item| item.fn_has_self_parameter)
|
||||
.any(|item| item.is_method())
|
||||
})
|
||||
}) {
|
||||
return None;
|
||||
|
|
@ -2500,11 +2500,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
);
|
||||
let ty::Tuple(params) = tupled_params.kind() else { return };
|
||||
|
||||
// Find the first argument with a matching type, get its name
|
||||
let Some(this_name) = params.iter().zip(tcx.hir_body_param_names(closure.body)).find_map(
|
||||
|(param_ty, name)| {
|
||||
// Find the first argument with a matching type and get its identifier.
|
||||
let Some(this_name) = params.iter().zip(tcx.hir_body_param_idents(closure.body)).find_map(
|
||||
|(param_ty, ident)| {
|
||||
// FIXME: also support deref for stuff like `Rc` arguments
|
||||
if param_ty.peel_refs() == local_ty { name } else { None }
|
||||
if param_ty.peel_refs() == local_ty { ident } else { None }
|
||||
},
|
||||
) else {
|
||||
return;
|
||||
|
|
@ -2959,21 +2959,27 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{name}`"));
|
||||
let name = if borrow_span.in_external_macro(self.infcx.tcx.sess.source_map()) {
|
||||
// Don't name local variables in external macros.
|
||||
"value".to_string()
|
||||
} else {
|
||||
format!("`{name}`")
|
||||
};
|
||||
|
||||
let mut err = self.path_does_not_live_long_enough(borrow_span, &name);
|
||||
|
||||
if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
|
||||
let region_name = annotation.emit(self, &mut err);
|
||||
|
||||
err.span_label(
|
||||
borrow_span,
|
||||
format!("`{name}` would have to be valid for `{region_name}`..."),
|
||||
format!("{name} would have to be valid for `{region_name}`..."),
|
||||
);
|
||||
|
||||
err.span_label(
|
||||
drop_span,
|
||||
format!(
|
||||
"...but `{}` will be dropped here, when the {} returns",
|
||||
name,
|
||||
"...but {name} will be dropped here, when the {} returns",
|
||||
self.infcx
|
||||
.tcx
|
||||
.opt_item_name(self.mir_def_id().to_def_id())
|
||||
|
|
@ -3011,7 +3017,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
} else {
|
||||
err.span_label(borrow_span, "borrowed value does not live long enough");
|
||||
err.span_label(drop_span, format!("`{name}` dropped here while still borrowed"));
|
||||
err.span_label(drop_span, format!("{name} dropped here while still borrowed"));
|
||||
|
||||
borrow_spans.args_subdiag(&mut err, |args_span| {
|
||||
crate::session_diagnostics::CaptureArgLabel::Capture {
|
||||
|
|
@ -3376,10 +3382,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
|
||||
Ok(string) => {
|
||||
let coro_prefix = if string.starts_with("async") {
|
||||
// `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize`
|
||||
// to `u32`.
|
||||
Some(5)
|
||||
let coro_prefix = if let Some(sub) = string.strip_prefix("async") {
|
||||
let trimmed_sub = sub.trim_end();
|
||||
if trimmed_sub.ends_with("gen") {
|
||||
// `async` is 5 chars long.
|
||||
Some((trimmed_sub.len() + 5) as _)
|
||||
} else {
|
||||
// `async` is 5 chars long.
|
||||
Some(5)
|
||||
}
|
||||
} else if string.starts_with("gen") {
|
||||
// `gen` is 3 chars long
|
||||
Some(3)
|
||||
|
|
@ -3774,7 +3785,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
method_args,
|
||||
*fn_span,
|
||||
call_source.from_hir_call(),
|
||||
self.infcx.tcx.fn_arg_names(method_did)[0],
|
||||
self.infcx.tcx.fn_arg_idents(method_did)[0],
|
||||
)
|
||||
{
|
||||
err.note(format!("borrow occurs due to deref coercion to `{deref_target_ty}`"));
|
||||
|
|
|
|||
|
|
@ -95,7 +95,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
&& let hir::def::Res::Local(hir_id) = p.res
|
||||
&& let hir::Node::Pat(pat) = tcx.hir_node(hir_id)
|
||||
{
|
||||
err.span_label(pat.span, format!("binding `{ident}` declared here"));
|
||||
if !ident.span.in_external_macro(tcx.sess.source_map()) {
|
||||
err.span_label(pat.span, format!("binding `{ident}` declared here"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,7 @@ use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify};
|
|||
use rustc_hir::def::{CtorKind, Namespace};
|
||||
use rustc_hir::{self as hir, CoroutineKind, LangItem};
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::{
|
||||
BoundRegionConversionTime, NllRegionVariableOrigin, RegionVariableOrigin,
|
||||
};
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, NllRegionVariableOrigin};
|
||||
use rustc_infer::traits::SelectionError;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{
|
||||
|
|
@ -587,7 +585,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// this by hooking into the pretty printer and telling it to label the
|
||||
// lifetimes without names with the value `'0`.
|
||||
if let ty::Ref(region, ..) = ty.kind() {
|
||||
match **region {
|
||||
match region.kind() {
|
||||
ty::ReBound(_, ty::BoundRegion { kind: br, .. })
|
||||
| ty::RePlaceholder(ty::PlaceholderRegion {
|
||||
bound: ty::BoundRegion { kind: br, .. },
|
||||
|
|
@ -607,7 +605,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
||||
|
||||
let region = if let ty::Ref(region, ..) = ty.kind() {
|
||||
match **region {
|
||||
match region.kind() {
|
||||
ty::ReBound(_, ty::BoundRegion { kind: br, .. })
|
||||
| ty::RePlaceholder(ty::PlaceholderRegion {
|
||||
bound: ty::BoundRegion { kind: br, .. },
|
||||
|
|
@ -633,9 +631,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, '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
|
||||
if let Some(origin) = self.regioncx.definitions.get(outlived)
|
||||
&& let NllRegionVariableOrigin::Placeholder(_) = origin.origin
|
||||
&& let ConstraintCategory::Predicate(span) = constraint.category
|
||||
{
|
||||
Some(span)
|
||||
|
|
@ -1029,7 +1026,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
method_args,
|
||||
*fn_span,
|
||||
call_source.from_hir_call(),
|
||||
self.infcx.tcx.fn_arg_names(method_did)[0],
|
||||
self.infcx.tcx.fn_arg_idents(method_did)[0],
|
||||
);
|
||||
|
||||
return FnSelfUse {
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
fold_regions(tcx, ty, |region, _| match *region {
|
||||
fold_regions(tcx, ty, |region, _| match region.kind() {
|
||||
ty::ReVar(vid) => self.to_error_region(vid).unwrap_or(region),
|
||||
_ => region,
|
||||
})
|
||||
|
|
@ -198,7 +198,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
/// Returns `true` if a closure is inferred to be an `FnMut` closure.
|
||||
fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
|
||||
if let Some(ty::ReLateParam(late_param)) = self.to_error_region(fr).as_deref()
|
||||
if let Some(r) = self.to_error_region(fr)
|
||||
&& let ty::ReLateParam(late_param) = r.kind()
|
||||
&& let ty::LateParamRegionKind::ClosureEnv = late_param.kind
|
||||
&& let DefiningTy::Closure(_, args) = self.regioncx.universal_regions().defining_ty
|
||||
{
|
||||
|
|
@ -832,7 +833,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if let (Some(f), Some(outlived_f)) =
|
||||
(self.to_error_region(fr), self.to_error_region(outlived_fr))
|
||||
{
|
||||
if *outlived_f != ty::ReStatic {
|
||||
if outlived_f.kind() != ty::ReStatic {
|
||||
return;
|
||||
}
|
||||
let suitable_region = self.infcx.tcx.is_suitable_region(self.mir_def_id(), f);
|
||||
|
|
@ -887,7 +888,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// Skip `async` desugaring `impl Future`.
|
||||
}
|
||||
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
|
||||
if lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault {
|
||||
if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault {
|
||||
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
|
||||
} else {
|
||||
spans_suggs.push((lt.ident.span, "'a".to_string()));
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
let tcx = self.infcx.tcx;
|
||||
|
||||
debug!("give_region_a_name: error_region = {:?}", error_region);
|
||||
match *error_region {
|
||||
match error_region.kind() {
|
||||
ty::ReEarlyParam(ebr) => ebr.has_name().then(|| {
|
||||
let def_id = tcx.generics_of(self.mir_def_id()).region_param(ebr, tcx).def_id;
|
||||
let span = tcx.hir_span_if_local(def_id).unwrap_or(DUMMY_SP);
|
||||
|
|
@ -896,7 +896,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
&self,
|
||||
fr: RegionVid,
|
||||
) -> Option<RegionName> {
|
||||
let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else {
|
||||
let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else {
|
||||
return None;
|
||||
};
|
||||
if region.has_name() {
|
||||
|
|
@ -912,7 +912,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
|
||||
let found = tcx
|
||||
.any_free_region_meets(&tcx.type_of(region_parent).instantiate_identity(), |r| {
|
||||
*r == ty::ReEarlyParam(region)
|
||||
r.kind() == ty::ReEarlyParam(region)
|
||||
});
|
||||
|
||||
Some(RegionName {
|
||||
|
|
@ -931,7 +931,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
&self,
|
||||
fr: RegionVid,
|
||||
) -> Option<RegionName> {
|
||||
let ty::ReEarlyParam(region) = *self.to_error_region(fr)? else {
|
||||
let ty::ReEarlyParam(region) = self.to_error_region(fr)?.kind() else {
|
||||
return None;
|
||||
};
|
||||
if region.has_name() {
|
||||
|
|
@ -1007,7 +1007,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
if data.projection_term.self_ty() == ty => {}
|
||||
_ => return false,
|
||||
}
|
||||
tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyParam(region))
|
||||
tcx.any_free_region_meets(pred, |r| r.kind() == ty::ReEarlyParam(region))
|
||||
})
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(rustdoc_internals)]
|
||||
|
|
@ -21,6 +21,8 @@ use std::cell::RefCell;
|
|||
use std::marker::PhantomData;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
use borrow_set::LocalsStateAtExit;
|
||||
use root_cx::BorrowCheckRootCtxt;
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::graph::dominators::Dominators;
|
||||
|
|
@ -35,7 +37,9 @@ use rustc_infer::infer::{
|
|||
};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode};
|
||||
use rustc_middle::ty::{
|
||||
self, ParamEnv, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypingMode, fold_regions,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_mir_dataflow::impls::{
|
||||
EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces,
|
||||
|
|
@ -45,7 +49,7 @@ use rustc_mir_dataflow::move_paths::{
|
|||
};
|
||||
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
use smallvec::SmallVec;
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
|
|
@ -73,7 +77,6 @@ mod def_use;
|
|||
mod diagnostics;
|
||||
mod member_constraints;
|
||||
mod nll;
|
||||
mod opaque_types;
|
||||
mod path_utils;
|
||||
mod place_ext;
|
||||
mod places_conflict;
|
||||
|
|
@ -81,6 +84,7 @@ mod polonius;
|
|||
mod prefixes;
|
||||
mod region_infer;
|
||||
mod renumber;
|
||||
mod root_cx;
|
||||
mod session_diagnostics;
|
||||
mod type_check;
|
||||
mod universal_regions;
|
||||
|
|
@ -102,64 +106,202 @@ pub fn provide(providers: &mut Providers) {
|
|||
*providers = Providers { mir_borrowck, ..*providers };
|
||||
}
|
||||
|
||||
fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
|
||||
/// Provider for `query mir_borrowck`. Similar to `typeck`, this must
|
||||
/// only be called for typeck roots which will then borrowck all
|
||||
/// nested bodies as well.
|
||||
fn mir_borrowck(
|
||||
tcx: TyCtxt<'_>,
|
||||
def: LocalDefId,
|
||||
) -> Result<&ConcreteOpaqueTypes<'_>, ErrorGuaranteed> {
|
||||
assert!(!tcx.is_typeck_child(def.to_def_id()));
|
||||
let (input_body, _) = tcx.mir_promoted(def);
|
||||
debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
|
||||
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
if input_body.should_skip() || input_body.tainted_by_errors.is_some() {
|
||||
debug!("Skipping borrowck because of injected body or tainted body");
|
||||
// Let's make up a borrowck result! Fun times!
|
||||
let result = BorrowCheckResult {
|
||||
concrete_opaque_types: FxIndexMap::default(),
|
||||
closure_requirements: None,
|
||||
used_mut_upvars: SmallVec::new(),
|
||||
tainted_by_errors: input_body.tainted_by_errors,
|
||||
};
|
||||
return tcx.arena.alloc(result);
|
||||
if let Some(guar) = input_body.tainted_by_errors {
|
||||
debug!("Skipping borrowck because of tainted body");
|
||||
Err(guar)
|
||||
} else if input_body.should_skip() {
|
||||
debug!("Skipping borrowck because of injected body");
|
||||
let opaque_types = ConcreteOpaqueTypes(Default::default());
|
||||
Ok(tcx.arena.alloc(opaque_types))
|
||||
} else {
|
||||
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
|
||||
let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
|
||||
do_mir_borrowck(&mut root_cx, def, None).0;
|
||||
debug_assert!(closure_requirements.is_none());
|
||||
debug_assert!(used_mut_upvars.is_empty());
|
||||
root_cx.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
/// Data propagated to the typeck parent by nested items.
|
||||
/// This should always be empty for the typeck root.
|
||||
#[derive(Debug)]
|
||||
struct PropagatedBorrowCheckResults<'tcx> {
|
||||
closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
|
||||
used_mut_upvars: SmallVec<[FieldIdx; 8]>,
|
||||
}
|
||||
|
||||
/// After we borrow check a closure, we are left with various
|
||||
/// requirements that we have inferred between the free regions that
|
||||
/// appear in the closure's signature or on its field types. These
|
||||
/// requirements are then verified and proved by the closure's
|
||||
/// creating function. This struct encodes those requirements.
|
||||
///
|
||||
/// The requirements are listed as being between various `RegionVid`. The 0th
|
||||
/// region refers to `'static`; subsequent region vids refer to the free
|
||||
/// regions that appear in the closure (or coroutine's) type, in order of
|
||||
/// appearance. (This numbering is actually defined by the `UniversalRegions`
|
||||
/// struct in the NLL region checker. See for example
|
||||
/// `UniversalRegions::closure_mapping`.) Note the free regions in the
|
||||
/// closure's signature and captures are erased.
|
||||
///
|
||||
/// Example: If type check produces a closure with the closure args:
|
||||
///
|
||||
/// ```text
|
||||
/// ClosureArgs = [
|
||||
/// 'a, // From the parent.
|
||||
/// 'b,
|
||||
/// i8, // the "closure kind"
|
||||
/// for<'x> fn(&'<erased> &'x u32) -> &'x u32, // the "closure signature"
|
||||
/// &'<erased> String, // some upvar
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// We would "renumber" each free region to a unique vid, as follows:
|
||||
///
|
||||
/// ```text
|
||||
/// ClosureArgs = [
|
||||
/// '1, // From the parent.
|
||||
/// '2,
|
||||
/// i8, // the "closure kind"
|
||||
/// for<'x> fn(&'3 &'x u32) -> &'x u32, // the "closure signature"
|
||||
/// &'4 String, // some upvar
|
||||
/// ]
|
||||
/// ```
|
||||
///
|
||||
/// Now the code might impose a requirement like `'1: '2`. When an
|
||||
/// instance of the closure is created, the corresponding free regions
|
||||
/// can be extracted from its type and constrained to have the given
|
||||
/// outlives relationship.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ClosureRegionRequirements<'tcx> {
|
||||
/// The number of external regions defined on the closure. In our
|
||||
/// example above, it would be 3 -- one for `'static`, then `'1`
|
||||
/// and `'2`. This is just used for a sanity check later on, to
|
||||
/// make sure that the number of regions we see at the callsite
|
||||
/// matches.
|
||||
pub num_external_vids: usize,
|
||||
|
||||
/// Requirements between the various free regions defined in
|
||||
/// indices.
|
||||
pub outlives_requirements: Vec<ClosureOutlivesRequirement<'tcx>>,
|
||||
}
|
||||
|
||||
/// Indicates an outlives-constraint between a type or between two
|
||||
/// free regions declared on the closure.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClosureOutlivesRequirement<'tcx> {
|
||||
// This region or type ...
|
||||
pub subject: ClosureOutlivesSubject<'tcx>,
|
||||
|
||||
// ... must outlive this one.
|
||||
pub outlived_free_region: ty::RegionVid,
|
||||
|
||||
// If not, report an error here ...
|
||||
pub blame_span: Span,
|
||||
|
||||
// ... due to this reason.
|
||||
pub category: ConstraintCategory<'tcx>,
|
||||
}
|
||||
|
||||
// Make sure this enum doesn't unintentionally grow
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
|
||||
|
||||
/// The subject of a `ClosureOutlivesRequirement` -- that is, the thing
|
||||
/// that must outlive some region.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum ClosureOutlivesSubject<'tcx> {
|
||||
/// Subject is a type, typically a type parameter, but could also
|
||||
/// be a projection. Indicates a requirement like `T: 'a` being
|
||||
/// passed to the caller, where the type here is `T`.
|
||||
Ty(ClosureOutlivesSubjectTy<'tcx>),
|
||||
|
||||
/// Subject is a free region from the closure. Indicates a requirement
|
||||
/// like `'a: 'b` being passed to the caller; the region here is `'a`.
|
||||
Region(ty::RegionVid),
|
||||
}
|
||||
|
||||
/// Represents a `ty::Ty` for use in [`ClosureOutlivesSubject`].
|
||||
///
|
||||
/// This abstraction is necessary because the type may include `ReVar` regions,
|
||||
/// which is what we use internally within NLL code, and they can't be used in
|
||||
/// a query response.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct ClosureOutlivesSubjectTy<'tcx> {
|
||||
inner: Ty<'tcx>,
|
||||
}
|
||||
// DO NOT implement `TypeVisitable` or `TypeFoldable` traits, because this
|
||||
// type is not recognized as a binder for late-bound region.
|
||||
impl<'tcx, I> !TypeVisitable<I> for ClosureOutlivesSubjectTy<'tcx> {}
|
||||
impl<'tcx, I> !TypeFoldable<I> for ClosureOutlivesSubjectTy<'tcx> {}
|
||||
|
||||
impl<'tcx> ClosureOutlivesSubjectTy<'tcx> {
|
||||
/// All regions of `ty` must be of kind `ReVar` and must represent
|
||||
/// universal regions *external* to the closure.
|
||||
pub fn bind(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
|
||||
let inner = fold_regions(tcx, ty, |r, depth| match r.kind() {
|
||||
ty::ReVar(vid) => {
|
||||
let br = ty::BoundRegion {
|
||||
var: ty::BoundVar::from_usize(vid.index()),
|
||||
kind: ty::BoundRegionKind::Anon,
|
||||
};
|
||||
ty::Region::new_bound(tcx, depth, br)
|
||||
}
|
||||
_ => bug!("unexpected region in ClosureOutlivesSubjectTy: {r:?}"),
|
||||
});
|
||||
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
let borrowck_result = do_mir_borrowck(tcx, def, None).0;
|
||||
debug!("mir_borrowck done");
|
||||
|
||||
tcx.arena.alloc(borrowck_result)
|
||||
pub fn instantiate(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut map: impl FnMut(ty::RegionVid) -> ty::Region<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
fold_regions(tcx, self.inner, |r, depth| match r.kind() {
|
||||
ty::ReBound(debruijn, br) => {
|
||||
debug_assert_eq!(debruijn, depth);
|
||||
map(ty::RegionVid::from_usize(br.var.index()))
|
||||
}
|
||||
_ => bug!("unexpected region {r:?}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Perform the actual borrow checking.
|
||||
///
|
||||
/// Use `consumer_options: None` for the default behavior of returning
|
||||
/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
|
||||
/// to the given [`ConsumerOptions`].
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
/// [`PropagatedBorrowCheckResults`] only. Otherwise, return [`BodyWithBorrowckFacts`]
|
||||
/// according to the given [`ConsumerOptions`].
|
||||
///
|
||||
/// For nested bodies this should only be called through `root_cx.get_or_insert_nested`.
|
||||
#[instrument(skip(root_cx), level = "debug")]
|
||||
fn do_mir_borrowck<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
def: LocalDefId,
|
||||
consumer_options: Option<ConsumerOptions>,
|
||||
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
|
||||
) -> (PropagatedBorrowCheckResults<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
|
||||
let tcx = root_cx.tcx;
|
||||
let infcx = BorrowckInferCtxt::new(tcx, def);
|
||||
let (input_body, promoted) = tcx.mir_promoted(def);
|
||||
let input_body: &Body<'_> = &input_body.borrow();
|
||||
let input_promoted: &IndexSlice<_, _> = &promoted.borrow();
|
||||
if let Some(e) = input_body.tainted_by_errors {
|
||||
infcx.set_tainted_by_errors(e);
|
||||
}
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
|
||||
for var_debug_info in &input_body.var_debug_info {
|
||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||
if let Some(local) = place.as_local() {
|
||||
if let Some(prev_name) = local_names[local]
|
||||
&& var_debug_info.name != prev_name
|
||||
{
|
||||
span_bug!(
|
||||
var_debug_info.source_info.span,
|
||||
"local {:?} has many names (`{}` vs `{}`)",
|
||||
local,
|
||||
prev_name,
|
||||
var_debug_info.name
|
||||
);
|
||||
}
|
||||
local_names[local] = Some(var_debug_info.name);
|
||||
}
|
||||
}
|
||||
root_cx.set_tainted_by_errors(e);
|
||||
}
|
||||
|
||||
// Replace all regions with fresh inference variables. This
|
||||
|
|
@ -168,7 +310,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
// will have a lifetime tied to the inference context.
|
||||
let mut body_owned = input_body.clone();
|
||||
let mut promoted = input_promoted.to_owned();
|
||||
let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
|
||||
let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
|
||||
let body = &body_owned; // no further changes
|
||||
|
||||
let location_table = PoloniusLocationTable::new(body);
|
||||
|
|
@ -185,15 +327,15 @@ fn do_mir_borrowck<'tcx>(
|
|||
// Compute non-lexical lifetimes.
|
||||
let nll::NllOutput {
|
||||
regioncx,
|
||||
concrete_opaque_types,
|
||||
polonius_input,
|
||||
polonius_output,
|
||||
opt_closure_req,
|
||||
nll_errors,
|
||||
polonius_diagnostics,
|
||||
} = nll::compute_regions(
|
||||
root_cx,
|
||||
&infcx,
|
||||
free_regions,
|
||||
universal_regions,
|
||||
body,
|
||||
&promoted,
|
||||
&location_table,
|
||||
|
|
@ -206,31 +348,23 @@ fn do_mir_borrowck<'tcx>(
|
|||
// Dump MIR results into a file, if that is enabled. This lets us
|
||||
// write unit-tests, as well as helping with debugging.
|
||||
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
|
||||
|
||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||
// information.
|
||||
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
|
||||
nll::dump_annotation(
|
||||
polonius::dump_polonius_mir(
|
||||
&infcx,
|
||||
body,
|
||||
®ioncx,
|
||||
&opt_closure_req,
|
||||
&concrete_opaque_types,
|
||||
diags_buffer,
|
||||
&borrow_set,
|
||||
polonius_diagnostics.as_ref(),
|
||||
);
|
||||
|
||||
let movable_coroutine =
|
||||
// The first argument is the coroutine type passed by value
|
||||
if let Some(local) = body.local_decls.raw.get(1)
|
||||
// Get the interior types and args which typeck computed
|
||||
&& let ty::Coroutine(def_id, _) = *local.ty.kind()
|
||||
&& tcx.coroutine_movability(def_id) == hir::Movability::Movable
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// We also have a `#[rustc_regions]` annotation that causes us to dump
|
||||
// information.
|
||||
nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
|
||||
|
||||
let movable_coroutine = body.coroutine.is_some()
|
||||
&& tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
|
||||
|
||||
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
|
||||
// While promoteds should mostly be correct by construction, we need to check them for
|
||||
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
|
||||
for promoted_body in &promoted {
|
||||
|
|
@ -240,6 +374,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
// this check out of `MirBorrowckCtxt`, actually doing so is far from trivial.
|
||||
let move_data = MoveData::gather_moves(promoted_body, tcx, |_| true);
|
||||
let mut promoted_mbcx = MirBorrowckCtxt {
|
||||
root_cx,
|
||||
infcx: &infcx,
|
||||
body: promoted_body,
|
||||
move_data: &move_data,
|
||||
|
|
@ -247,7 +382,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
location_table: &location_table,
|
||||
movable_coroutine,
|
||||
fn_self_span_reported: Default::default(),
|
||||
locals_are_invalidated_at_exit,
|
||||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
uninitialized_error_reported: Default::default(),
|
||||
|
|
@ -279,13 +413,33 @@ fn do_mir_borrowck<'tcx>(
|
|||
promoted_mbcx.report_move_errors();
|
||||
}
|
||||
|
||||
let mut local_names = IndexVec::from_elem(None, &body.local_decls);
|
||||
for var_debug_info in &body.var_debug_info {
|
||||
if let VarDebugInfoContents::Place(place) = var_debug_info.value {
|
||||
if let Some(local) = place.as_local() {
|
||||
if let Some(prev_name) = local_names[local]
|
||||
&& var_debug_info.name != prev_name
|
||||
{
|
||||
span_bug!(
|
||||
var_debug_info.source_info.span,
|
||||
"local {:?} has many names (`{}` vs `{}`)",
|
||||
local,
|
||||
prev_name,
|
||||
var_debug_info.name
|
||||
);
|
||||
}
|
||||
local_names[local] = Some(var_debug_info.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut mbcx = MirBorrowckCtxt {
|
||||
root_cx,
|
||||
infcx: &infcx,
|
||||
body,
|
||||
move_data: &move_data,
|
||||
location_table: &location_table,
|
||||
movable_coroutine,
|
||||
locals_are_invalidated_at_exit,
|
||||
fn_self_span_reported: Default::default(),
|
||||
access_place_error_reported: Default::default(),
|
||||
reservation_error_reported: Default::default(),
|
||||
|
|
@ -298,9 +452,9 @@ fn do_mir_borrowck<'tcx>(
|
|||
local_names,
|
||||
region_names: RefCell::default(),
|
||||
next_region_name: RefCell::new(1),
|
||||
polonius_output,
|
||||
move_errors: Vec::new(),
|
||||
diags_buffer,
|
||||
polonius_output: polonius_output.as_deref(),
|
||||
polonius_diagnostics: polonius_diagnostics.as_ref(),
|
||||
};
|
||||
|
||||
|
|
@ -317,16 +471,6 @@ fn do_mir_borrowck<'tcx>(
|
|||
|
||||
mbcx.report_move_errors();
|
||||
|
||||
// If requested, dump polonius MIR.
|
||||
polonius::dump_polonius_mir(
|
||||
&infcx,
|
||||
body,
|
||||
®ioncx,
|
||||
&borrow_set,
|
||||
polonius_diagnostics.as_ref(),
|
||||
&opt_closure_req,
|
||||
);
|
||||
|
||||
// For each non-user used mutable variable, check if it's been assigned from
|
||||
// a user-declared local. If so, then put that local into the used_mut set.
|
||||
// Note that this set is expected to be small - only upvars from closures
|
||||
|
|
@ -347,17 +491,16 @@ fn do_mir_borrowck<'tcx>(
|
|||
|
||||
debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
|
||||
mbcx.lint_unused_mut();
|
||||
let tainted_by_errors = mbcx.emit_errors();
|
||||
if let Some(guar) = mbcx.emit_errors() {
|
||||
mbcx.root_cx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
let result = BorrowCheckResult {
|
||||
concrete_opaque_types: concrete_opaque_types.into_inner(),
|
||||
let result = PropagatedBorrowCheckResults {
|
||||
closure_requirements: opt_closure_req,
|
||||
used_mut_upvars: mbcx.used_mut_upvars,
|
||||
tainted_by_errors,
|
||||
};
|
||||
|
||||
let body_with_facts = if consumer_options.is_some() {
|
||||
let output_facts = mbcx.polonius_output;
|
||||
Some(Box::new(BodyWithBorrowckFacts {
|
||||
body: body_owned,
|
||||
promoted,
|
||||
|
|
@ -365,7 +508,7 @@ fn do_mir_borrowck<'tcx>(
|
|||
region_inference_context: regioncx,
|
||||
location_table: polonius_input.as_ref().map(|_| location_table),
|
||||
input_facts: polonius_input,
|
||||
output_facts,
|
||||
output_facts: polonius_output,
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -488,6 +631,7 @@ impl<'tcx> Deref for BorrowckInferCtxt<'tcx> {
|
|||
}
|
||||
|
||||
struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
||||
root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &'infcx BorrowckInferCtxt<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
move_data: &'a MoveData<'tcx>,
|
||||
|
|
@ -497,13 +641,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
location_table: &'a PoloniusLocationTable,
|
||||
|
||||
movable_coroutine: bool,
|
||||
/// This keeps track of whether local variables are free-ed when the function
|
||||
/// exits even without a `StorageDead`, which appears to be the case for
|
||||
/// constants.
|
||||
///
|
||||
/// I'm not sure this is the right approach - @eddyb could you try and
|
||||
/// figure this out?
|
||||
locals_are_invalidated_at_exit: bool,
|
||||
/// This field keeps track of when borrow errors are reported in the access_place function
|
||||
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
|
||||
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
|
||||
|
|
@ -551,12 +688,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
|
|||
/// The counter for generating new region names.
|
||||
next_region_name: RefCell<usize>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<Box<PoloniusOutput>>,
|
||||
|
||||
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
|
||||
move_errors: Vec<MoveError<'tcx>>,
|
||||
|
||||
/// Results of Polonius analysis.
|
||||
polonius_output: Option<&'a PoloniusOutput>,
|
||||
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
|
||||
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
|
||||
}
|
||||
|
|
@ -780,13 +916,20 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<
|
|||
| TerminatorKind::Return
|
||||
| TerminatorKind::TailCall { .. }
|
||||
| TerminatorKind::CoroutineDrop => {
|
||||
// Returning from the function implicitly kills storage for all locals and statics.
|
||||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
match self.borrow_set.locals_state_at_exit() {
|
||||
LocalsStateAtExit::AllAreInvalidated => {
|
||||
// Returning from the function implicitly kills storage for all locals and statics.
|
||||
// Often, the storage will already have been killed by an explicit
|
||||
// StorageDead, but we don't always emit those (notably on unwind paths),
|
||||
// so this "extra check" serves as a kind of backup.
|
||||
for i in state.borrows.iter() {
|
||||
let borrow = &self.borrow_set[i];
|
||||
self.check_for_invalidation_at_exit(loc, borrow, span);
|
||||
}
|
||||
}
|
||||
// If we do not implicitly invalidate all locals on exit,
|
||||
// we check for conflicts when dropping or moving this local.
|
||||
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1143,7 +1286,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
error_reported
|
||||
}
|
||||
|
||||
/// Through #123739, backward incompatible drops (BIDs) are introduced.
|
||||
/// Through #123739, `BackwardIncompatibleDropHint`s (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(
|
||||
|
|
@ -1361,11 +1504,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
| AggregateKind::CoroutineClosure(def_id, _)
|
||||
| AggregateKind::Coroutine(def_id, _) => {
|
||||
let def_id = def_id.expect_local();
|
||||
let BorrowCheckResult { used_mut_upvars, .. } =
|
||||
self.infcx.tcx.mir_borrowck(def_id);
|
||||
let used_mut_upvars = self.root_cx.used_mut_upvars(def_id);
|
||||
debug!("{:?} used_mut_upvars={:?}", def_id, used_mut_upvars);
|
||||
for field in used_mut_upvars {
|
||||
self.propagate_closure_used_mut_upvar(&operands[*field]);
|
||||
// FIXME: We're cloning the `SmallVec` here to avoid borrowing `root_cx`
|
||||
// when calling `propagate_closure_used_mut_upvar`. This should ideally
|
||||
// be unnecessary.
|
||||
for field in used_mut_upvars.clone() {
|
||||
self.propagate_closure_used_mut_upvar(&operands[field]);
|
||||
}
|
||||
}
|
||||
AggregateKind::Adt(..)
|
||||
|
|
@ -1556,22 +1701,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
// we'll have a memory leak) and assume that all statics have a destructor.
|
||||
//
|
||||
// FIXME: allow thread-locals to borrow other thread locals?
|
||||
|
||||
let (might_be_alive, will_be_dropped) =
|
||||
if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
|
||||
// Thread-locals might be dropped after the function exits
|
||||
// We have to dereference the outer reference because
|
||||
// borrows don't conflict behind shared references.
|
||||
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
|
||||
(true, true)
|
||||
} else {
|
||||
(false, self.locals_are_invalidated_at_exit)
|
||||
};
|
||||
|
||||
if !will_be_dropped {
|
||||
debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
|
||||
return;
|
||||
}
|
||||
let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
|
||||
// Thread-locals might be dropped after the function exits
|
||||
// We have to dereference the outer reference because
|
||||
// borrows don't conflict behind shared references.
|
||||
root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let sd = if might_be_alive { Deep } else { Shallow(None) };
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ use std::str::FromStr;
|
|||
use polonius_engine::{Algorithm, Output};
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
|
||||
use rustc_middle::mir::{
|
||||
Body, ClosureOutlivesSubject, ClosureRegionRequirements, PassWhere, Promoted, create_dump_file,
|
||||
dump_enabled, dump_mir,
|
||||
};
|
||||
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_mir_dataflow::ResultsCursor;
|
||||
|
|
@ -24,8 +21,7 @@ use tracing::{debug, instrument};
|
|||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::consumers::ConsumerOptions;
|
||||
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
|
||||
use crate::opaque_types::ConcreteOpaqueTypes;
|
||||
use crate::diagnostics::RegionErrors;
|
||||
use crate::polonius::PoloniusDiagnosticsContext;
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
|
|
@ -33,13 +29,15 @@ use crate::polonius::legacy::{
|
|||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::type_check::{self, MirTypeckResults};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{BorrowckInferCtxt, polonius, renumber};
|
||||
use crate::{
|
||||
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
polonius, renumber,
|
||||
};
|
||||
|
||||
/// The output of `nll::compute_regions`. This includes the computed `RegionInferenceContext`, any
|
||||
/// closure requirements to propagate, and any generated errors.
|
||||
pub(crate) struct NllOutput<'tcx> {
|
||||
pub regioncx: RegionInferenceContext<'tcx>,
|
||||
pub concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
|
||||
pub polonius_input: Option<Box<PoloniusFacts>>,
|
||||
pub polonius_output: Option<Box<PoloniusOutput>>,
|
||||
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
|
||||
|
|
@ -78,6 +76,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
|
|||
///
|
||||
/// This may result in errors being reported.
|
||||
pub(crate) fn compute_regions<'a, 'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
|
|
@ -98,8 +97,6 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
|
||||
let location_map = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
let mut concrete_opaque_types = ConcreteOpaqueTypes::default();
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults {
|
||||
constraints,
|
||||
|
|
@ -107,6 +104,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
opaque_type_values,
|
||||
polonius_context,
|
||||
} = type_check::type_check(
|
||||
root_cx,
|
||||
infcx,
|
||||
body,
|
||||
promoted,
|
||||
|
|
@ -117,14 +115,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
flow_inits,
|
||||
move_data,
|
||||
Rc::clone(&location_map),
|
||||
&mut concrete_opaque_types,
|
||||
);
|
||||
|
||||
// Create the region inference context, taking ownership of the
|
||||
// region inference data that was contained in `infcx`, and the
|
||||
// base constraints generated by the type-check.
|
||||
let var_infos = infcx.get_region_var_infos();
|
||||
|
||||
// If requested, emit legacy polonius facts.
|
||||
polonius::legacy::emit_facts(
|
||||
&mut polonius_facts,
|
||||
|
|
@ -137,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
&constraints,
|
||||
);
|
||||
|
||||
let mut regioncx = RegionInferenceContext::new(
|
||||
infcx,
|
||||
var_infos,
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
location_map,
|
||||
);
|
||||
let mut regioncx =
|
||||
RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map);
|
||||
|
||||
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
|
||||
// and use them to compute loan liveness.
|
||||
|
|
@ -181,11 +168,10 @@ pub(crate) fn compute_regions<'a, 'tcx>(
|
|||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
regioncx.infer_opaque_types(infcx, opaque_type_values, &mut concrete_opaque_types);
|
||||
regioncx.infer_opaque_types(root_cx, infcx, opaque_type_values);
|
||||
|
||||
NllOutput {
|
||||
regioncx,
|
||||
concrete_opaque_types,
|
||||
polonius_input: polonius_facts.map(Box::new),
|
||||
polonius_output,
|
||||
opt_closure_req: closure_region_requirements,
|
||||
|
|
@ -301,8 +287,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
concrete_opaque_types: &ConcreteOpaqueTypes<'tcx>,
|
||||
diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
|
||||
|
|
@ -318,7 +302,7 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
// better.
|
||||
|
||||
let def_span = tcx.def_span(body.source.def_id());
|
||||
let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
|
||||
let err = if let Some(closure_region_requirements) = closure_region_requirements {
|
||||
let mut err = infcx.dcx().struct_span_note(def_span, "external requirements");
|
||||
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
|
@ -340,15 +324,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
|
|||
} else {
|
||||
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
|
||||
regioncx.annotate(tcx, &mut err);
|
||||
|
||||
err
|
||||
};
|
||||
|
||||
if !concrete_opaque_types.is_empty() {
|
||||
err.note(format!("Inferred opaque type values:\n{concrete_opaque_types:#?}"));
|
||||
}
|
||||
|
||||
diagnostics_buffer.buffer_non_error(err);
|
||||
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
|
||||
err.emit();
|
||||
}
|
||||
|
||||
fn for_each_region_constraint<'tcx>(
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(super) struct ConcreteOpaqueTypes<'tcx> {
|
||||
concrete_opaque_types: FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> ConcreteOpaqueTypes<'tcx> {
|
||||
pub(super) fn is_empty(&self) -> bool {
|
||||
self.concrete_opaque_types.is_empty()
|
||||
}
|
||||
|
||||
pub(super) fn into_inner(self) -> FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>> {
|
||||
self.concrete_opaque_types
|
||||
}
|
||||
|
||||
/// Insert an opaque type into the list of opaque types defined by this function
|
||||
/// after mapping the hidden type to the generic parameters of the opaque type
|
||||
/// definition.
|
||||
pub(super) fn insert(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
hidden_ty: OpaqueHiddenType<'tcx>,
|
||||
) {
|
||||
// Sometimes two opaque types are the same only after we remap the generic parameters
|
||||
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
|
||||
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
|
||||
// only know that once we convert the generic parameters to those of the opaque type.
|
||||
if let Some(prev) = self.concrete_opaque_types.get_mut(&def_id) {
|
||||
if prev.ty != hidden_ty.ty {
|
||||
let (Ok(guar) | Err(guar)) =
|
||||
prev.build_mismatch_error(&hidden_ty, tcx).map(|d| d.emit());
|
||||
prev.ty = Ty::new_error(tcx, guar);
|
||||
}
|
||||
// Pick a better span if there is one.
|
||||
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
|
||||
prev.span = prev.span.substitute_dummy(hidden_ty.span);
|
||||
} else {
|
||||
self.concrete_opaque_types.insert(def_id, hidden_ty);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn extend_from_nested_body(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
nested_body: &FxIndexMap<LocalDefId, OpaqueHiddenType<'tcx>>,
|
||||
) {
|
||||
for (&def_id, &hidden_ty) in nested_body {
|
||||
self.insert(tcx, def_id, hidden_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ use rustc_index::IndexVec;
|
|||
use rustc_middle::mir::pretty::{
|
||||
PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
|
||||
};
|
||||
use rustc_middle::mir::{Body, ClosureRegionRequirements, Location};
|
||||
use rustc_middle::mir::{Body, Location};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
use rustc_session::config::MirIncludeSpans;
|
||||
|
|
@ -17,16 +17,16 @@ use crate::polonius::{
|
|||
};
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::{BorrowckInferCtxt, RegionInferenceContext};
|
||||
use crate::{BorrowckInferCtxt, ClosureRegionRequirements, RegionInferenceContext};
|
||||
|
||||
/// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
|
||||
pub(crate) fn dump_polonius_mir<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
regioncx: &RegionInferenceContext<'tcx>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
|
||||
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
|
||||
) {
|
||||
let tcx = infcx.tcx;
|
||||
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
|
||||
|
|
@ -334,7 +334,7 @@ fn emit_mermaid_nll_regions<'tcx>(
|
|||
writeln!(out, "flowchart TD")?;
|
||||
|
||||
// Emit the region nodes.
|
||||
for region in regioncx.var_infos.indices() {
|
||||
for region in regioncx.definitions.indices() {
|
||||
write!(out, "{}[\"", region.as_usize())?;
|
||||
render_region(region, regioncx, out)?;
|
||||
writeln!(out, "\"]")?;
|
||||
|
|
@ -387,7 +387,7 @@ fn emit_mermaid_nll_sccs<'tcx>(
|
|||
// Gather and emit the SCC nodes.
|
||||
let mut nodes_per_scc: IndexVec<_, _> =
|
||||
regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect();
|
||||
for region in regioncx.var_infos.indices() {
|
||||
for region in regioncx.definitions.indices() {
|
||||
let scc = regioncx.constraint_sccs().scc(region);
|
||||
nodes_per_scc[scc].push(region);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,22 +9,20 @@ use rustc_errors::Diag;
|
|||
use rustc_hir::def_id::CRATE_DEF_ID;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_infer::infer::outlives::test_type_match;
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
|
||||
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq};
|
||||
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{
|
||||
AnnotationSource, BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject,
|
||||
ClosureOutlivesSubjectTy, ClosureRegionRequirements, ConstraintCategory, Local, Location,
|
||||
ReturnConstraint, TerminatorKind,
|
||||
AnnotationSource, BasicBlock, Body, ConstraintCategory, Local, Location, ReturnConstraint,
|
||||
TerminatorKind,
|
||||
};
|
||||
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, fold_regions};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use tracing::{debug, instrument, trace};
|
||||
use tracing::{Level, debug, enabled, instrument, trace};
|
||||
|
||||
use crate::BorrowckInferCtxt;
|
||||
use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
|
||||
use crate::constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet};
|
||||
use crate::dataflow::BorrowIndex;
|
||||
|
|
@ -37,6 +35,10 @@ use crate::region_infer::values::{LivenessValues, RegionElement, RegionValues, T
|
|||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{
|
||||
BorrowckInferCtxt, ClosureOutlivesRequirement, ClosureOutlivesSubject,
|
||||
ClosureOutlivesSubjectTy, ClosureRegionRequirements,
|
||||
};
|
||||
|
||||
mod dump_mir;
|
||||
mod graphviz;
|
||||
|
|
@ -139,13 +141,11 @@ impl RegionTracker {
|
|||
}
|
||||
|
||||
pub struct RegionInferenceContext<'tcx> {
|
||||
pub var_infos: VarInfos,
|
||||
|
||||
/// Contains the definition for every region variable. Region
|
||||
/// variables are identified by their index (`RegionVid`). The
|
||||
/// definition contains information about where the region came
|
||||
/// from as well as its final inferred value.
|
||||
definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
|
||||
pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
|
||||
|
||||
/// The liveness constraints added to each region. For most
|
||||
/// regions, these start out empty and steadily grow, though for
|
||||
|
|
@ -327,31 +327,34 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
|||
let mut var_to_origin_sorted = var_to_origin.clone().into_iter().collect::<Vec<_>>();
|
||||
var_to_origin_sorted.sort_by_key(|vto| vto.0);
|
||||
|
||||
let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
|
||||
for (reg_var, origin) in var_to_origin_sorted.into_iter() {
|
||||
reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n"));
|
||||
if enabled!(Level::DEBUG) {
|
||||
let mut reg_vars_to_origins_str = "region variables to origins:\n".to_string();
|
||||
for (reg_var, origin) in var_to_origin_sorted.into_iter() {
|
||||
reg_vars_to_origins_str.push_str(&format!("{reg_var:?}: {origin:?}\n"));
|
||||
}
|
||||
debug!("{}", reg_vars_to_origins_str);
|
||||
}
|
||||
debug!("{}", reg_vars_to_origins_str);
|
||||
|
||||
let num_components = sccs.num_sccs();
|
||||
let mut components = vec![FxIndexSet::default(); num_components];
|
||||
|
||||
for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
|
||||
let reg_var = ty::RegionVid::from_usize(reg_var_idx);
|
||||
for (reg_var, scc_idx) in sccs.scc_indices().iter_enumerated() {
|
||||
let origin = var_to_origin.get(®_var).unwrap_or(&RegionCtxt::Unknown);
|
||||
components[scc_idx.as_usize()].insert((reg_var, *origin));
|
||||
}
|
||||
|
||||
let mut components_str = "strongly connected components:".to_string();
|
||||
for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
|
||||
let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
|
||||
components_str.push_str(&format!(
|
||||
"{:?}: {:?},\n)",
|
||||
ConstraintSccIndex::from_usize(scc_idx),
|
||||
regions_info,
|
||||
))
|
||||
if enabled!(Level::DEBUG) {
|
||||
let mut components_str = "strongly connected components:".to_string();
|
||||
for (scc_idx, reg_vars_origins) in components.iter().enumerate() {
|
||||
let regions_info = reg_vars_origins.clone().into_iter().collect::<Vec<_>>();
|
||||
components_str.push_str(&format!(
|
||||
"{:?}: {:?},\n)",
|
||||
ConstraintSccIndex::from_usize(scc_idx),
|
||||
regions_info,
|
||||
))
|
||||
}
|
||||
debug!("{}", components_str);
|
||||
}
|
||||
debug!("{}", components_str);
|
||||
|
||||
// calculate the best representative for each component
|
||||
let components_representatives = components
|
||||
|
|
@ -381,6 +384,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
|
|||
debug!("SCC edges {:#?}", scc_node_to_edges);
|
||||
}
|
||||
|
||||
fn create_definitions<'tcx>(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>> {
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let mut definitions: IndexVec<_, _> = infcx
|
||||
.get_region_var_infos()
|
||||
.iter()
|
||||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
|
||||
// Add the external name for all universal regions.
|
||||
for (external_name, variable) in universal_regions.named_universal_regions_iter() {
|
||||
debug!("region {variable:?} has external name {external_name:?}");
|
||||
definitions[variable].external_name = Some(external_name);
|
||||
}
|
||||
|
||||
Frozen::freeze(definitions)
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Creates a new region inference context with a total of
|
||||
/// `num_region_variables` valid inference variables; the first N
|
||||
|
|
@ -391,7 +414,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// of constraints produced by the MIR type check.
|
||||
pub(crate) fn new(
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
var_infos: VarInfos,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
|
|
@ -422,11 +444,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
// Create a RegionDefinition for each inference variable.
|
||||
let definitions: IndexVec<_, _> = var_infos
|
||||
.iter()
|
||||
.map(|info| RegionDefinition::new(info.universe, info.origin))
|
||||
.collect();
|
||||
let definitions = create_definitions(infcx, &universal_regions);
|
||||
|
||||
let constraint_sccs =
|
||||
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
|
||||
|
|
@ -449,7 +467,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
Rc::new(member_constraints.into_mapped(|r| constraint_sccs.scc(r)));
|
||||
|
||||
let mut result = Self {
|
||||
var_infos,
|
||||
definitions,
|
||||
liveness_constraints,
|
||||
constraints,
|
||||
|
|
@ -523,18 +540,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// means that the `R1: !1` constraint here will cause
|
||||
/// `R1` to become `'static`.
|
||||
fn init_free_and_bound_regions(&mut self) {
|
||||
// Update the names (if any)
|
||||
// This iterator has unstable order but we collect it all into an IndexVec
|
||||
for (external_name, variable) in
|
||||
self.universal_region_relations.universal_regions.named_universal_regions_iter()
|
||||
{
|
||||
debug!(
|
||||
"init_free_and_bound_regions: region {:?} has external name {:?}",
|
||||
variable, external_name
|
||||
);
|
||||
self.definitions[variable].external_name = Some(external_name);
|
||||
}
|
||||
|
||||
for variable in self.definitions.indices() {
|
||||
let scc = self.constraint_sccs.scc(variable);
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
use crate::opaque_types::ConcreteOpaqueTypes;
|
||||
use crate::BorrowCheckRootCtxt;
|
||||
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
|
||||
use crate::universal_regions::RegionClassification;
|
||||
|
||||
|
|
@ -58,12 +58,12 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
///
|
||||
/// [rustc-dev-guide chapter]:
|
||||
/// https://rustc-dev-guide.rust-lang.org/opaque-types-region-infer-restrictions.html
|
||||
#[instrument(level = "debug", skip(self, infcx), ret)]
|
||||
#[instrument(level = "debug", skip(self, root_cx, infcx), ret)]
|
||||
pub(crate) fn infer_opaque_types(
|
||||
&self,
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
) {
|
||||
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
|
||||
FxIndexMap::default();
|
||||
|
|
@ -140,11 +140,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
concrete_opaque_types.insert(
|
||||
infcx.tcx,
|
||||
root_cx.add_concrete_opaque_type(
|
||||
opaque_type_key.def_id,
|
||||
OpaqueHiddenType { ty, span: concrete_type.span },
|
||||
OpaqueHiddenType { span: concrete_type.span, ty },
|
||||
);
|
||||
|
||||
// Check that all opaque types have the same region parameters if they have the same
|
||||
// non-region parameters. This is necessary because within the new solver we perform
|
||||
// various query operations modulo regions, and thus could unsoundly select some impls
|
||||
|
|
@ -186,7 +186,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
where
|
||||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
fold_regions(tcx, ty, |region, _| match *region {
|
||||
fold_regions(tcx, ty, |region, _| match region.kind() {
|
||||
ty::ReVar(vid) => {
|
||||
let scc = self.constraint_sccs.scc(vid);
|
||||
|
||||
|
|
|
|||
101
compiler/rustc_borrowck/src/root_cx.rs
Normal file
101
compiler/rustc_borrowck/src/root_cx.rs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
use rustc_abi::FieldIdx;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::{OpaqueHiddenType, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::ErrorGuaranteed;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{ClosureRegionRequirements, ConcreteOpaqueTypes, PropagatedBorrowCheckResults};
|
||||
|
||||
/// The shared context used by both the root as well as all its nested
|
||||
/// items.
|
||||
pub(super) struct BorrowCheckRootCtxt<'tcx> {
|
||||
pub tcx: TyCtxt<'tcx>,
|
||||
root_def_id: LocalDefId,
|
||||
concrete_opaque_types: ConcreteOpaqueTypes<'tcx>,
|
||||
nested_bodies: FxHashMap<LocalDefId, PropagatedBorrowCheckResults<'tcx>>,
|
||||
tainted_by_errors: Option<ErrorGuaranteed>,
|
||||
}
|
||||
|
||||
impl<'tcx> BorrowCheckRootCtxt<'tcx> {
|
||||
pub(super) fn new(tcx: TyCtxt<'tcx>, root_def_id: LocalDefId) -> BorrowCheckRootCtxt<'tcx> {
|
||||
BorrowCheckRootCtxt {
|
||||
tcx,
|
||||
root_def_id,
|
||||
concrete_opaque_types: Default::default(),
|
||||
nested_bodies: Default::default(),
|
||||
tainted_by_errors: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all defining uses of opaque types inside of this typeck root. This
|
||||
/// expects the hidden type to be mapped to the definition parameters of the opaque
|
||||
/// and errors if we end up with distinct hidden types.
|
||||
pub(super) fn add_concrete_opaque_type(
|
||||
&mut self,
|
||||
def_id: LocalDefId,
|
||||
hidden_ty: OpaqueHiddenType<'tcx>,
|
||||
) {
|
||||
// Sometimes two opaque types are the same only after we remap the generic parameters
|
||||
// back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to
|
||||
// `(X, Y)` and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we
|
||||
// only know that once we convert the generic parameters to those of the opaque type.
|
||||
if let Some(prev) = self.concrete_opaque_types.0.get_mut(&def_id) {
|
||||
if prev.ty != hidden_ty.ty {
|
||||
let guar = hidden_ty.ty.error_reported().err().unwrap_or_else(|| {
|
||||
let (Ok(e) | Err(e)) =
|
||||
prev.build_mismatch_error(&hidden_ty, self.tcx).map(|d| d.emit());
|
||||
e
|
||||
});
|
||||
prev.ty = Ty::new_error(self.tcx, guar);
|
||||
}
|
||||
// Pick a better span if there is one.
|
||||
// FIXME(oli-obk): collect multiple spans for better diagnostics down the road.
|
||||
prev.span = prev.span.substitute_dummy(hidden_ty.span);
|
||||
} else {
|
||||
self.concrete_opaque_types.0.insert(def_id, hidden_ty);
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn set_tainted_by_errors(&mut self, guar: ErrorGuaranteed) {
|
||||
self.tainted_by_errors = Some(guar);
|
||||
}
|
||||
|
||||
fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> {
|
||||
debug_assert_eq!(
|
||||
self.tcx.typeck_root_def_id(def_id.to_def_id()),
|
||||
self.root_def_id.to_def_id()
|
||||
);
|
||||
if !self.nested_bodies.contains_key(&def_id) {
|
||||
let result = super::do_mir_borrowck(self, def_id, None).0;
|
||||
if let Some(prev) = self.nested_bodies.insert(def_id, result) {
|
||||
bug!("unexpected previous nested body: {prev:?}");
|
||||
}
|
||||
}
|
||||
|
||||
self.nested_bodies.get(&def_id).unwrap()
|
||||
}
|
||||
|
||||
pub(super) fn closure_requirements(
|
||||
&mut self,
|
||||
nested_body_def_id: LocalDefId,
|
||||
) -> &Option<ClosureRegionRequirements<'tcx>> {
|
||||
&self.get_or_insert_nested(nested_body_def_id).closure_requirements
|
||||
}
|
||||
|
||||
pub(super) fn used_mut_upvars(
|
||||
&mut self,
|
||||
nested_body_def_id: LocalDefId,
|
||||
) -> &SmallVec<[FieldIdx; 8]> {
|
||||
&self.get_or_insert_nested(nested_body_def_id).used_mut_upvars
|
||||
}
|
||||
|
||||
pub(super) fn finalize(self) -> Result<&'tcx ConcreteOpaqueTypes<'tcx>, ErrorGuaranteed> {
|
||||
if let Some(guar) = self.tainted_by_errors {
|
||||
Err(guar)
|
||||
} else {
|
||||
Ok(self.tcx.arena.alloc(self.concrete_opaque_types))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
|
|||
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
|
||||
use rustc_infer::traits::query::type_op::DeeplyNormalize;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
|
||||
};
|
||||
|
|
@ -18,10 +17,10 @@ use crate::constraints::OutlivesConstraint;
|
|||
use crate::region_infer::TypeTest;
|
||||
use crate::type_check::{Locations, MirTypeckRegionConstraints};
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
|
||||
|
||||
pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
||||
infcx: &'a InferCtxt<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
/// Each RBP `GK: 'a` is assumed to be true. These encode
|
||||
/// relationships like `T: 'a` that are added via implicit bounds
|
||||
|
|
@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
|
|||
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
|
||||
/// our special inference variable there, we would mess that up.
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
|
|
@ -49,7 +47,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
infcx: &'a InferCtxt<'tcx>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
|
||||
locations: Locations,
|
||||
|
|
@ -59,10 +56,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
) -> Self {
|
||||
Self {
|
||||
infcx,
|
||||
tcx: infcx.tcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
param_env,
|
||||
known_type_outlives_obligations,
|
||||
locations,
|
||||
|
|
@ -96,7 +91,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
// into a vector. These are the regions that we will be
|
||||
// relating to one another.
|
||||
let closure_mapping = &UniversalRegions::closure_mapping(
|
||||
self.tcx,
|
||||
self.infcx.tcx,
|
||||
closure_args,
|
||||
closure_requirements.num_external_vids,
|
||||
closure_def_id,
|
||||
|
|
@ -111,7 +106,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
let subject = match outlives_requirement.subject {
|
||||
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
|
||||
ClosureOutlivesSubject::Ty(subject_ty) => {
|
||||
subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
|
||||
subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -127,14 +122,14 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
|
||||
constraint_category: ConstraintCategory<'tcx>,
|
||||
) {
|
||||
let tcx = self.infcx.tcx;
|
||||
debug!("generate: constraints at: {:#?}", self.locations);
|
||||
|
||||
// Extract out various useful fields we'll need below.
|
||||
let ConstraintConversion {
|
||||
tcx,
|
||||
infcx,
|
||||
universal_regions,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
known_type_outlives_obligations,
|
||||
..
|
||||
} = *self;
|
||||
|
|
@ -145,7 +140,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
break;
|
||||
}
|
||||
|
||||
if !self.tcx.recursion_limit().value_within_limit(iteration) {
|
||||
if !tcx.recursion_limit().value_within_limit(iteration) {
|
||||
bug!(
|
||||
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
);
|
||||
|
|
@ -170,10 +165,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
let implicit_region_bound =
|
||||
ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
|
||||
// we don't actually use this for anything, but
|
||||
// the `TypeOutlives` code needs an origin.
|
||||
let origin = infer::RelateParamBound(self.span, t1, None);
|
||||
|
||||
TypeOutlives::new(
|
||||
&mut *self,
|
||||
tcx,
|
||||
|
|
@ -205,7 +201,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
/// are dealt with during trait solving.
|
||||
fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
|
||||
if value.has_placeholders() {
|
||||
fold_regions(self.tcx, value, |r, _| match *r {
|
||||
fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
|
||||
ty::RePlaceholder(placeholder) => {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder)
|
||||
}
|
||||
|
|
@ -227,7 +223,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
|
||||
if let ty::RePlaceholder(placeholder) = *r {
|
||||
if let ty::RePlaceholder(placeholder) = r.kind() {
|
||||
self.constraints.placeholder_region(self.infcx, placeholder).as_var()
|
||||
} else {
|
||||
self.universal_regions.to_region_vid(r)
|
||||
|
|
|
|||
|
|
@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> {
|
|||
pub(crate) fn create<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
constraints: &mut MirTypeckRegionConstraints<'tcx>,
|
||||
) -> CreateResult<'tcx> {
|
||||
UniversalRegionRelationsBuilder {
|
||||
infcx,
|
||||
param_env,
|
||||
implicit_region_bound,
|
||||
constraints,
|
||||
universal_regions,
|
||||
region_bound_pairs: Default::default(),
|
||||
|
|
@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> {
|
|||
infcx: &'a InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
|
||||
// outputs:
|
||||
|
|
@ -320,7 +317,6 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
|
|||
self.infcx,
|
||||
&self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
param_env,
|
||||
&known_type_outlives_obligations,
|
||||
Locations::All(span),
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ use crate::borrow_set::BorrowSet;
|
|||
use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet};
|
||||
use crate::diagnostics::UniverseInfo;
|
||||
use crate::member_constraints::MemberConstraintSet;
|
||||
use crate::opaque_types::ConcreteOpaqueTypes;
|
||||
use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable};
|
||||
use crate::polonius::{PoloniusContext, PoloniusLivenessContext};
|
||||
use crate::region_infer::TypeTest;
|
||||
|
|
@ -53,7 +52,7 @@ use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderI
|
|||
use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst};
|
||||
use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
|
||||
use crate::universal_regions::{DefiningTy, UniversalRegions};
|
||||
use crate::{BorrowckInferCtxt, path_utils};
|
||||
use crate::{BorrowCheckRootCtxt, BorrowckInferCtxt, path_utils};
|
||||
|
||||
macro_rules! span_mirbug {
|
||||
($context:expr, $elem:expr, $($message:tt)*) => ({
|
||||
|
|
@ -102,6 +101,7 @@ mod relate_tys;
|
|||
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
|
||||
/// - `location_map` -- map between MIR `Location` and `PointIndex`
|
||||
pub(crate) fn type_check<'a, 'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
|
|
@ -112,9 +112,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
concrete_opaque_types: &mut ConcreteOpaqueTypes<'tcx>,
|
||||
) -> 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(),
|
||||
|
|
@ -130,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
region_bound_pairs,
|
||||
normalized_inputs_and_output,
|
||||
known_type_outlives_obligations,
|
||||
} = free_region_relations::create(
|
||||
infcx,
|
||||
infcx.param_env,
|
||||
implicit_region_bound,
|
||||
universal_regions,
|
||||
&mut constraints,
|
||||
);
|
||||
} = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
|
||||
|
||||
let pre_obligations = infcx.take_registered_region_obligations();
|
||||
assert!(
|
||||
|
|
@ -153,6 +145,7 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
};
|
||||
|
||||
let mut typeck = TypeChecker {
|
||||
root_cx,
|
||||
infcx,
|
||||
last_span: body.span,
|
||||
body,
|
||||
|
|
@ -160,14 +153,12 @@ pub(crate) fn type_check<'a, 'tcx>(
|
|||
user_type_annotations: &body.user_type_annotations,
|
||||
region_bound_pairs,
|
||||
known_type_outlives_obligations,
|
||||
implicit_region_bound,
|
||||
reported_errors: Default::default(),
|
||||
universal_regions: &universal_region_relations.universal_regions,
|
||||
location_table,
|
||||
polonius_facts,
|
||||
borrow_set,
|
||||
constraints: &mut constraints,
|
||||
concrete_opaque_types,
|
||||
polonius_liveness,
|
||||
};
|
||||
|
||||
|
|
@ -215,6 +206,7 @@ enum FieldAccessError {
|
|||
/// way, it accrues region constraints -- these can later be used by
|
||||
/// NLL region checking.
|
||||
struct TypeChecker<'a, 'tcx> {
|
||||
root_cx: &'a mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &'a BorrowckInferCtxt<'tcx>,
|
||||
last_span: Span,
|
||||
body: &'a Body<'tcx>,
|
||||
|
|
@ -226,14 +218,12 @@ struct TypeChecker<'a, 'tcx> {
|
|||
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
|
||||
region_bound_pairs: RegionBoundPairs<'tcx>,
|
||||
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
|
||||
universal_regions: &'a UniversalRegions<'tcx>,
|
||||
location_table: &'a PoloniusLocationTable,
|
||||
polonius_facts: &'a mut Option<PoloniusFacts>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
|
||||
concrete_opaque_types: &'a mut ConcreteOpaqueTypes<'tcx>,
|
||||
/// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints.
|
||||
polonius_liveness: Option<PoloniusLivenessContext>,
|
||||
}
|
||||
|
|
@ -423,7 +413,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
self.infcx,
|
||||
self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.infcx.param_env,
|
||||
&self.known_type_outlives_obligations,
|
||||
locations,
|
||||
|
|
@ -1568,11 +1557,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
CastKind::Transmute => {
|
||||
span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
|
||||
);
|
||||
let ty_from = op.ty(self.body, tcx);
|
||||
match ty_from.kind() {
|
||||
ty::Pat(base, _) if base == ty => {}
|
||||
_ => span_mirbug!(
|
||||
self,
|
||||
rvalue,
|
||||
"Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2503,16 +2496,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
args: GenericArgsRef<'tcx>,
|
||||
locations: Locations,
|
||||
) -> ty::InstantiatedPredicates<'tcx> {
|
||||
let closure_borrowck_results = tcx.mir_borrowck(def_id);
|
||||
self.concrete_opaque_types
|
||||
.extend_from_nested_body(tcx, &closure_borrowck_results.concrete_opaque_types);
|
||||
|
||||
if let Some(closure_requirements) = &closure_borrowck_results.closure_requirements {
|
||||
if let Some(closure_requirements) = &self.root_cx.closure_requirements(def_id) {
|
||||
constraint_conversion::ConstraintConversion::new(
|
||||
self.infcx,
|
||||
self.universal_regions,
|
||||
&self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.infcx.param_env,
|
||||
&self.known_type_outlives_obligations,
|
||||
locations,
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ where
|
|||
}
|
||||
|
||||
fn visit_region(&mut self, r: ty::Region<'tcx>) {
|
||||
match *r {
|
||||
match r.kind() {
|
||||
// ignore bound regions, keep visiting
|
||||
ty::ReBound(_, _) => {}
|
||||
_ => (self.op)(r),
|
||||
|
|
|
|||
|
|
@ -438,6 +438,10 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn implicit_region_bound(&self) -> RegionVid {
|
||||
self.fr_fn_body
|
||||
}
|
||||
|
||||
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.indices.tainted_by_errors.get()
|
||||
}
|
||||
|
|
@ -909,19 +913,19 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
|||
/// if it is a placeholder. Handling placeholders requires access to the
|
||||
/// `MirTypeckRegionConstraints`.
|
||||
fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
|
||||
if let ty::ReVar(..) = *r {
|
||||
r.as_var()
|
||||
} else if let ty::ReError(guar) = *r {
|
||||
self.tainted_by_errors.set(Some(guar));
|
||||
// We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the
|
||||
// `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if
|
||||
// errors are being emitted and 2) it leaves the happy path unaffected.
|
||||
self.fr_static
|
||||
} else {
|
||||
*self
|
||||
match r.kind() {
|
||||
ty::ReVar(..) => r.as_var(),
|
||||
ty::ReError(guar) => {
|
||||
self.tainted_by_errors.set(Some(guar));
|
||||
// We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the
|
||||
// `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if
|
||||
// errors are being emitted and 2) it leaves the happy path unaffected.
|
||||
self.fr_static
|
||||
}
|
||||
_ => *self
|
||||
.indices
|
||||
.get(&r)
|
||||
.unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r))
|
||||
.unwrap_or_else(|| bug!("cannot convert `{:?}` to a region vid", r)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -231,8 +231,6 @@ builtin_macros_format_unused_args = multiple unused formatting arguments
|
|||
|
||||
builtin_macros_format_use_positional = consider using a positional formatting argument instead
|
||||
|
||||
builtin_macros_invalid_crate_attribute = invalid crate attribute
|
||||
|
||||
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
|
||||
.note = only one `#[default]` attribute is needed
|
||||
.label = `#[default]` used here
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ mod llvm_enzyme {
|
|||
use rustc_ast::visit::AssocCtxt::*;
|
||||
use rustc_ast::{
|
||||
self as ast, AssocItemKind, BindingMode, ExprKind, FnRetTy, FnSig, Generics, ItemKind,
|
||||
MetaItemInner, PatKind, QSelf, TyKind,
|
||||
MetaItemInner, PatKind, QSelf, TyKind, Visibility,
|
||||
};
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_span::{Ident, Span, Symbol, kw, sym};
|
||||
|
|
@ -72,6 +72,16 @@ mod llvm_enzyme {
|
|||
}
|
||||
}
|
||||
|
||||
// Get information about the function the macro is applied to
|
||||
fn extract_item_info(iitem: &P<ast::Item>) -> Option<(Visibility, FnSig, Ident)> {
|
||||
match &iitem.kind {
|
||||
ItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
|
||||
Some((iitem.vis.clone(), sig.clone(), ident.clone()))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_ast(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
meta_item: &ThinVec<MetaItemInner>,
|
||||
|
|
@ -199,38 +209,32 @@ mod llvm_enzyme {
|
|||
return vec![item];
|
||||
}
|
||||
let dcx = ecx.sess.dcx();
|
||||
// first get the annotable item:
|
||||
let (primal, sig, is_impl): (Ident, FnSig, bool) = match &item {
|
||||
Annotatable::Item(iitem) => {
|
||||
let (ident, sig) = match &iitem.kind {
|
||||
ItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig),
|
||||
_ => {
|
||||
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
|
||||
return vec![item];
|
||||
}
|
||||
};
|
||||
(*ident, sig.clone(), false)
|
||||
}
|
||||
|
||||
// first get information about the annotable item:
|
||||
let Some((vis, sig, primal)) = (match &item {
|
||||
Annotatable::Item(iitem) => extract_item_info(iitem),
|
||||
Annotatable::Stmt(stmt) => match &stmt.kind {
|
||||
ast::StmtKind::Item(iitem) => extract_item_info(iitem),
|
||||
_ => None,
|
||||
},
|
||||
Annotatable::AssocItem(assoc_item, Impl { of_trait: false }) => {
|
||||
let (ident, sig) = match &assoc_item.kind {
|
||||
ast::AssocItemKind::Fn(box ast::Fn { ident, sig, .. }) => (ident, sig),
|
||||
_ => {
|
||||
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
|
||||
return vec![item];
|
||||
match &assoc_item.kind {
|
||||
ast::AssocItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
|
||||
Some((assoc_item.vis.clone(), sig.clone(), ident.clone()))
|
||||
}
|
||||
};
|
||||
(*ident, sig.clone(), true)
|
||||
}
|
||||
_ => {
|
||||
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
|
||||
return vec![item];
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}) else {
|
||||
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
|
||||
return vec![item];
|
||||
};
|
||||
|
||||
let meta_item_vec: ThinVec<MetaItemInner> = match meta_item.kind {
|
||||
ast::MetaItemKind::List(ref vec) => vec.clone(),
|
||||
_ => {
|
||||
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
|
||||
dcx.emit_err(errors::AutoDiffMissingConfig { span: item.span() });
|
||||
return vec![item];
|
||||
}
|
||||
};
|
||||
|
|
@ -238,15 +242,6 @@ mod llvm_enzyme {
|
|||
let has_ret = has_ret(&sig.decl.output);
|
||||
let sig_span = ecx.with_call_site_ctxt(sig.span);
|
||||
|
||||
let vis = match &item {
|
||||
Annotatable::Item(iitem) => iitem.vis.clone(),
|
||||
Annotatable::AssocItem(assoc_item, _) => assoc_item.vis.clone(),
|
||||
_ => {
|
||||
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
|
||||
return vec![item];
|
||||
}
|
||||
};
|
||||
|
||||
// create TokenStream from vec elemtents:
|
||||
// meta_item doesn't have a .tokens field
|
||||
let mut ts: Vec<TokenTree> = vec![];
|
||||
|
|
@ -379,6 +374,22 @@ mod llvm_enzyme {
|
|||
}
|
||||
Annotatable::AssocItem(assoc_item.clone(), i)
|
||||
}
|
||||
Annotatable::Stmt(ref mut stmt) => {
|
||||
match stmt.kind {
|
||||
ast::StmtKind::Item(ref mut iitem) => {
|
||||
if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
|
||||
iitem.attrs.push(attr);
|
||||
}
|
||||
if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind))
|
||||
{
|
||||
iitem.attrs.push(inline_never.clone());
|
||||
}
|
||||
}
|
||||
_ => unreachable!("stmt kind checked previously"),
|
||||
};
|
||||
|
||||
Annotatable::Stmt(stmt.clone())
|
||||
}
|
||||
_ => {
|
||||
unreachable!("annotatable kind checked previously")
|
||||
}
|
||||
|
|
@ -389,22 +400,40 @@ mod llvm_enzyme {
|
|||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
});
|
||||
|
||||
let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
|
||||
let d_annotatable = if is_impl {
|
||||
let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf);
|
||||
let d_fn = P(ast::AssocItem {
|
||||
attrs: thin_vec![d_attr, inline_never],
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
vis,
|
||||
kind: assoc_item,
|
||||
tokens: None,
|
||||
});
|
||||
Annotatable::AssocItem(d_fn, Impl { of_trait: false })
|
||||
} else {
|
||||
let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
|
||||
d_fn.vis = vis;
|
||||
Annotatable::Item(d_fn)
|
||||
let d_annotatable = match &item {
|
||||
Annotatable::AssocItem(_, _) => {
|
||||
let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf);
|
||||
let d_fn = P(ast::AssocItem {
|
||||
attrs: thin_vec![d_attr, inline_never],
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
span,
|
||||
vis,
|
||||
kind: assoc_item,
|
||||
tokens: None,
|
||||
});
|
||||
Annotatable::AssocItem(d_fn, Impl { of_trait: false })
|
||||
}
|
||||
Annotatable::Item(_) => {
|
||||
let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
|
||||
d_fn.vis = vis;
|
||||
|
||||
Annotatable::Item(d_fn)
|
||||
}
|
||||
Annotatable::Stmt(_) => {
|
||||
let mut d_fn = ecx.item(span, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf));
|
||||
d_fn.vis = vis;
|
||||
|
||||
Annotatable::Stmt(P(ast::Stmt {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::StmtKind::Item(d_fn),
|
||||
span,
|
||||
}))
|
||||
}
|
||||
_ => {
|
||||
unreachable!("item kind checked previously")
|
||||
}
|
||||
};
|
||||
|
||||
return vec![orig_annotatable, d_annotatable];
|
||||
|
|
@ -770,8 +799,19 @@ mod llvm_enzyme {
|
|||
d_inputs.push(shadow_arg.clone());
|
||||
}
|
||||
}
|
||||
DiffActivity::Dual | DiffActivity::DualOnly => {
|
||||
for i in 0..x.width {
|
||||
DiffActivity::Dual
|
||||
| DiffActivity::DualOnly
|
||||
| DiffActivity::Dualv
|
||||
| DiffActivity::DualvOnly => {
|
||||
// the *v variants get lowered to enzyme_dupv and enzyme_dupnoneedv, which cause
|
||||
// Enzyme to not expect N arguments, but one argument (which is instead larger).
|
||||
let iterations =
|
||||
if matches!(activity, DiffActivity::Dualv | DiffActivity::DualvOnly) {
|
||||
1
|
||||
} else {
|
||||
x.width
|
||||
};
|
||||
for i in 0..iterations {
|
||||
let mut shadow_arg = arg.clone();
|
||||
let old_name = if let PatKind::Ident(_, ident, _) = arg.pat.kind {
|
||||
ident.name
|
||||
|
|
@ -794,7 +834,7 @@ mod llvm_enzyme {
|
|||
DiffActivity::Const => {
|
||||
// Nothing to do here.
|
||||
}
|
||||
DiffActivity::None | DiffActivity::FakeActivitySize => {
|
||||
DiffActivity::None | DiffActivity::FakeActivitySize(_) => {
|
||||
panic!("Should not happen");
|
||||
}
|
||||
}
|
||||
|
|
@ -858,8 +898,8 @@ mod llvm_enzyme {
|
|||
}
|
||||
};
|
||||
|
||||
if let DiffActivity::Dual = x.ret_activity {
|
||||
let kind = if x.width == 1 {
|
||||
if matches!(x.ret_activity, DiffActivity::Dual | DiffActivity::Dualv) {
|
||||
let kind = if x.width == 1 || matches!(x.ret_activity, DiffActivity::Dualv) {
|
||||
// Dual can only be used for f32/f64 ret.
|
||||
// In that case we return now a tuple with two floats.
|
||||
TyKind::Tup(thin_vec![ty.clone(), ty.clone()])
|
||||
|
|
@ -874,7 +914,7 @@ mod llvm_enzyme {
|
|||
let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None });
|
||||
d_decl.output = FnRetTy::Ty(ty);
|
||||
}
|
||||
if let DiffActivity::DualOnly = x.ret_activity {
|
||||
if matches!(x.ret_activity, DiffActivity::DualOnly | DiffActivity::DualvOnly) {
|
||||
// No need to change the return type,
|
||||
// we will just return the shadow in place of the primal return.
|
||||
// However, if we have a width > 1, then we don't return -> T, but -> [T; width]
|
||||
|
|
|
|||
|
|
@ -92,11 +92,7 @@ impl CfgEval<'_> {
|
|||
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
|
||||
// process is lossless, so this process is invisible to proc-macros.
|
||||
|
||||
// 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
|
||||
// to `None`-delimited groups containing the corresponding tokens. This
|
||||
// is normally delayed until the proc-macro server actually needs to
|
||||
// provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier,
|
||||
// so that we can handle cases like:
|
||||
// Interesting cases:
|
||||
//
|
||||
// ```rust
|
||||
// #[cfg_eval] #[cfg] $item
|
||||
|
|
@ -104,8 +100,8 @@ impl CfgEval<'_> {
|
|||
//
|
||||
// where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
|
||||
// sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
|
||||
// way to do this is to do a single parse of a stream without any nonterminals.
|
||||
let orig_tokens = annotatable.to_tokens().flattened();
|
||||
// way to do this is to do a single parse of the token stream.
|
||||
let orig_tokens = annotatable.to_tokens();
|
||||
|
||||
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
|
||||
// to the captured `AttrTokenStream` (specifically, we capture
|
||||
|
|
|
|||
|
|
@ -1,44 +1,37 @@
|
|||
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
|
||||
|
||||
use rustc_ast::attr::mk_attr;
|
||||
use rustc_ast::{self as ast, AttrItem, AttrStyle, token};
|
||||
use rustc_parse::parser::ForceCollect;
|
||||
use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
|
||||
use rustc_ast::{self as ast};
|
||||
use rustc_errors::Diag;
|
||||
use rustc_parse::parser::attr::InnerAttrPolicy;
|
||||
use rustc_parse::{parse_in, source_str_to_stream};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::FileName;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
|
||||
for raw_attr in attrs {
|
||||
let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
raw_attr.clone(),
|
||||
));
|
||||
|
||||
let start_span = parser.token.span;
|
||||
let AttrItem { unsafety, path, args, tokens: _ } =
|
||||
match parser.parse_attr_item(ForceCollect::No) {
|
||||
Ok(ai) => ai,
|
||||
Err(err) => {
|
||||
let source = format!("#![{raw_attr}]");
|
||||
let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
|
||||
let tokens = source_str_to_stream(
|
||||
psess,
|
||||
FileName::cli_crate_attr_source_code(raw_attr),
|
||||
source,
|
||||
None,
|
||||
)?;
|
||||
parse_in(psess, tokens, "<crate attribute>", |p| {
|
||||
p.parse_attribute(InnerAttrPolicy::Permitted)
|
||||
})
|
||||
.map_err(|e| vec![e])
|
||||
};
|
||||
let meta = match parse() {
|
||||
Ok(meta) => meta,
|
||||
Err(errs) => {
|
||||
for err in errs {
|
||||
err.emit();
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let end_span = parser.token.span;
|
||||
if parser.token != token::Eof {
|
||||
psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
krate.attrs.push(mk_attr(
|
||||
&psess.attr_id_generator,
|
||||
AttrStyle::Inner,
|
||||
unsafety,
|
||||
path,
|
||||
args,
|
||||
start_span.to(end_span),
|
||||
));
|
||||
krate.attrs.push(meta);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -527,15 +527,14 @@ impl<'a> TraitDef<'a> {
|
|||
item.attrs
|
||||
.iter()
|
||||
.filter(|a| {
|
||||
[
|
||||
a.has_any_name(&[
|
||||
sym::allow,
|
||||
sym::warn,
|
||||
sym::deny,
|
||||
sym::forbid,
|
||||
sym::stable,
|
||||
sym::unstable,
|
||||
]
|
||||
.contains(&a.name_or_empty())
|
||||
])
|
||||
})
|
||||
.cloned(),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
|
||||
SubdiagMessageOp, Subdiagnostic,
|
||||
Subdiagnostic,
|
||||
};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
|
@ -109,13 +109,6 @@ pub(crate) struct ProcMacro {
|
|||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_invalid_crate_attribute)]
|
||||
pub(crate) struct InvalidCrateAttr {
|
||||
#[primary_span]
|
||||
pub(crate) span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(builtin_macros_non_abi)]
|
||||
pub(crate) struct NonABI {
|
||||
|
|
@ -691,13 +684,9 @@ pub(crate) struct FormatUnusedArg {
|
|||
// Allow the singular form to be a subdiagnostic of the multiple-unused
|
||||
// form of diagnostic.
|
||||
impl Subdiagnostic for FormatUnusedArg {
|
||||
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
|
||||
self,
|
||||
diag: &mut Diag<'_, G>,
|
||||
f: &F,
|
||||
) {
|
||||
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
|
||||
diag.arg("named", self.named);
|
||||
let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
|
||||
let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg);
|
||||
diag.span_label(self.span, msg);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
#![allow(internal_features)]
|
||||
#![allow(rustc::diagnostic_outside_of_impl)]
|
||||
#![allow(rustc::untranslatable_diagnostic)]
|
||||
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ use crate::errors;
|
|||
struct ProcMacroDerive {
|
||||
id: NodeId,
|
||||
trait_name: Symbol,
|
||||
function_name: Ident,
|
||||
function_ident: Ident,
|
||||
span: Span,
|
||||
attrs: Vec<Symbol>,
|
||||
}
|
||||
|
||||
struct ProcMacroDef {
|
||||
id: NodeId,
|
||||
function_name: Ident,
|
||||
function_ident: Ident,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
|
|
@ -95,7 +95,7 @@ impl<'a> CollectProcMacros<'a> {
|
|||
fn collect_custom_derive(
|
||||
&mut self,
|
||||
item: &'a ast::Item,
|
||||
function_name: Ident,
|
||||
function_ident: Ident,
|
||||
attr: &'a ast::Attribute,
|
||||
) {
|
||||
let Some((trait_name, proc_attrs)) =
|
||||
|
|
@ -109,7 +109,7 @@ impl<'a> CollectProcMacros<'a> {
|
|||
id: item.id,
|
||||
span: item.span,
|
||||
trait_name,
|
||||
function_name,
|
||||
function_ident,
|
||||
attrs: proc_attrs,
|
||||
}));
|
||||
} else {
|
||||
|
|
@ -123,12 +123,12 @@ impl<'a> CollectProcMacros<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, function_name: Ident) {
|
||||
fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, function_ident: Ident) {
|
||||
if self.in_root && item.vis.kind.is_pub() {
|
||||
self.macros.push(ProcMacro::Attr(ProcMacroDef {
|
||||
id: item.id,
|
||||
span: item.span,
|
||||
function_name,
|
||||
function_ident,
|
||||
}));
|
||||
} else {
|
||||
let msg = if !self.in_root {
|
||||
|
|
@ -141,12 +141,12 @@ impl<'a> CollectProcMacros<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, function_name: Ident) {
|
||||
fn collect_bang_proc_macro(&mut self, item: &'a ast::Item, function_ident: Ident) {
|
||||
if self.in_root && item.vis.kind.is_pub() {
|
||||
self.macros.push(ProcMacro::Bang(ProcMacroDef {
|
||||
id: item.id,
|
||||
span: item.span,
|
||||
function_name,
|
||||
function_ident,
|
||||
}));
|
||||
} else {
|
||||
let msg = if !self.in_root {
|
||||
|
|
@ -303,7 +303,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
|
|||
ProcMacro::Derive(m) => m.span,
|
||||
ProcMacro::Attr(m) | ProcMacro::Bang(m) => m.span,
|
||||
};
|
||||
let local_path = |cx: &ExtCtxt<'_>, name| cx.expr_path(cx.path(span, vec![name]));
|
||||
let local_path = |cx: &ExtCtxt<'_>, ident| cx.expr_path(cx.path(span, vec![ident]));
|
||||
let proc_macro_ty_method_path = |cx: &ExtCtxt<'_>, method| {
|
||||
cx.expr_path(cx.path(
|
||||
span.with_ctxt(harness_span.ctxt()),
|
||||
|
|
@ -327,7 +327,7 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
|
|||
.map(|&s| cx.expr_str(span, s))
|
||||
.collect::<ThinVec<_>>(),
|
||||
),
|
||||
local_path(cx, cd.function_name),
|
||||
local_path(cx, cd.function_ident),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
|
@ -345,8 +345,8 @@ fn mk_decls(cx: &mut ExtCtxt<'_>, macros: &[ProcMacro]) -> P<ast::Item> {
|
|||
harness_span,
|
||||
proc_macro_ty_method_path(cx, ident),
|
||||
thin_vec![
|
||||
cx.expr_str(span, ca.function_name.name),
|
||||
local_path(cx, ca.function_name),
|
||||
cx.expr_str(span, ca.function_ident.name),
|
||||
local_path(cx, ca.function_ident),
|
||||
],
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,8 +169,11 @@ fn produce_final_output_artifacts(
|
|||
if codegen_results.modules.len() == 1 {
|
||||
// 1) Only one codegen unit. In this case it's no difficulty
|
||||
// to copy `foo.0.x` to `foo.x`.
|
||||
let module_name = Some(&codegen_results.modules[0].name[..]);
|
||||
let path = crate_output.temp_path(output_type, module_name);
|
||||
let path = crate_output.temp_path_for_cgu(
|
||||
output_type,
|
||||
&codegen_results.modules[0].name,
|
||||
sess.invocation_temp.as_deref(),
|
||||
);
|
||||
let output = crate_output.path(output_type);
|
||||
if !output_type.is_text_output() && output.is_tty() {
|
||||
sess.dcx()
|
||||
|
|
@ -183,22 +186,16 @@ fn produce_final_output_artifacts(
|
|||
ensure_removed(sess.dcx(), &path);
|
||||
}
|
||||
} else {
|
||||
let extension = crate_output
|
||||
.temp_path(output_type, None)
|
||||
.extension()
|
||||
.unwrap()
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
|
||||
if crate_output.outputs.contains_explicit_name(&output_type) {
|
||||
// 2) Multiple codegen units, with `--emit foo=some_name`. We have
|
||||
// no good solution for this case, so warn the user.
|
||||
sess.dcx().emit_warn(ssa_errors::IgnoringEmitPath { extension });
|
||||
sess.dcx()
|
||||
.emit_warn(ssa_errors::IgnoringEmitPath { extension: output_type.extension() });
|
||||
} else if crate_output.single_output_file.is_some() {
|
||||
// 3) Multiple codegen units, with `-o some_name`. We have
|
||||
// no good solution for this case, so warn the user.
|
||||
sess.dcx().emit_warn(ssa_errors::IgnoringOutput { extension });
|
||||
sess.dcx()
|
||||
.emit_warn(ssa_errors::IgnoringOutput { extension: output_type.extension() });
|
||||
} else {
|
||||
// 4) Multiple codegen units, but no explicit name. We
|
||||
// just leave the `foo.0.x` files in place.
|
||||
|
|
@ -351,6 +348,7 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> {
|
|||
|
||||
fn emit_cgu(
|
||||
output_filenames: &OutputFilenames,
|
||||
invocation_temp: Option<&str>,
|
||||
prof: &SelfProfilerRef,
|
||||
name: String,
|
||||
module: UnwindModule<ObjectModule>,
|
||||
|
|
@ -366,6 +364,7 @@ fn emit_cgu(
|
|||
|
||||
let module_regular = emit_module(
|
||||
output_filenames,
|
||||
invocation_temp,
|
||||
prof,
|
||||
product.object,
|
||||
ModuleKind::Regular,
|
||||
|
|
@ -391,6 +390,7 @@ fn emit_cgu(
|
|||
|
||||
fn emit_module(
|
||||
output_filenames: &OutputFilenames,
|
||||
invocation_temp: Option<&str>,
|
||||
prof: &SelfProfilerRef,
|
||||
mut object: cranelift_object::object::write::Object<'_>,
|
||||
kind: ModuleKind,
|
||||
|
|
@ -409,7 +409,7 @@ fn emit_module(
|
|||
object.set_section_data(comment_section, producer, 1);
|
||||
}
|
||||
|
||||
let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name));
|
||||
let tmp_file = output_filenames.temp_path_for_cgu(OutputType::Object, &name, invocation_temp);
|
||||
let file = match File::create(&tmp_file) {
|
||||
Ok(file) => file,
|
||||
Err(err) => return Err(format!("error creating object file: {}", err)),
|
||||
|
|
@ -449,8 +449,11 @@ fn reuse_workproduct_for_cgu(
|
|||
cgu: &CodegenUnit<'_>,
|
||||
) -> Result<ModuleCodegenResult, String> {
|
||||
let work_product = cgu.previous_work_product(tcx);
|
||||
let obj_out_regular =
|
||||
tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu.name().as_str()));
|
||||
let obj_out_regular = tcx.output_filenames(()).temp_path_for_cgu(
|
||||
OutputType::Object,
|
||||
cgu.name().as_str(),
|
||||
tcx.sess.invocation_temp.as_deref(),
|
||||
);
|
||||
let source_file_regular = rustc_incremental::in_incr_comp_dir_sess(
|
||||
&tcx.sess,
|
||||
&work_product.saved_files.get("o").expect("no saved object file in work product"),
|
||||
|
|
@ -595,13 +598,19 @@ fn module_codegen(
|
|||
|
||||
let global_asm_object_file =
|
||||
profiler.generic_activity_with_arg("compile assembly", &*cgu_name).run(|| {
|
||||
crate::global_asm::compile_global_asm(&global_asm_config, &cgu_name, &cx.global_asm)
|
||||
crate::global_asm::compile_global_asm(
|
||||
&global_asm_config,
|
||||
&cgu_name,
|
||||
&cx.global_asm,
|
||||
cx.invocation_temp.as_deref(),
|
||||
)
|
||||
})?;
|
||||
|
||||
let codegen_result =
|
||||
profiler.generic_activity_with_arg("write object file", &*cgu_name).run(|| {
|
||||
emit_cgu(
|
||||
&global_asm_config.output_filenames,
|
||||
cx.invocation_temp.as_deref(),
|
||||
&profiler,
|
||||
cgu_name,
|
||||
module,
|
||||
|
|
@ -626,8 +635,11 @@ fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> Compiled
|
|||
.as_str()
|
||||
.to_string();
|
||||
|
||||
let tmp_file =
|
||||
tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
|
||||
let tmp_file = tcx.output_filenames(()).temp_path_for_cgu(
|
||||
OutputType::Metadata,
|
||||
&metadata_cgu_name,
|
||||
tcx.sess.invocation_temp.as_deref(),
|
||||
);
|
||||
|
||||
let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx);
|
||||
let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name);
|
||||
|
|
@ -657,6 +669,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> {
|
|||
|
||||
match emit_module(
|
||||
tcx.output_filenames(()),
|
||||
tcx.sess.invocation_temp.as_deref(),
|
||||
&tcx.sess.prof,
|
||||
product.object,
|
||||
ModuleKind::Allocator,
|
||||
|
|
@ -728,26 +741,27 @@ pub(crate) fn run_aot(
|
|||
|
||||
let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(todo_cgus.len()));
|
||||
|
||||
let modules = tcx.sess.time("codegen mono items", || {
|
||||
let mut modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| {
|
||||
let dep_node = cgu.codegen_dep_node(tcx);
|
||||
tcx.dep_graph
|
||||
.with_task(
|
||||
let modules: Vec<_> =
|
||||
tcx.sess.time("codegen mono items", || {
|
||||
let modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| {
|
||||
let dep_node = cgu.codegen_dep_node(tcx);
|
||||
let (module, _) = tcx.dep_graph.with_task(
|
||||
dep_node,
|
||||
tcx,
|
||||
(global_asm_config.clone(), cgu.name(), concurrency_limiter.acquire(tcx.dcx())),
|
||||
module_codegen,
|
||||
Some(rustc_middle::dep_graph::hash_result),
|
||||
)
|
||||
.0
|
||||
});
|
||||
modules.extend(
|
||||
done_cgus
|
||||
);
|
||||
IntoDynSyncSend(module)
|
||||
});
|
||||
modules
|
||||
.into_iter()
|
||||
.map(|(_, cgu)| OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))),
|
||||
);
|
||||
modules
|
||||
});
|
||||
.map(|module| module.0)
|
||||
.chain(done_cgus.into_iter().map(|(_, cgu)| {
|
||||
OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
|
||||
}))
|
||||
.collect()
|
||||
});
|
||||
|
||||
let allocator_module = emit_allocator_module(tcx);
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,7 @@ pub(crate) fn compile_global_asm(
|
|||
config: &GlobalAsmConfig,
|
||||
cgu_name: &str,
|
||||
global_asm: &str,
|
||||
invocation_temp: Option<&str>,
|
||||
) -> Result<Option<PathBuf>, String> {
|
||||
if global_asm.is_empty() {
|
||||
return Ok(None);
|
||||
|
|
@ -146,7 +147,7 @@ pub(crate) fn compile_global_asm(
|
|||
global_asm.push('\n');
|
||||
|
||||
let global_asm_object_file = add_file_stem_postfix(
|
||||
config.output_filenames.temp_path(OutputType::Object, Some(cgu_name)),
|
||||
config.output_filenames.temp_path_for_cgu(OutputType::Object, cgu_name, invocation_temp),
|
||||
".asm",
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//! Codegen of intrinsics. This includes `extern "rust-intrinsic"`,
|
||||
//! functions marked with the `#[rustc_intrinsic]` attribute
|
||||
//! Codegen of intrinsics. This includes functions marked with the `#[rustc_intrinsic]` attribute
|
||||
//! and LLVM intrinsics that have symbol names starting with `llvm.`.
|
||||
|
||||
macro_rules! intrinsic_args {
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
|
|||
/// inside a single codegen unit with the exception of the Cranelift [`Module`](cranelift_module::Module).
|
||||
struct CodegenCx {
|
||||
output_filenames: Arc<OutputFilenames>,
|
||||
invocation_temp: Option<String>,
|
||||
should_write_ir: bool,
|
||||
global_asm: String,
|
||||
inline_asm_index: usize,
|
||||
|
|
@ -142,6 +143,7 @@ impl CodegenCx {
|
|||
};
|
||||
CodegenCx {
|
||||
output_filenames: tcx.output_filenames(()).clone(),
|
||||
invocation_temp: tcx.sess.invocation_temp.clone(),
|
||||
should_write_ir: crate::pretty_clif::should_write_ir(tcx),
|
||||
global_asm: String::new(),
|
||||
inline_asm_index: 0,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use rustc_hir::LangItem;
|
||||
use rustc_middle::ty::{AssocKind, GenericArg};
|
||||
use rustc_middle::ty::{AssocTag, GenericArg};
|
||||
use rustc_session::config::EntryFnType;
|
||||
use rustc_span::{DUMMY_SP, Ident};
|
||||
|
||||
|
|
@ -104,10 +104,10 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||
let termination_trait = tcx.require_lang_item(LangItem::Termination, None);
|
||||
let report = tcx
|
||||
.associated_items(termination_trait)
|
||||
.find_by_name_and_kind(
|
||||
.find_by_ident_and_kind(
|
||||
tcx,
|
||||
Ident::from_str("report"),
|
||||
AssocKind::Fn,
|
||||
AssocTag::Fn,
|
||||
termination_trait,
|
||||
)
|
||||
.unwrap();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -121,3 +123,22 @@ jobs:
|
|||
run: |
|
||||
cd build_system
|
||||
cargo test
|
||||
|
||||
# Summary job for the merge queue.
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
success:
|
||||
needs: [build, duplicates, build_system]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@
|
|||
name: Failures
|
||||
|
||||
on:
|
||||
- pull_request
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -108,3 +111,22 @@ jobs:
|
|||
echo "Error: 'the compiler unexpectedly panicked' found in output logs. CI Error!!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Summary job for the merge queue.
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
success_failures:
|
||||
needs: [build]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
name: CI libgccjit 12
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -85,3 +87,22 @@ jobs:
|
|||
#- name: Run tests
|
||||
#run: |
|
||||
#./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features
|
||||
|
||||
# Summary job for the merge queue.
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
success_gcc12:
|
||||
needs: [build]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
|
|
|||
|
|
@ -3,8 +3,10 @@
|
|||
name: m68k CI
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -105,3 +107,22 @@ jobs:
|
|||
- name: Run tests
|
||||
run: |
|
||||
./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }}
|
||||
|
||||
# Summary job for the merge queue.
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
success_m68k:
|
||||
needs: [build]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
name: CI with sysroot compiled in release mode
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -82,3 +84,22 @@ jobs:
|
|||
echo "Test is done with LTO enabled, hence inlining should occur across crates"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Summary job for the merge queue.
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
success_release:
|
||||
needs: [build]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
name: stdarch tests with sysroot compiled in release mode
|
||||
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
|
@ -102,3 +104,22 @@ jobs:
|
|||
# TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc.
|
||||
# TODO: remove --skip test_tile_ when it's implemented.
|
||||
STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_
|
||||
|
||||
# Summary job for the merge queue.
|
||||
# ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
|
||||
success_stdarch:
|
||||
needs: [build]
|
||||
# We need to ensure this job does *not* get skipped if its dependencies fail,
|
||||
# because a skipped job is considered a success by GitHub. So we have to
|
||||
# overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
|
||||
# when the workflow is canceled manually.
|
||||
if: ${{ !cancelled() }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# Manually check the status of all dependencies. `if: failure()` does not work.
|
||||
- name: Conclusion
|
||||
run: |
|
||||
# Print the dependent jobs to see them in the CI log
|
||||
jq -C <<< '${{ toJson(needs) }}'
|
||||
# Check if all jobs that we depend on (in the needs array) were successful.
|
||||
jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
|
||||
|
|
|
|||
|
|
@ -56,18 +56,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gccjit"
|
||||
version = "2.4.0"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72fd91f4adbf02b53cfc73c97bc33c5f253009043f30c56a5ec08dd5c8094dc8"
|
||||
checksum = "2895ddec764de7ac76fe6c056050c4801a80109c066f177a00a9cc8dee02b29b"
|
||||
dependencies = [
|
||||
"gccjit_sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gccjit_sys"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fb7b8f48a75e2cfe78c3d9a980b32771c34ffd12d196021ab3f98c49fbd2f0d"
|
||||
checksum = "ac133db68db8a6a8b2c51ef4b18d8ea16682d5814c4641272fe37bbbc223d5f3"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ master = ["gccjit/master"]
|
|||
default = ["master"]
|
||||
|
||||
[dependencies]
|
||||
gccjit = "2.4"
|
||||
gccjit = "2.5"
|
||||
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" }
|
||||
|
||||
# Local copy.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ A secondary goal is to check if using the gcc backend will provide any run-time
|
|||
## Building
|
||||
|
||||
**This requires a patched libgccjit in order to work.
|
||||
You need to use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
|
||||
You need to use my [fork of gcc](https://github.com/rust-lang/gcc) which already includes these patches.**
|
||||
|
||||
```bash
|
||||
$ cp config.example.toml config.toml
|
||||
|
|
@ -40,7 +40,7 @@ to do a few more things.
|
|||
To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue):
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/antoyo/gcc
|
||||
$ git clone https://github.com/rust-lang/gcc
|
||||
$ sudo apt install flex libmpfr-dev libgmp-dev libmpc3 libmpc-dev
|
||||
$ mkdir gcc-build gcc-install
|
||||
$ cd gcc-build
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ pub fn run() -> Result<(), String> {
|
|||
return Ok(());
|
||||
};
|
||||
|
||||
let result = git_clone("https://github.com/antoyo/gcc", Some(&args.out_path), false)?;
|
||||
let result = git_clone("https://github.com/rust-lang/gcc", Some(&args.out_path), false)?;
|
||||
if result.ran_clone {
|
||||
let gcc_commit = args.config_info.get_gcc_commit()?;
|
||||
println!("Checking out GCC commit `{}`...", gcc_commit);
|
||||
|
|
|
|||
|
|
@ -529,20 +529,21 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
|
||||
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
|
||||
|
||||
let extra =
|
||||
if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" };
|
||||
|
||||
let rustc_args = &format!(
|
||||
r#"-Zpanic-abort-tests \
|
||||
-Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \
|
||||
--sysroot "{sysroot_dir}" -Cpanic=abort{extra}"#,
|
||||
let codegen_backend_path = format!(
|
||||
"{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
|
||||
pwd = std::env::current_dir()
|
||||
.map_err(|error| format!("`current_dir` failed: {:?}", error))?
|
||||
.display(),
|
||||
channel = args.config_info.channel.as_str(),
|
||||
dylib_ext = args.config_info.dylib_ext,
|
||||
sysroot_dir = args.config_info.sysroot_path,
|
||||
extra = extra,
|
||||
);
|
||||
|
||||
let extra =
|
||||
if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" };
|
||||
|
||||
let rustc_args = format!(
|
||||
"-Zpanic-abort-tests -Zcodegen-backend={codegen_backend_path} --sysroot {} -Cpanic=abort{extra}",
|
||||
args.config_info.sysroot_path
|
||||
);
|
||||
|
||||
run_command_with_env(
|
||||
|
|
@ -677,7 +678,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[TEST] libcore");
|
||||
let path = get_sysroot_dir().join("sysroot_src/library/core/tests");
|
||||
let path = get_sysroot_dir().join("sysroot_src/library/coretests");
|
||||
let _ = remove_dir_all(path.join("target"));
|
||||
run_cargo_command(&[&"test"], Some(&path), env, args)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -14,4 +14,4 @@ Finally, you need to update this repository by calling the relevant API you adde
|
|||
|
||||
To test it, build `gcc`, run `cargo update -p gccjit` and then you can test the generated output for a given Rust crate.
|
||||
|
||||
[gccjit.rs]: https://github.com/antoyo/gccjit.rs
|
||||
[gccjit.rs]: https://github.com/rust-lang/gccjit.rs
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@ impl<T: ?Sized> LegacyReceiver for &T {}
|
|||
impl<T: ?Sized> LegacyReceiver for &mut T {}
|
||||
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
|
||||
|
||||
#[lang = "receiver"]
|
||||
trait Receiver {
|
||||
}
|
||||
|
||||
#[lang = "copy"]
|
||||
pub trait Copy {}
|
||||
|
||||
|
|
@ -134,6 +138,14 @@ impl Mul for u8 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Mul for i32 {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
self * rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Mul for usize {
|
||||
type Output = Self;
|
||||
|
||||
|
|
@ -142,6 +154,14 @@ impl Mul for usize {
|
|||
}
|
||||
}
|
||||
|
||||
impl Mul for isize {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, rhs: Self) -> Self::Output {
|
||||
self * rhs
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "add"]
|
||||
pub trait Add<RHS = Self> {
|
||||
type Output;
|
||||
|
|
@ -165,6 +185,14 @@ impl Add for i8 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Add for i32 {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self {
|
||||
self + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for usize {
|
||||
type Output = Self;
|
||||
|
||||
|
|
@ -196,6 +224,14 @@ impl Sub for usize {
|
|||
}
|
||||
}
|
||||
|
||||
impl Sub for isize {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
self - rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for u8 {
|
||||
type Output = Self;
|
||||
|
||||
|
|
@ -220,6 +256,14 @@ impl Sub for i16 {
|
|||
}
|
||||
}
|
||||
|
||||
impl Sub for i32 {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self {
|
||||
self - rhs
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "rem"]
|
||||
pub trait Rem<RHS = Self> {
|
||||
type Output;
|
||||
|
|
@ -628,6 +672,10 @@ pub mod libc {
|
|||
pub fn memcpy(dst: *mut u8, src: *const u8, size: usize);
|
||||
pub fn memmove(dst: *mut u8, src: *const u8, size: usize);
|
||||
pub fn strncpy(dst: *mut u8, src: *const u8, size: usize);
|
||||
pub fn fflush(stream: *mut i32) -> i32;
|
||||
pub fn exit(status: i32);
|
||||
|
||||
pub static stdout: *mut i32;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
e607be166673a8de9fc07f6f02c60426e556c5f2
|
||||
0ea98a1365b81f7488073512c850e8ee951a4afd
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
From af0e237f056fa838c77463381a19b0dc993c0a35 Mon Sep 17 00:00:00 2001
|
||||
From: None <none@example.com>
|
||||
Date: Sun, 1 Sep 2024 11:42:17 -0400
|
||||
Subject: [PATCH] Disable not compiling tests
|
||||
|
||||
---
|
||||
library/core/tests/Cargo.toml | 14 ++++++++++++++
|
||||
library/core/tests/lib.rs | 1 +
|
||||
2 files changed, 15 insertions(+)
|
||||
create mode 100644 library/core/tests/Cargo.toml
|
||||
|
||||
diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml
|
||||
new file mode 100644
|
||||
index 0000000..ca326ac
|
||||
--- /dev/null
|
||||
+++ b/library/core/tests/Cargo.toml
|
||||
@@ -0,0 +1,14 @@
|
||||
+[workspace]
|
||||
+
|
||||
+[package]
|
||||
+name = "coretests"
|
||||
+version = "0.0.0"
|
||||
+edition = "2021"
|
||||
+
|
||||
+[lib]
|
||||
+name = "coretests"
|
||||
+path = "lib.rs"
|
||||
+
|
||||
+[dependencies]
|
||||
+rand = { version = "0.8.5", default-features = false }
|
||||
+rand_xorshift = { version = "0.3.0", default-features = false }
|
||||
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
|
||||
index a4a7946..ecfe43f 100644
|
||||
--- a/library/core/tests/lib.rs
|
||||
+++ b/library/core/tests/lib.rs
|
||||
@@ -1,4 +1,5 @@
|
||||
// tidy-alphabetical-start
|
||||
+#![cfg(test)]
|
||||
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
|
||||
#![cfg_attr(test, feature(cfg_match))]
|
||||
#![feature(alloc_layout_extra)]
|
||||
--
|
||||
2.47.1
|
||||
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
From eb703e627e7a84f1cd8d0d87f0f69da1f0acf765 Mon Sep 17 00:00:00 2001
|
||||
From: bjorn3 <bjorn3@users.noreply.github.com>
|
||||
Date: Fri, 3 Dec 2021 12:16:30 +0100
|
||||
From ec2d0dc77fb484d926b45bb626b0db6a4bb0ab5c Mon Sep 17 00:00:00 2001
|
||||
From: None <none@example.com>
|
||||
Date: Thu, 27 Mar 2025 09:20:41 -0400
|
||||
Subject: [PATCH] Disable long running tests
|
||||
|
||||
---
|
||||
library/core/tests/slice.rs | 2 ++
|
||||
library/coretests/tests/slice.rs | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
|
||||
index 8402833..84592e0 100644
|
||||
--- a/library/core/tests/slice.rs
|
||||
+++ b/library/core/tests/slice.rs
|
||||
@@ -2462,6 +2462,7 @@ take_tests! {
|
||||
diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs
|
||||
index d17e681..fba5cd6 100644
|
||||
--- a/library/coretests/tests/slice.rs
|
||||
+++ b/library/coretests/tests/slice.rs
|
||||
@@ -2486,6 +2486,7 @@ split_off_tests! {
|
||||
#[cfg(not(miri))] // unused in Miri
|
||||
const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
|
||||
|
||||
|
|
@ -19,14 +19,14 @@ index 8402833..84592e0 100644
|
|||
// can't be a constant due to const mutability rules
|
||||
#[cfg(not(miri))] // unused in Miri
|
||||
macro_rules! empty_max_mut {
|
||||
@@ -2485,6 +2486,7 @@ take_tests! {
|
||||
(take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
|
||||
(take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
|
||||
@@ -2509,6 +2510,7 @@ split_off_tests! {
|
||||
(split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
|
||||
(split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
|
||||
}
|
||||
+*/
|
||||
|
||||
#[test]
|
||||
fn test_slice_from_ptr_range() {
|
||||
--
|
||||
2.26.2.7.g19db9cfb68
|
||||
2.49.0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
From 966beefe08be6045bfcca26079b76a7a80413080 Mon Sep 17 00:00:00 2001
|
||||
From b2911e732d1bf0e28872495c4c47af1dad3c7911 Mon Sep 17 00:00:00 2001
|
||||
From: None <none@example.com>
|
||||
Date: Thu, 28 Sep 2023 17:37:38 -0400
|
||||
Date: Thu, 27 Mar 2025 14:30:10 -0400
|
||||
Subject: [PATCH] Disable libstd and libtest dylib
|
||||
|
||||
---
|
||||
library/std/Cargo.toml | 2 +-
|
||||
library/test/Cargo.toml | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
library/std/Cargo.toml | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
|
||||
index 5b21355..cb0c49b 100644
|
||||
index 176da60..c183cdb 100644
|
||||
--- a/library/std/Cargo.toml
|
||||
+++ b/library/std/Cargo.toml
|
||||
@@ -9,7 +9,7 @@ description = "The Rust Standard Library"
|
||||
edition = "2021"
|
||||
@@ -10,7 +10,7 @@ edition = "2024"
|
||||
autobenches = false
|
||||
|
||||
[lib]
|
||||
-crate-type = ["dylib", "rlib"]
|
||||
|
|
@ -21,3 +20,6 @@ index 5b21355..cb0c49b 100644
|
|||
|
||||
[dependencies]
|
||||
alloc = { path = "../alloc", public = true }
|
||||
--
|
||||
2.49.0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,25 +1,17 @@
|
|||
From 124a11ce086952a5794d5cfbaa45175809497b81 Mon Sep 17 00:00:00 2001
|
||||
From 1a8f6b8e39f343959d4d2e6b6957a6d780ac3fc0 Mon Sep 17 00:00:00 2001
|
||||
From: None <none@example.com>
|
||||
Date: Sat, 18 Nov 2023 10:50:36 -0500
|
||||
Subject: [PATCH] [core] Disable portable-simd test
|
||||
Date: Thu, 27 Mar 2025 14:32:14 -0400
|
||||
Subject: [PATCH] Disable portable-simd test
|
||||
|
||||
---
|
||||
library/core/tests/lib.rs | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
library/coretests/tests/lib.rs | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
|
||||
index b71786c..cf484d5 100644
|
||||
--- a/library/core/tests/lib.rs
|
||||
+++ b/library/core/tests/lib.rs
|
||||
@@ -87,7 +87,6 @@
|
||||
#![feature(numfmt)]
|
||||
#![feature(pattern)]
|
||||
#![feature(pointer_is_aligned_to)]
|
||||
-#![feature(portable_simd)]
|
||||
#![feature(ptr_metadata)]
|
||||
#![feature(slice_from_ptr_range)]
|
||||
#![feature(slice_internals)]
|
||||
@@ -155,7 +154,6 @@ mod pin;
|
||||
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
|
||||
index 79022fe..9223b2f 100644
|
||||
--- a/library/coretests/tests/lib.rs
|
||||
+++ b/library/coretests/tests/lib.rs
|
||||
@@ -165,7 +165,6 @@ mod pin;
|
||||
mod pin_macro;
|
||||
mod ptr;
|
||||
mod result;
|
||||
|
|
@ -27,4 +19,6 @@ index b71786c..cf484d5 100644
|
|||
mod slice;
|
||||
mod str;
|
||||
mod str_lossy;
|
||||
-- 2.45.2
|
||||
--
|
||||
2.49.0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-01-12"
|
||||
channel = "nightly-2025-04-17"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ use rustc_middle::ty::Ty;
|
|||
use rustc_middle::ty::layout::LayoutOf;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_session::config;
|
||||
#[cfg(feature = "master")]
|
||||
use rustc_target::callconv::Conv;
|
||||
use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode};
|
||||
|
||||
use crate::builder::Builder;
|
||||
|
|
@ -105,6 +107,8 @@ pub trait FnAbiGccExt<'gcc, 'tcx> {
|
|||
// TODO(antoyo): return a function pointer type instead?
|
||||
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc>;
|
||||
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
|
||||
#[cfg(feature = "master")]
|
||||
fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<FnAttribute<'gcc>>;
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
||||
|
|
@ -227,4 +231,47 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
);
|
||||
pointer_type
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<FnAttribute<'gcc>> {
|
||||
conv_to_fn_attribute(self.conv, &cx.tcx.sess.target.arch)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute<'gcc>> {
|
||||
// TODO: handle the calling conventions returning None.
|
||||
let attribute = match conv {
|
||||
Conv::C
|
||||
| Conv::Rust
|
||||
| Conv::CCmseNonSecureCall
|
||||
| Conv::CCmseNonSecureEntry
|
||||
| Conv::RiscvInterrupt { .. } => return None,
|
||||
Conv::Cold => return None,
|
||||
Conv::PreserveMost => return None,
|
||||
Conv::PreserveAll => return None,
|
||||
Conv::GpuKernel => {
|
||||
// TODO(antoyo): remove clippy allow attribute when this is implemented.
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if arch == "amdgpu" {
|
||||
return None;
|
||||
} else if arch == "nvptx64" {
|
||||
return None;
|
||||
} else {
|
||||
panic!("Architecture {} does not support GpuKernel calling convention", arch);
|
||||
}
|
||||
}
|
||||
Conv::AvrInterrupt => return None,
|
||||
Conv::AvrNonBlockingInterrupt => return None,
|
||||
Conv::ArmAapcs => return None,
|
||||
Conv::Msp430Intr => return None,
|
||||
Conv::X86Fastcall => return None,
|
||||
Conv::X86Intr => return None,
|
||||
Conv::X86Stdcall => return None,
|
||||
Conv::X86ThisCall => return None,
|
||||
Conv::X86VectorCall => return None,
|
||||
Conv::X86_64SysV => FnAttribute::SysvAbi,
|
||||
Conv::X86_64Win64 => FnAttribute::MsAbi,
|
||||
};
|
||||
Some(attribute)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ use crate::type_of::LayoutGccExt;
|
|||
//
|
||||
// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
|
||||
// Contrary, Rust expresses clobbers through "out" operands that aren't tied to
|
||||
// a variable (`_`), and such "clobbers" do have index.
|
||||
// a variable (`_`), and such "clobbers" do have index. Input operands cannot also
|
||||
// be clobbered.
|
||||
//
|
||||
// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
|
||||
// (like `out("eax")`) directly, offering so-called "local register variables"
|
||||
|
|
@ -161,6 +162,16 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
// Also, we don't emit any asm operands immediately; we save them to
|
||||
// the one of the buffers to be emitted later.
|
||||
|
||||
let mut input_registers = vec![];
|
||||
|
||||
for op in rust_operands {
|
||||
if let InlineAsmOperandRef::In { reg, .. } = *op {
|
||||
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
|
||||
input_registers.push(reg_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 1. Normal variables (and saving operands to buffers).
|
||||
for (rust_idx, op) in rust_operands.iter().enumerate() {
|
||||
match *op {
|
||||
|
|
@ -183,25 +194,39 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
continue;
|
||||
}
|
||||
(Register(reg_name), None) => {
|
||||
// `clobber_abi` can add lots of clobbers that are not supported by the target,
|
||||
// such as AVX-512 registers, so we just ignore unsupported registers
|
||||
let is_target_supported =
|
||||
reg.reg_class().supported_types(asm_arch, true).iter().any(
|
||||
|&(_, feature)| {
|
||||
if let Some(feature) = feature {
|
||||
self.tcx
|
||||
.asm_target_features(instance.def_id())
|
||||
.contains(&feature)
|
||||
} else {
|
||||
true // Register class is unconditionally supported
|
||||
}
|
||||
},
|
||||
);
|
||||
if input_registers.contains(®_name) {
|
||||
// the `clobber_abi` operand is converted into a series of
|
||||
// `lateout("reg") _` operands. Of course, a user could also
|
||||
// explicitly define such an output operand.
|
||||
//
|
||||
// GCC does not allow input registers to be clobbered, so if this out register
|
||||
// is also used as an in register, do not add it to the clobbers list.
|
||||
// it will be treated as a lateout register with `out_place: None`
|
||||
if !late {
|
||||
bug!("input registers can only be used as lateout regisers");
|
||||
}
|
||||
("r", dummy_output_type(self.cx, reg.reg_class()))
|
||||
} else {
|
||||
// `clobber_abi` can add lots of clobbers that are not supported by the target,
|
||||
// such as AVX-512 registers, so we just ignore unsupported registers
|
||||
let is_target_supported =
|
||||
reg.reg_class().supported_types(asm_arch, true).iter().any(
|
||||
|&(_, feature)| {
|
||||
if let Some(feature) = feature {
|
||||
self.tcx
|
||||
.asm_target_features(instance.def_id())
|
||||
.contains(&feature)
|
||||
} else {
|
||||
true // Register class is unconditionally supported
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if is_target_supported && !clobbers.contains(®_name) {
|
||||
clobbers.push(reg_name);
|
||||
if is_target_supported && !clobbers.contains(®_name) {
|
||||
clobbers.push(reg_name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -230,13 +255,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
|
||||
let constraint =
|
||||
if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
|
||||
constraint
|
||||
} else {
|
||||
// left for the next pass
|
||||
continue;
|
||||
};
|
||||
let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) else {
|
||||
// left for the next pass
|
||||
continue;
|
||||
};
|
||||
|
||||
// Rustc frontend guarantees that input and output types are "compatible",
|
||||
// so we can just use input var's type for the output variable.
|
||||
|
|
@ -589,114 +611,127 @@ fn estimate_template_length(
|
|||
}
|
||||
|
||||
/// Converts a register class to a GCC constraint code.
|
||||
fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
||||
let constraint = match reg {
|
||||
// For vector registers LLVM wants the register name to match the type size.
|
||||
fn reg_to_gcc(reg_or_reg_class: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
|
||||
match reg_or_reg_class {
|
||||
InlineAsmRegOrRegClass::Reg(reg) => {
|
||||
match reg {
|
||||
InlineAsmReg::X86(_) => {
|
||||
// TODO(antoyo): add support for vector register.
|
||||
//
|
||||
// // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
|
||||
return ConstraintOrRegister::Register(match reg.name() {
|
||||
// Some of registers' names does not map 1-1 from rust to gcc
|
||||
"st(0)" => "st",
|
||||
ConstraintOrRegister::Register(explicit_reg_to_gcc(reg))
|
||||
}
|
||||
InlineAsmRegOrRegClass::RegClass(reg_class) => {
|
||||
ConstraintOrRegister::Constraint(reg_class_to_gcc(reg_class))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
name => name,
|
||||
});
|
||||
fn explicit_reg_to_gcc(reg: InlineAsmReg) -> &'static str {
|
||||
// For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
|
||||
match reg {
|
||||
InlineAsmReg::X86(reg) => {
|
||||
// TODO(antoyo): add support for vector register.
|
||||
match reg.reg_class() {
|
||||
X86InlineAsmRegClass::reg_byte => {
|
||||
// GCC does not support the `b` suffix, so we just strip it
|
||||
// see https://github.com/rust-lang/rustc_codegen_gcc/issues/485
|
||||
reg.name().trim_end_matches('b')
|
||||
}
|
||||
_ => match reg.name() {
|
||||
// Some of registers' names does not map 1-1 from rust to gcc
|
||||
"st(0)" => "st",
|
||||
|
||||
_ => unimplemented!(),
|
||||
name => name,
|
||||
},
|
||||
}
|
||||
}
|
||||
// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
|
||||
InlineAsmRegOrRegClass::RegClass(reg) => match reg {
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
|
||||
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
|
||||
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for
|
||||
// "define_constraint".
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
|
||||
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
|
||||
InlineAsmRegClass::X86(
|
||||
X86InlineAsmRegClass::kreg0
|
||||
| X86InlineAsmRegClass::x87_reg
|
||||
| X86InlineAsmRegClass::mmx_reg
|
||||
| X86InlineAsmRegClass::tmm_reg,
|
||||
) => unreachable!("clobber-only"),
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("GCC backend does not support SPIR-V")
|
||||
}
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
},
|
||||
};
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
ConstraintOrRegister::Constraint(constraint)
|
||||
/// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
|
||||
fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str {
|
||||
match reg_class {
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
|
||||
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
|
||||
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
|
||||
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
|
||||
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
|
||||
// https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for
|
||||
// "define_constraint".
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
|
||||
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
|
||||
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
|
||||
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
|
||||
InlineAsmRegClass::X86(
|
||||
X86InlineAsmRegClass::kreg0
|
||||
| X86InlineAsmRegClass::x87_reg
|
||||
| X86InlineAsmRegClass::mmx_reg
|
||||
| X86InlineAsmRegClass::tmm_reg,
|
||||
) => unreachable!("clobber-only"),
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("GCC backend does not support SPIR-V")
|
||||
}
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
|
||||
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
|
||||
InlineAsmRegClass::Err => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Type to use for outputs that are discarded. It doesn't really matter what
|
||||
|
|
|
|||
|
|
@ -24,19 +24,23 @@ pub(crate) unsafe fn codegen(
|
|||
{
|
||||
let context = &module.module_llvm.context;
|
||||
|
||||
let module_name = module.name.clone();
|
||||
|
||||
let should_combine_object_files = module.module_llvm.should_combine_object_files;
|
||||
|
||||
let module_name = Some(&module_name[..]);
|
||||
|
||||
// NOTE: Only generate object files with GIMPLE when this environment variable is set for
|
||||
// now because this requires a particular setup (same gcc/lto1/lto-wrapper commit as libgccjit).
|
||||
// TODO(antoyo): remove this environment variable.
|
||||
let fat_lto = env::var("EMBED_LTO_BITCODE").as_deref() == Ok("1");
|
||||
|
||||
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
|
||||
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
|
||||
let bc_out = cgcx.output_filenames.temp_path_for_cgu(
|
||||
OutputType::Bitcode,
|
||||
&module.name,
|
||||
cgcx.invocation_temp.as_deref(),
|
||||
);
|
||||
let obj_out = cgcx.output_filenames.temp_path_for_cgu(
|
||||
OutputType::Object,
|
||||
&module.name,
|
||||
cgcx.invocation_temp.as_deref(),
|
||||
);
|
||||
|
||||
if config.bitcode_needed() {
|
||||
if fat_lto {
|
||||
|
|
@ -117,14 +121,22 @@ pub(crate) unsafe fn codegen(
|
|||
}
|
||||
|
||||
if config.emit_ir {
|
||||
let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
|
||||
let out = cgcx.output_filenames.temp_path_for_cgu(
|
||||
OutputType::LlvmAssembly,
|
||||
&module.name,
|
||||
cgcx.invocation_temp.as_deref(),
|
||||
);
|
||||
std::fs::write(out, "").expect("write file");
|
||||
}
|
||||
|
||||
if config.emit_asm {
|
||||
let _timer =
|
||||
cgcx.prof.generic_activity_with_arg("GCC_module_codegen_emit_asm", &*module.name);
|
||||
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
|
||||
let path = cgcx.output_filenames.temp_path_for_cgu(
|
||||
OutputType::Assembly,
|
||||
&module.name,
|
||||
cgcx.invocation_temp.as_deref(),
|
||||
);
|
||||
context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str"));
|
||||
}
|
||||
|
||||
|
|
@ -238,6 +250,7 @@ pub(crate) unsafe fn codegen(
|
|||
config.emit_asm,
|
||||
config.emit_ir,
|
||||
&cgcx.output_filenames,
|
||||
cgcx.invocation_temp.as_deref(),
|
||||
))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -368,16 +368,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
let previous_arg_count = args.len();
|
||||
let orig_args = args;
|
||||
let args = {
|
||||
let function_address_names = self.function_address_names.borrow();
|
||||
let original_function_name = function_address_names.get(&func_ptr);
|
||||
func_ptr = llvm::adjust_function(self.context, &func_name, func_ptr, args);
|
||||
llvm::adjust_intrinsic_arguments(
|
||||
self,
|
||||
gcc_func,
|
||||
args.into(),
|
||||
&func_name,
|
||||
original_function_name,
|
||||
)
|
||||
llvm::adjust_intrinsic_arguments(self, gcc_func, args.into(), &func_name)
|
||||
};
|
||||
let args_adjusted = args.len() != previous_arg_count;
|
||||
let args = self.check_ptr_call("call", func_ptr, &args);
|
||||
|
|
@ -1271,7 +1263,50 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
}
|
||||
|
||||
fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
|
||||
self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs)
|
||||
// LLVM has a concept of "unordered compares", where eg ULT returns true if either the two
|
||||
// arguments are unordered (i.e. either is NaN), or the lhs is less than the rhs. GCC does
|
||||
// not natively have this concept, so in some cases we must manually handle NaNs
|
||||
let must_handle_nan = match op {
|
||||
RealPredicate::RealPredicateFalse => unreachable!(),
|
||||
RealPredicate::RealOEQ => false,
|
||||
RealPredicate::RealOGT => false,
|
||||
RealPredicate::RealOGE => false,
|
||||
RealPredicate::RealOLT => false,
|
||||
RealPredicate::RealOLE => false,
|
||||
RealPredicate::RealONE => false,
|
||||
RealPredicate::RealORD => unreachable!(),
|
||||
RealPredicate::RealUNO => unreachable!(),
|
||||
RealPredicate::RealUEQ => false,
|
||||
RealPredicate::RealUGT => true,
|
||||
RealPredicate::RealUGE => true,
|
||||
RealPredicate::RealULT => true,
|
||||
RealPredicate::RealULE => true,
|
||||
RealPredicate::RealUNE => false,
|
||||
RealPredicate::RealPredicateTrue => unreachable!(),
|
||||
};
|
||||
|
||||
let cmp = self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs);
|
||||
|
||||
if must_handle_nan {
|
||||
let is_nan = self.context.new_binary_op(
|
||||
self.location,
|
||||
BinaryOp::LogicalOr,
|
||||
self.cx.bool_type,
|
||||
// compare a value to itself to check whether it is NaN
|
||||
self.context.new_comparison(self.location, ComparisonOp::NotEquals, lhs, lhs),
|
||||
self.context.new_comparison(self.location, ComparisonOp::NotEquals, rhs, rhs),
|
||||
);
|
||||
|
||||
self.context.new_binary_op(
|
||||
self.location,
|
||||
BinaryOp::LogicalOr,
|
||||
self.cx.bool_type,
|
||||
is_nan,
|
||||
cmp,
|
||||
)
|
||||
} else {
|
||||
cmp
|
||||
}
|
||||
}
|
||||
|
||||
/* Miscellaneous instructions */
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ use rustc_target::spec::{
|
|||
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
|
||||
};
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
use crate::abi::conv_to_fn_attribute;
|
||||
use crate::callee::get_fn;
|
||||
use crate::common::SignType;
|
||||
|
||||
|
|
@ -213,33 +215,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let bool_type = context.new_type::<bool>();
|
||||
|
||||
let mut functions = FxHashMap::default();
|
||||
let builtins = [
|
||||
"__builtin_unreachable",
|
||||
"abort",
|
||||
"__builtin_expect", /*"__builtin_expect_with_probability",*/
|
||||
"__builtin_constant_p",
|
||||
"__builtin_add_overflow",
|
||||
"__builtin_mul_overflow",
|
||||
"__builtin_saddll_overflow",
|
||||
/*"__builtin_sadd_overflow",*/
|
||||
"__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
|
||||
"__builtin_ssubll_overflow",
|
||||
/*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow",
|
||||
"__builtin_uaddll_overflow",
|
||||
"__builtin_uadd_overflow",
|
||||
"__builtin_umulll_overflow",
|
||||
"__builtin_umul_overflow",
|
||||
"__builtin_usubll_overflow",
|
||||
"__builtin_usub_overflow",
|
||||
"__builtin_powif",
|
||||
"__builtin_powi",
|
||||
"fabsf",
|
||||
"fabs",
|
||||
"copysignf",
|
||||
"copysign",
|
||||
"nearbyintf",
|
||||
"nearbyint",
|
||||
];
|
||||
let builtins = ["abort"];
|
||||
|
||||
for builtin in builtins.iter() {
|
||||
functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
|
||||
|
|
@ -509,7 +485,11 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
||||
let entry_name = self.sess().target.entry_name.as_ref();
|
||||
if !self.functions.borrow().contains_key(entry_name) {
|
||||
Some(self.declare_entry_fn(entry_name, fn_type, ()))
|
||||
#[cfg(feature = "master")]
|
||||
let conv = conv_to_fn_attribute(self.sess().target.entry_abi, &self.sess().target.arch);
|
||||
#[cfg(not(feature = "master"))]
|
||||
let conv = None;
|
||||
Some(self.declare_entry_fn(entry_name, fn_type, conv))
|
||||
} else {
|
||||
// If the symbol already exists, it is an error: for example, the user wrote
|
||||
// #[no_mangle] extern "C" fn main(..) {..}
|
||||
|
|
@ -605,7 +585,10 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
|
|||
let mut name = String::with_capacity(prefix.len() + 6);
|
||||
name.push_str(prefix);
|
||||
name.push('.');
|
||||
name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
|
||||
// Offset the index by the base so that always at least two characters
|
||||
// are generated. This avoids cases where the suffix is interpreted as
|
||||
// size by the assembler (for m68k: .b, .w, .l).
|
||||
name.push_str(&(idx as u64 + ALPHANUMERIC_ONLY as u64).to_base(ALPHANUMERIC_ONLY));
|
||||
name
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
variadic: bool,
|
||||
) -> Function<'gcc> {
|
||||
self.linkage.set(FunctionType::Extern);
|
||||
declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic)
|
||||
declare_raw_fn(self, name, None, return_type, params, variadic)
|
||||
}
|
||||
|
||||
pub fn declare_global(
|
||||
|
|
@ -92,7 +92,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
&self,
|
||||
name: &str,
|
||||
_fn_type: Type<'gcc>,
|
||||
callconv: (), /*llvm::CCallConv*/
|
||||
#[cfg(feature = "master")] callconv: Option<FnAttribute<'gcc>>,
|
||||
#[cfg(not(feature = "master"))] callconv: Option<()>,
|
||||
) -> RValue<'gcc> {
|
||||
// TODO(antoyo): use the fn_type parameter.
|
||||
let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
|
||||
|
|
@ -123,14 +124,11 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
#[cfg(feature = "master")]
|
||||
fn_attributes,
|
||||
} = fn_abi.gcc_type(self);
|
||||
let func = declare_raw_fn(
|
||||
self,
|
||||
name,
|
||||
(), /*fn_abi.llvm_cconv()*/
|
||||
return_type,
|
||||
&arguments_type,
|
||||
is_c_variadic,
|
||||
);
|
||||
#[cfg(feature = "master")]
|
||||
let conv = fn_abi.gcc_cconv(self);
|
||||
#[cfg(not(feature = "master"))]
|
||||
let conv = None;
|
||||
let func = declare_raw_fn(self, name, conv, return_type, &arguments_type, is_c_variadic);
|
||||
self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
|
||||
#[cfg(feature = "master")]
|
||||
for fn_attr in fn_attributes {
|
||||
|
|
@ -162,7 +160,8 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
fn declare_raw_fn<'gcc>(
|
||||
cx: &CodegenCx<'gcc, '_>,
|
||||
name: &str,
|
||||
_callconv: (), /*llvm::CallConv*/
|
||||
#[cfg(feature = "master")] callconv: Option<FnAttribute<'gcc>>,
|
||||
#[cfg(not(feature = "master"))] _callconv: Option<()>,
|
||||
return_type: Type<'gcc>,
|
||||
param_types: &[Type<'gcc>],
|
||||
variadic: bool,
|
||||
|
|
@ -192,6 +191,10 @@ fn declare_raw_fn<'gcc>(
|
|||
let name = &mangle_name(name);
|
||||
let func =
|
||||
cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, name, variadic);
|
||||
#[cfg(feature = "master")]
|
||||
if let Some(attribute) = callconv {
|
||||
func.add_attribute(attribute);
|
||||
}
|
||||
cx.functions.borrow_mut().insert(name.to_string(), func);
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ pub fn to_gcc_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]>
|
|||
|
||||
fn arch_to_gcc(name: &str) -> &str {
|
||||
match name {
|
||||
"M68000" => "68000",
|
||||
"M68020" => "68020",
|
||||
_ => name,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
|
||||
let ret_indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
|
||||
|
||||
let result = if ret_indirect {
|
||||
let call = if ret_indirect {
|
||||
let res_value = self.current_func().new_local(self.location, res_type, "result_value");
|
||||
let res_addr = res_value.get_address(self.location);
|
||||
let res_param_type = res_type.make_pointer();
|
||||
|
|
@ -432,8 +432,17 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
|
|||
);
|
||||
self.context.new_call(self.location, func, &[lhs, rhs, overflow_addr])
|
||||
};
|
||||
// NOTE: we must assign the result of the operation to a variable at this point to make
|
||||
// sure it will be evaluated by libgccjit now.
|
||||
// Otherwise, it will only be evaluated when the rvalue for the call is used somewhere else
|
||||
// and overflow_value will not be initialized at the correct point in the program.
|
||||
let result = self.current_func().new_local(self.location, res_type, "result");
|
||||
self.block.add_assignment(self.location, result, call);
|
||||
|
||||
(result, self.context.new_cast(self.location, overflow_value, self.bool_type).to_rvalue())
|
||||
(
|
||||
result.to_rvalue(),
|
||||
self.context.new_cast(self.location, overflow_value, self.bool_type).to_rvalue(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn gcc_icmp(
|
||||
|
|
@ -865,6 +874,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let value_type = value.get_type();
|
||||
if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type)
|
||||
{
|
||||
// TODO: use self.location.
|
||||
self.context.new_cast(None, value, dest_typ)
|
||||
} else if self.is_native_int_type_or_bool(dest_typ) {
|
||||
self.context.new_cast(None, self.low(value), dest_typ)
|
||||
|
|
@ -905,6 +915,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||
let name_suffix = match self.type_kind(dest_typ) {
|
||||
TypeKind::Float => "tisf",
|
||||
TypeKind::Double => "tidf",
|
||||
TypeKind::FP128 => "tixf",
|
||||
kind => panic!("cannot cast a non-native integer to type {:?}", kind),
|
||||
};
|
||||
let sign = if signed { "" } else { "un" };
|
||||
|
|
|
|||
|
|
@ -1,11 +1,90 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use gccjit::{CType, Context, Function, FunctionPtrType, RValue, ToRValue, UnaryOp};
|
||||
use gccjit::{CType, Context, Field, Function, FunctionPtrType, RValue, ToRValue, Type};
|
||||
use rustc_codegen_ssa::traits::BuilderMethods;
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::context::CodegenCx;
|
||||
|
||||
fn encode_key_128_type<'a, 'gcc, 'tcx>(
|
||||
builder: &Builder<'a, 'gcc, 'tcx>,
|
||||
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
|
||||
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
|
||||
let field1 = builder.context.new_field(None, builder.u32_type, "field1");
|
||||
let field2 = builder.context.new_field(None, m128i, "field2");
|
||||
let field3 = builder.context.new_field(None, m128i, "field3");
|
||||
let field4 = builder.context.new_field(None, m128i, "field4");
|
||||
let field5 = builder.context.new_field(None, m128i, "field5");
|
||||
let field6 = builder.context.new_field(None, m128i, "field6");
|
||||
let field7 = builder.context.new_field(None, m128i, "field7");
|
||||
let encode_type = builder.context.new_struct_type(
|
||||
None,
|
||||
"EncodeKey128Output",
|
||||
&[field1, field2, field3, field4, field5, field6, field7],
|
||||
);
|
||||
#[cfg(feature = "master")]
|
||||
encode_type.as_type().set_packed();
|
||||
(encode_type.as_type(), field1, field2)
|
||||
}
|
||||
|
||||
fn encode_key_256_type<'a, 'gcc, 'tcx>(
|
||||
builder: &Builder<'a, 'gcc, 'tcx>,
|
||||
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
|
||||
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
|
||||
let field1 = builder.context.new_field(None, builder.u32_type, "field1");
|
||||
let field2 = builder.context.new_field(None, m128i, "field2");
|
||||
let field3 = builder.context.new_field(None, m128i, "field3");
|
||||
let field4 = builder.context.new_field(None, m128i, "field4");
|
||||
let field5 = builder.context.new_field(None, m128i, "field5");
|
||||
let field6 = builder.context.new_field(None, m128i, "field6");
|
||||
let field7 = builder.context.new_field(None, m128i, "field7");
|
||||
let field8 = builder.context.new_field(None, m128i, "field8");
|
||||
let encode_type = builder.context.new_struct_type(
|
||||
None,
|
||||
"EncodeKey256Output",
|
||||
&[field1, field2, field3, field4, field5, field6, field7, field8],
|
||||
);
|
||||
#[cfg(feature = "master")]
|
||||
encode_type.as_type().set_packed();
|
||||
(encode_type.as_type(), field1, field2)
|
||||
}
|
||||
|
||||
fn aes_output_type<'a, 'gcc, 'tcx>(
|
||||
builder: &Builder<'a, 'gcc, 'tcx>,
|
||||
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
|
||||
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
|
||||
let field1 = builder.context.new_field(None, builder.u8_type, "field1");
|
||||
let field2 = builder.context.new_field(None, m128i, "field2");
|
||||
let aes_output_type = builder.context.new_struct_type(None, "AesOutput", &[field1, field2]);
|
||||
let typ = aes_output_type.as_type();
|
||||
#[cfg(feature = "master")]
|
||||
typ.set_packed();
|
||||
(typ, field1, field2)
|
||||
}
|
||||
|
||||
fn wide_aes_output_type<'a, 'gcc, 'tcx>(
|
||||
builder: &Builder<'a, 'gcc, 'tcx>,
|
||||
) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
|
||||
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
|
||||
let field1 = builder.context.new_field(None, builder.u8_type, "field1");
|
||||
let field2 = builder.context.new_field(None, m128i, "field2");
|
||||
let field3 = builder.context.new_field(None, m128i, "field3");
|
||||
let field4 = builder.context.new_field(None, m128i, "field4");
|
||||
let field5 = builder.context.new_field(None, m128i, "field5");
|
||||
let field6 = builder.context.new_field(None, m128i, "field6");
|
||||
let field7 = builder.context.new_field(None, m128i, "field7");
|
||||
let field8 = builder.context.new_field(None, m128i, "field8");
|
||||
let field9 = builder.context.new_field(None, m128i, "field9");
|
||||
let aes_output_type = builder.context.new_struct_type(
|
||||
None,
|
||||
"WideAesOutput",
|
||||
&[field1, field2, field3, field4, field5, field6, field7, field8, field9],
|
||||
);
|
||||
#[cfg(feature = "master")]
|
||||
aes_output_type.as_type().set_packed();
|
||||
(aes_output_type.as_type(), field1, field2)
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "master"), allow(unused_variables))]
|
||||
pub fn adjust_function<'gcc>(
|
||||
context: &'gcc Context<'gcc>,
|
||||
|
|
@ -43,7 +122,6 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
|
|||
gcc_func: FunctionPtrType<'gcc>,
|
||||
mut args: Cow<'b, [RValue<'gcc>]>,
|
||||
func_name: &str,
|
||||
original_function_name: Option<&String>,
|
||||
) -> Cow<'b, [RValue<'gcc>]> {
|
||||
// TODO: this might not be a good way to workaround the missing tile builtins.
|
||||
if func_name == "__builtin_trap" {
|
||||
|
|
@ -504,6 +582,72 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
|
|||
let arg4 = builder.context.new_rvalue_from_int(arg4_type, -1);
|
||||
args = vec![a, b, c, arg4, new_args[3]].into();
|
||||
}
|
||||
"__builtin_ia32_encodekey128_u32" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
|
||||
let array_type = builder.context.new_array_type(None, m128i, 6);
|
||||
let result = builder.current_func().new_local(None, array_type, "result");
|
||||
new_args.push(result.get_address(None));
|
||||
args = new_args.into();
|
||||
}
|
||||
"__builtin_ia32_encodekey256_u32" => {
|
||||
let mut new_args = args.to_vec();
|
||||
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
|
||||
let array_type = builder.context.new_array_type(None, m128i, 7);
|
||||
let result = builder.current_func().new_local(None, array_type, "result");
|
||||
new_args.push(result.get_address(None));
|
||||
args = new_args.into();
|
||||
}
|
||||
"__builtin_ia32_aesenc128kl_u8"
|
||||
| "__builtin_ia32_aesdec128kl_u8"
|
||||
| "__builtin_ia32_aesenc256kl_u8"
|
||||
| "__builtin_ia32_aesdec256kl_u8" => {
|
||||
let mut new_args = vec![];
|
||||
let m128i = builder.context.new_vector_type(builder.i64_type, 2);
|
||||
let result = builder.current_func().new_local(None, m128i, "result");
|
||||
new_args.push(result.get_address(None));
|
||||
new_args.extend(args.to_vec());
|
||||
args = new_args.into();
|
||||
}
|
||||
"__builtin_ia32_aesencwide128kl_u8"
|
||||
| "__builtin_ia32_aesdecwide128kl_u8"
|
||||
| "__builtin_ia32_aesencwide256kl_u8"
|
||||
| "__builtin_ia32_aesdecwide256kl_u8" => {
|
||||
let mut new_args = vec![];
|
||||
|
||||
let mut old_args = args.to_vec();
|
||||
let handle = old_args.swap_remove(0); // Called __P in GCC.
|
||||
let first_value = old_args.swap_remove(0);
|
||||
|
||||
let element_type = first_value.get_type();
|
||||
let array_type = builder.context.new_array_type(None, element_type, 8);
|
||||
let result = builder.current_func().new_local(None, array_type, "result");
|
||||
new_args.push(result.get_address(None));
|
||||
|
||||
let array = builder.current_func().new_local(None, array_type, "array");
|
||||
let input = builder.context.new_array_constructor(
|
||||
None,
|
||||
array_type,
|
||||
&[
|
||||
first_value,
|
||||
old_args.swap_remove(0),
|
||||
old_args.swap_remove(0),
|
||||
old_args.swap_remove(0),
|
||||
old_args.swap_remove(0),
|
||||
old_args.swap_remove(0),
|
||||
old_args.swap_remove(0),
|
||||
old_args.swap_remove(0),
|
||||
],
|
||||
);
|
||||
builder.llbb().add_assignment(None, array, input);
|
||||
let input_ptr = array.get_address(None);
|
||||
let arg2_type = gcc_func.get_param_type(1);
|
||||
let input_ptr = builder.context.new_cast(None, input_ptr, arg2_type);
|
||||
new_args.push(input_ptr);
|
||||
|
||||
new_args.push(handle);
|
||||
args = new_args.into();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
|
|
@ -541,33 +685,6 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
|
|||
let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 2]);
|
||||
args = vec![a, b, c, new_args[3]].into();
|
||||
}
|
||||
"__builtin_ia32_vfmaddsubpd256"
|
||||
| "__builtin_ia32_vfmaddsubps"
|
||||
| "__builtin_ia32_vfmaddsubps256"
|
||||
| "__builtin_ia32_vfmaddsubpd" => {
|
||||
if let Some(original_function_name) = original_function_name {
|
||||
match &**original_function_name {
|
||||
"llvm.x86.fma.vfmsubadd.pd.256"
|
||||
| "llvm.x86.fma.vfmsubadd.ps"
|
||||
| "llvm.x86.fma.vfmsubadd.ps.256"
|
||||
| "llvm.x86.fma.vfmsubadd.pd" => {
|
||||
// NOTE: since both llvm.x86.fma.vfmsubadd.ps and llvm.x86.fma.vfmaddsub.ps maps to
|
||||
// __builtin_ia32_vfmaddsubps, only add minus if this comes from a
|
||||
// subadd LLVM intrinsic, e.g. _mm256_fmsubadd_pd.
|
||||
let mut new_args = args.to_vec();
|
||||
let arg3 = &mut new_args[2];
|
||||
*arg3 = builder.context.new_unary_op(
|
||||
None,
|
||||
UnaryOp::Minus,
|
||||
arg3.get_type(),
|
||||
*arg3,
|
||||
);
|
||||
args = new_args.into();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
"__builtin_ia32_ldmxcsr" => {
|
||||
// The builtin __builtin_ia32_ldmxcsr takes an integer value while llvm.x86.sse.ldmxcsr takes a pointer,
|
||||
// so dereference the pointer.
|
||||
|
|
@ -728,6 +845,96 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
|
|||
let f16_type = builder.context.new_c_type(CType::Float16);
|
||||
return_value = builder.context.new_cast(None, return_value, f16_type);
|
||||
}
|
||||
"__builtin_ia32_encodekey128_u32" => {
|
||||
// The builtin __builtin_ia32_encodekey128_u32 writes the result in its pointer argument while
|
||||
// llvm.x86.encodekey128 returns a value.
|
||||
// We added a result pointer argument and now need to assign its value to the return_value expected by
|
||||
// the LLVM intrinsic.
|
||||
let (encode_type, field1, field2) = encode_key_128_type(builder);
|
||||
let result = builder.current_func().new_local(None, encode_type, "result");
|
||||
let field1 = result.access_field(None, field1);
|
||||
builder.llbb().add_assignment(None, field1, return_value);
|
||||
let field2 = result.access_field(None, field2);
|
||||
let field2_type = field2.to_rvalue().get_type();
|
||||
let array_type = builder.context.new_array_type(None, field2_type, 6);
|
||||
let ptr = builder.context.new_cast(None, args[2], array_type.make_pointer());
|
||||
let field2_ptr =
|
||||
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
|
||||
builder.llbb().add_assignment(
|
||||
None,
|
||||
field2_ptr.dereference(None),
|
||||
ptr.dereference(None),
|
||||
);
|
||||
return_value = result.to_rvalue();
|
||||
}
|
||||
"__builtin_ia32_encodekey256_u32" => {
|
||||
// The builtin __builtin_ia32_encodekey256_u32 writes the result in its pointer argument while
|
||||
// llvm.x86.encodekey256 returns a value.
|
||||
// We added a result pointer argument and now need to assign its value to the return_value expected by
|
||||
// the LLVM intrinsic.
|
||||
let (encode_type, field1, field2) = encode_key_256_type(builder);
|
||||
let result = builder.current_func().new_local(None, encode_type, "result");
|
||||
let field1 = result.access_field(None, field1);
|
||||
builder.llbb().add_assignment(None, field1, return_value);
|
||||
let field2 = result.access_field(None, field2);
|
||||
let field2_type = field2.to_rvalue().get_type();
|
||||
let array_type = builder.context.new_array_type(None, field2_type, 7);
|
||||
let ptr = builder.context.new_cast(None, args[3], array_type.make_pointer());
|
||||
let field2_ptr =
|
||||
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
|
||||
builder.llbb().add_assignment(
|
||||
None,
|
||||
field2_ptr.dereference(None),
|
||||
ptr.dereference(None),
|
||||
);
|
||||
return_value = result.to_rvalue();
|
||||
}
|
||||
"__builtin_ia32_aesdec128kl_u8"
|
||||
| "__builtin_ia32_aesenc128kl_u8"
|
||||
| "__builtin_ia32_aesdec256kl_u8"
|
||||
| "__builtin_ia32_aesenc256kl_u8" => {
|
||||
// The builtin for aesdec/aesenc writes the result in its pointer argument while
|
||||
// llvm.x86.aesdec128kl returns a value.
|
||||
// We added a result pointer argument and now need to assign its value to the return_value expected by
|
||||
// the LLVM intrinsic.
|
||||
let (aes_output_type, field1, field2) = aes_output_type(builder);
|
||||
let result = builder.current_func().new_local(None, aes_output_type, "result");
|
||||
let field1 = result.access_field(None, field1);
|
||||
builder.llbb().add_assignment(None, field1, return_value);
|
||||
let field2 = result.access_field(None, field2);
|
||||
let ptr = builder.context.new_cast(
|
||||
None,
|
||||
args[0],
|
||||
field2.to_rvalue().get_type().make_pointer(),
|
||||
);
|
||||
builder.llbb().add_assignment(None, field2, ptr.dereference(None));
|
||||
return_value = result.to_rvalue();
|
||||
}
|
||||
"__builtin_ia32_aesencwide128kl_u8"
|
||||
| "__builtin_ia32_aesdecwide128kl_u8"
|
||||
| "__builtin_ia32_aesencwide256kl_u8"
|
||||
| "__builtin_ia32_aesdecwide256kl_u8" => {
|
||||
// The builtin for aesdecwide/aesencwide writes the result in its pointer argument while
|
||||
// llvm.x86.aesencwide128kl returns a value.
|
||||
// We added a result pointer argument and now need to assign its value to the return_value expected by
|
||||
// the LLVM intrinsic.
|
||||
let (aes_output_type, field1, field2) = wide_aes_output_type(builder);
|
||||
let result = builder.current_func().new_local(None, aes_output_type, "result");
|
||||
let field1 = result.access_field(None, field1);
|
||||
builder.llbb().add_assignment(None, field1, return_value);
|
||||
let field2 = result.access_field(None, field2);
|
||||
let field2_type = field2.to_rvalue().get_type();
|
||||
let array_type = builder.context.new_array_type(None, field2_type, 8);
|
||||
let ptr = builder.context.new_cast(None, args[0], array_type.make_pointer());
|
||||
let field2_ptr =
|
||||
builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
|
||||
builder.llbb().add_assignment(
|
||||
None,
|
||||
field2_ptr.dereference(None),
|
||||
ptr.dereference(None),
|
||||
);
|
||||
return_value = result.to_rvalue();
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
|
|
@ -915,16 +1122,6 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
|
|||
"llvm.ctlz.v4i64" => "__builtin_ia32_vplzcntq_256_mask",
|
||||
"llvm.ctlz.v2i64" => "__builtin_ia32_vplzcntq_128_mask",
|
||||
"llvm.ctpop.v32i16" => "__builtin_ia32_vpopcountw_v32hi",
|
||||
"llvm.x86.fma.vfmsub.sd" => "__builtin_ia32_vfmsubsd3",
|
||||
"llvm.x86.fma.vfmsub.ss" => "__builtin_ia32_vfmsubss3",
|
||||
"llvm.x86.fma.vfmsubadd.pd" => "__builtin_ia32_vfmaddsubpd",
|
||||
"llvm.x86.fma.vfmsubadd.pd.256" => "__builtin_ia32_vfmaddsubpd256",
|
||||
"llvm.x86.fma.vfmsubadd.ps" => "__builtin_ia32_vfmaddsubps",
|
||||
"llvm.x86.fma.vfmsubadd.ps.256" => "__builtin_ia32_vfmaddsubps256",
|
||||
"llvm.x86.fma.vfnmadd.sd" => "__builtin_ia32_vfnmaddsd3",
|
||||
"llvm.x86.fma.vfnmadd.ss" => "__builtin_ia32_vfnmaddss3",
|
||||
"llvm.x86.fma.vfnmsub.sd" => "__builtin_ia32_vfnmsubsd3",
|
||||
"llvm.x86.fma.vfnmsub.ss" => "__builtin_ia32_vfnmsubss3",
|
||||
"llvm.x86.avx512.conflict.d.512" => "__builtin_ia32_vpconflictsi_512_mask",
|
||||
"llvm.x86.avx512.conflict.d.256" => "__builtin_ia32_vpconflictsi_256_mask",
|
||||
"llvm.x86.avx512.conflict.d.128" => "__builtin_ia32_vpconflictsi_128_mask",
|
||||
|
|
@ -1002,8 +1199,6 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
|
|||
"llvm.fshr.v32i16" => "__builtin_ia32_vpshrdv_v32hi",
|
||||
"llvm.fshr.v16i16" => "__builtin_ia32_vpshrdv_v16hi",
|
||||
"llvm.fshr.v8i16" => "__builtin_ia32_vpshrdv_v8hi",
|
||||
"llvm.x86.fma.vfmadd.sd" => "__builtin_ia32_vfmaddsd3",
|
||||
"llvm.x86.fma.vfmadd.ss" => "__builtin_ia32_vfmaddss3",
|
||||
"llvm.x86.rdrand.64" => "__builtin_ia32_rdrand64_step",
|
||||
|
||||
// The above doc points to unknown builtins for the following, so override them:
|
||||
|
|
@ -1324,6 +1519,16 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
|
|||
"llvm.x86.avx512fp16.mask.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_mask3",
|
||||
"llvm.x86.avx512fp16.mask.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_mask3",
|
||||
"llvm.x86.avx512fp16.mask.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_mask3",
|
||||
"llvm.x86.encodekey128" => "__builtin_ia32_encodekey128_u32",
|
||||
"llvm.x86.encodekey256" => "__builtin_ia32_encodekey256_u32",
|
||||
"llvm.x86.aesenc128kl" => "__builtin_ia32_aesenc128kl_u8",
|
||||
"llvm.x86.aesdec128kl" => "__builtin_ia32_aesdec128kl_u8",
|
||||
"llvm.x86.aesenc256kl" => "__builtin_ia32_aesenc256kl_u8",
|
||||
"llvm.x86.aesdec256kl" => "__builtin_ia32_aesdec256kl_u8",
|
||||
"llvm.x86.aesencwide128kl" => "__builtin_ia32_aesencwide128kl_u8",
|
||||
"llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8",
|
||||
"llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8",
|
||||
"llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8",
|
||||
|
||||
// TODO: support the tile builtins:
|
||||
"llvm.x86.ldtilecfg" => "__builtin_trap",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue