commit
6bb9af0eeb
2830 changed files with 45305 additions and 30588 deletions
12
.github/ISSUE_TEMPLATE/documentation.yaml
vendored
12
.github/ISSUE_TEMPLATE/documentation.yaml
vendored
|
|
@ -1,5 +1,5 @@
|
|||
name: Documentation problem
|
||||
description: Create a report for a documentation problem.
|
||||
description: Report an issue with documentation content.
|
||||
labels: ["A-docs"]
|
||||
body:
|
||||
- type: markdown
|
||||
|
|
@ -19,20 +19,20 @@ body:
|
|||
- [The Rustonomicon](https://github.com/rust-lang/nomicon/issues)
|
||||
- [The Embedded Book](https://github.com/rust-embedded/book/issues)
|
||||
|
||||
All other documentation issues should be filed here.
|
||||
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the rustdoc issue template instead.
|
||||
|
||||
Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead.
|
||||
All other documentation issues should be filed here.
|
||||
|
||||
- type: textarea
|
||||
id: location
|
||||
attributes:
|
||||
label: Location
|
||||
label: Location (URL)
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: summary
|
||||
attributes:
|
||||
label: Summary
|
||||
validations:
|
||||
required: true
|
||||
required: true
|
||||
|
|
|
|||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
|
@ -117,7 +117,7 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
# Free up disk space on Linux by removing preinstalled components that
|
||||
# Free up disk space on Linux and Windows by removing preinstalled components that
|
||||
# we do not need. We do this to enable some of the less resource
|
||||
# intensive jobs to run on free runners, which however also have
|
||||
# less disk space.
|
||||
|
|
@ -125,6 +125,13 @@ jobs:
|
|||
run: src/ci/scripts/free-disk-space.sh
|
||||
if: matrix.free_disk
|
||||
|
||||
# If we don't need to free up disk space then just report how much space we have
|
||||
- name: print disk usage
|
||||
run: |
|
||||
echo "disk usage:"
|
||||
df -h
|
||||
if: matrix.free_disk == false
|
||||
|
||||
# Rust Log Analyzer can't currently detect the PR number of a GitHub
|
||||
# Actions build on its own, so a hint in the log message is needed to
|
||||
# point it in the right direction.
|
||||
|
|
@ -152,9 +159,6 @@ jobs:
|
|||
- name: show the current environment
|
||||
run: src/ci/scripts/dump-environment.sh
|
||||
|
||||
- name: install rust
|
||||
run: src/ci/scripts/install-rust.sh
|
||||
|
||||
- name: install awscli
|
||||
run: src/ci/scripts/install-awscli.sh
|
||||
|
||||
|
|
|
|||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -25,7 +25,7 @@
|
|||
[submodule "src/llvm-project"]
|
||||
path = src/llvm-project
|
||||
url = https://github.com/rust-lang/llvm-project.git
|
||||
branch = rustc/20.1-2025-07-13
|
||||
branch = rustc/21.1-2025-08-01
|
||||
shallow = true
|
||||
[submodule "src/doc/embedded-book"]
|
||||
path = src/doc/embedded-book
|
||||
|
|
|
|||
1
.mailmap
1
.mailmap
|
|
@ -597,6 +597,7 @@ Sam Radhakrishnan <sk09idm@gmail.com>
|
|||
Samuel Tardieu <sam@rfc1149.net>
|
||||
Santiago Pastorino <spastorino@gmail.com>
|
||||
Santiago Pastorino <spastorino@gmail.com> <santiago@wyeworks.com>
|
||||
Sasha Pourcelot <sasha.pourcelot@protonmail.com> Sasha <sasha.pourcelot@protonmail.com>
|
||||
Scott McMurray <scottmcm@users.noreply.github.com>
|
||||
Scott McMurray <scottmcm@users.noreply.github.com> <smcmurray@acm.org>
|
||||
Scott Olson <scott@solson.me> Scott Olson <scott@scott-olson.org>
|
||||
|
|
|
|||
290
Cargo.lock
290
Cargo.lock
|
|
@ -466,6 +466,8 @@ version = "1.2.16"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
]
|
||||
|
||||
|
|
@ -516,9 +518,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.41"
|
||||
version = "4.5.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9"
|
||||
checksum = "ed87a9d530bb41a67537289bafcac159cb3ee28460e0a4571123d2a778a6a882"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -536,9 +538,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.41"
|
||||
version = "4.5.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d"
|
||||
checksum = "64f4f3f3c77c94aff3c7e9aac9a2ca1974a5adf392a8bb751e827d6d127ab966"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -566,7 +568,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.90"
|
||||
version = "0.1.91"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"askama",
|
||||
|
|
@ -593,7 +595,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.90"
|
||||
version = "0.1.91"
|
||||
dependencies = [
|
||||
"clippy_utils",
|
||||
"itertools",
|
||||
|
|
@ -616,7 +618,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.90"
|
||||
version = "0.1.91"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
|
@ -647,7 +649,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.90"
|
||||
version = "0.1.91"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itertools",
|
||||
|
|
@ -655,6 +657,26 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cmake"
|
||||
version = "0.1.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"termcolor",
|
||||
"unicode-width 0.2.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collect-license-metadata"
|
||||
version = "0.1.0"
|
||||
|
|
@ -913,6 +935,68 @@ dependencies = [
|
|||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.161"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3523cc02ad831111491dd64b27ad999f1ae189986728e477604e61b81f828df"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-cmd",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"foldhash",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.161"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "212b754247a6f07b10fa626628c157593f0abf640a3dd04cce2760eca970f909"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-cmd"
|
||||
version = "1.0.161"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f426a20413ec2e742520ba6837c9324b55ffac24ead47491a6e29f933c5b135a"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"codespan-reporting",
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.161"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a258b6069020b4e5da6415df94a50ee4f586a6c38b037a180e940a43d06a070d"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.161"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8dec184b52be5008d6eaf7e62fc1802caf1ad1227d11b3b7df2c409c7ffc3f4"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.104",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.11"
|
||||
|
|
@ -967,7 +1051,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.90"
|
||||
version = "0.1.91"
|
||||
|
||||
[[package]]
|
||||
name = "derive-where"
|
||||
|
|
@ -1087,7 +1171,7 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.0",
|
||||
"redox_users 0.5.2",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
|
|
@ -1373,6 +1457,17 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "genmc-sys"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cmake",
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
"git2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.23"
|
||||
|
|
@ -1427,6 +1522,21 @@ dependencies = [
|
|||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "git2"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
"libgit2-sys",
|
||||
"log",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.2"
|
||||
|
|
@ -1876,16 +1986,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ipc-channel"
|
||||
version = "0.20.0"
|
||||
version = "0.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b1c98b70019c830a1fc39cecfe1f60ff99c4122f0a189697c810c90ec545c14"
|
||||
checksum = "1700f6b8b9f00cdd675f32fbb3a5be882213140dfe045805273221ca266c43f8"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"crossbeam-channel",
|
||||
"fnv",
|
||||
"libc",
|
||||
"mio",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"serde",
|
||||
"tempfile",
|
||||
"uuid",
|
||||
|
|
@ -1984,9 +2094,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jsonpath-rust"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d057f8fd19e20c3f14d3663983397155739b6bc1148dc5cd4c4a1a5b3130eb0"
|
||||
checksum = "633a7320c4bb672863a3782e89b9094ad70285e097ff6832cddd0ec615beadfa"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
|
|
@ -2060,6 +2170,19 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libgit2-sys"
|
||||
version = "0.18.2+1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"libz-sys",
|
||||
"openssl-sys",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.8"
|
||||
|
|
@ -2067,7 +2190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.53.2",
|
||||
"windows-targets 0.53.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2078,9 +2201,9 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
|||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.6"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
|
||||
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
|
|
@ -2099,6 +2222,15 @@ dependencies = [
|
|||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a6f6da007f968f9def0d65a05b187e2960183de70c160204ecfccf0ee330212"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linkchecker"
|
||||
version = "0.1.0"
|
||||
|
|
@ -2308,6 +2440,7 @@ dependencies = [
|
|||
"chrono-tz",
|
||||
"colored 3.0.0",
|
||||
"directories",
|
||||
"genmc-sys",
|
||||
"getrandom 0.3.3",
|
||||
"ipc-channel",
|
||||
"libc",
|
||||
|
|
@ -2315,7 +2448,7 @@ dependencies = [
|
|||
"libloading",
|
||||
"measureme",
|
||||
"nix",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"serde",
|
||||
|
|
@ -2510,9 +2643,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.37.1"
|
||||
version = "0.37.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a"
|
||||
checksum = "b3e3d0a7419f081f4a808147e845310313a39f322d7ae1f996b7f001d6cbed04"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
|
|
@ -2520,7 +2653,7 @@ dependencies = [
|
|||
"indexmap",
|
||||
"memchr",
|
||||
"ruzstd 0.8.1",
|
||||
"wasmparser 0.234.0",
|
||||
"wasmparser 0.236.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2948,9 +3081,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha 0.9.0",
|
||||
"rand_core 0.9.3",
|
||||
|
|
@ -3034,9 +3167,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.13"
|
||||
version = "0.5.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
||||
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
|
@ -3054,9 +3187,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
"libredox",
|
||||
|
|
@ -3146,7 +3279,7 @@ dependencies = [
|
|||
"build_helper",
|
||||
"gimli 0.32.0",
|
||||
"libc",
|
||||
"object 0.37.1",
|
||||
"object 0.37.2",
|
||||
"regex",
|
||||
"serde_json",
|
||||
"similar",
|
||||
|
|
@ -3168,9 +3301,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.25"
|
||||
version = "0.1.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
||||
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
|
|
@ -3231,7 +3364,7 @@ name = "rustc_abi"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rand_xoshiro",
|
||||
"rustc_data_structures",
|
||||
"rustc_hashes",
|
||||
|
|
@ -3284,6 +3417,7 @@ dependencies = [
|
|||
"rustc_data_structures",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"rustc_span",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3293,7 +3427,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3343,20 +3476,6 @@ dependencies = [
|
|||
"thin-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_attr_data_structures"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
"rustc_span",
|
||||
"thin-vec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_attr_parsing"
|
||||
version = "0.0.0"
|
||||
|
|
@ -3364,7 +3483,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -3420,7 +3538,6 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3452,11 +3569,10 @@ dependencies = [
|
|||
"itertools",
|
||||
"libc",
|
||||
"measureme",
|
||||
"object 0.37.1",
|
||||
"object 0.37.2",
|
||||
"rustc-demangle",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_codegen_ssa",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3491,13 +3607,12 @@ dependencies = [
|
|||
"cc",
|
||||
"itertools",
|
||||
"libc",
|
||||
"object 0.37.1",
|
||||
"object 0.37.2",
|
||||
"pathdiff",
|
||||
"regex",
|
||||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3535,7 +3650,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_apfloat",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -3681,7 +3795,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_error_messages",
|
||||
|
|
@ -3711,7 +3824,6 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_ast_passes",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3735,8 +3847,8 @@ dependencies = [
|
|||
name = "rustc_feature"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_hir",
|
||||
"rustc_span",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
@ -3781,7 +3893,7 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_data_structures",
|
||||
"rustc_hashes",
|
||||
"rustc_index",
|
||||
|
|
@ -3802,7 +3914,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3829,7 +3940,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_hir",
|
||||
"rustc_span",
|
||||
]
|
||||
|
|
@ -3841,7 +3951,6 @@ dependencies = [
|
|||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3866,7 +3975,7 @@ dependencies = [
|
|||
name = "rustc_incremental"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -3987,7 +4096,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -4061,7 +4169,6 @@ dependencies = [
|
|||
"odht",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -4097,7 +4204,6 @@ dependencies = [
|
|||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_ast_ir",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_messages",
|
||||
"rustc_errors",
|
||||
|
|
@ -4131,7 +4237,6 @@ dependencies = [
|
|||
"rustc_apfloat",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -4178,7 +4283,6 @@ dependencies = [
|
|||
"rustc_abi",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_const_eval",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -4204,7 +4308,6 @@ version = "0.0.0"
|
|||
dependencies = [
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -4275,7 +4378,6 @@ dependencies = [
|
|||
"rustc_ast",
|
||||
"rustc_ast_lowering",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -4322,7 +4424,6 @@ name = "rustc_privacy"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -4397,7 +4498,6 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
|
|
@ -4419,12 +4519,12 @@ name = "rustc_resolve"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"itertools",
|
||||
"pulldown-cmark",
|
||||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_ast_pretty",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
|
|
@ -4479,7 +4579,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"getopts",
|
||||
"libc",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_data_structures",
|
||||
|
|
@ -4543,7 +4643,7 @@ name = "rustc_target"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"object 0.37.1",
|
||||
"object 0.37.2",
|
||||
"rustc_abi",
|
||||
"rustc_data_structures",
|
||||
"rustc_fs_util",
|
||||
|
|
@ -4564,7 +4664,7 @@ dependencies = [
|
|||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
"libc",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rand_xorshift",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
|
|
@ -4587,7 +4687,6 @@ dependencies = [
|
|||
"itertools",
|
||||
"rustc_abi",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_fluent_macro",
|
||||
|
|
@ -4877,6 +4976,12 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f6280af86e5f559536da57a45ebc84948833b3bee313a7dd25232e09c878a52"
|
||||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.2.0"
|
||||
|
|
@ -4935,9 +5040,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.141"
|
||||
version = "1.0.142"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3"
|
||||
checksum = "030fedb782600dcbd6f02d479bf0d817ac3bb40d644745b769d6a96bc3afc5a7"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
|
@ -5270,7 +5375,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"indicatif",
|
||||
"num",
|
||||
"rand 0.9.1",
|
||||
"rand 0.9.2",
|
||||
"rand_chacha 0.9.0",
|
||||
"rayon",
|
||||
]
|
||||
|
|
@ -5995,12 +6100,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.235.0"
|
||||
version = "0.236.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a"
|
||||
checksum = "3108979166ab0d3c7262d2e16a2190ffe784b2a5beb963edef154b5e8e07680b"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.235.0",
|
||||
"wasmparser 0.236.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6040,9 +6145,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.235.0"
|
||||
version = "0.236.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917"
|
||||
checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
|
|
@ -6051,22 +6156,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "235.0.0"
|
||||
version = "236.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1eda4293f626c99021bb3a6fbe4fbbe90c0e31a5ace89b5f620af8925de72e13"
|
||||
checksum = "11d6b6faeab519ba6fbf9b26add41617ca6f5553f99ebc33d876e591d2f4f3c6"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.1",
|
||||
"wasm-encoder 0.235.0",
|
||||
"wasm-encoder 0.236.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.235.0"
|
||||
version = "1.236.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e777e0327115793cb96ab220b98f85327ec3d11f34ec9e8d723264522ef206aa"
|
||||
checksum = "cc31704322400f461f7f31a5f9190d5488aaeafb63ae69ad2b5888d2704dcb08"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
|
@ -6322,7 +6427,7 @@ version = "0.60.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets 0.53.2",
|
||||
"windows-targets 0.53.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6358,10 +6463,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.2"
|
||||
version = "0.53.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
|
||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm 0.53.0",
|
||||
"windows_aarch64_msvc 0.53.0",
|
||||
"windows_i686_gnu 0.53.0",
|
||||
|
|
|
|||
137
RELEASES.md
137
RELEASES.md
|
|
@ -1,3 +1,140 @@
|
|||
Version 1.89.0 (2025-08-07)
|
||||
==========================
|
||||
|
||||
<a id="1.89.0-Language"></a>
|
||||
|
||||
Language
|
||||
--------
|
||||
- [Stabilize explicitly inferred const arguments (`feature(generic_arg_infer)`)](https://github.com/rust-lang/rust/pull/141610)
|
||||
- [Add a warn-by-default `mismatched_lifetime_syntaxes` lint.](https://github.com/rust-lang/rust/pull/138677)
|
||||
This lint detects when the same lifetime is referred to by different syntax categories between function arguments and return values, which can be confusing to read, especially in unsafe code.
|
||||
This lint supersedes the warn-by-default `elided_named_lifetimes` lint.
|
||||
- [Expand `unpredictable_function_pointer_comparisons` to also lint on function pointer comparisons in external macros](https://github.com/rust-lang/rust/pull/134536)
|
||||
- [Make the `dangerous_implicit_autorefs` lint deny-by-default](https://github.com/rust-lang/rust/pull/141661)
|
||||
- [Stabilize the avx512 target features](https://github.com/rust-lang/rust/pull/138940)
|
||||
- [Stabilize `kl` and `widekl` target features for x86](https://github.com/rust-lang/rust/pull/140766)
|
||||
- [Stabilize `sha512`, `sm3` and `sm4` target features for x86](https://github.com/rust-lang/rust/pull/140767)
|
||||
- [Stabilize LoongArch target features `f`, `d`, `frecipe`, `lasx`, `lbt`, `lsx`, and `lvz`](https://github.com/rust-lang/rust/pull/135015)
|
||||
- [Remove `i128` and `u128` from `improper_ctypes_definitions`](https://github.com/rust-lang/rust/pull/137306)
|
||||
- [Stabilize `repr128` (`#[repr(u128)]`, `#[repr(i128)]`)](https://github.com/rust-lang/rust/pull/138285)
|
||||
- [Allow `#![doc(test(attr(..)))]` everywhere](https://github.com/rust-lang/rust/pull/140560)
|
||||
- [Extend temporary lifetime extension to also go through tuple struct and tuple variant constructors](https://github.com/rust-lang/rust/pull/140593)
|
||||
- [`extern "C"` functions on the `wasm32-unknown-unknown` target now have a standards compliant ABI](https://blog.rust-lang.org/2025/04/04/c-abi-changes-for-wasm32-unknown-unknown/)
|
||||
|
||||
<a id="1.89.0-Compiler"></a>
|
||||
|
||||
Compiler
|
||||
--------
|
||||
- [Default to non-leaf frame pointers on aarch64-linux](https://github.com/rust-lang/rust/pull/140832)
|
||||
- [Enable non-leaf frame pointers for Arm64EC Windows](https://github.com/rust-lang/rust/pull/140862)
|
||||
- [Set Apple frame pointers by architecture](https://github.com/rust-lang/rust/pull/141797)
|
||||
|
||||
|
||||
<a id="1.89.0-Platform-Support"></a>
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
- [Add new Tier-3 targets `loongarch32-unknown-none` and `loongarch32-unknown-none-softfloat`](https://github.com/rust-lang/rust/pull/142053)
|
||||
- [`x86_64-apple-darwin` is in the process of being demoted to Tier 2 with host tools](https://github.com/rust-lang/rfcs/pull/3841)
|
||||
|
||||
Refer to Rust's [platform support page][platform-support-doc]
|
||||
for more information on Rust's tiered platform support.
|
||||
|
||||
[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
|
||||
|
||||
<a id="1.89.0-Libraries"></a>
|
||||
|
||||
Libraries
|
||||
---------
|
||||
- [Specify the base path for `file!`](https://github.com/rust-lang/rust/pull/134442)
|
||||
- [Allow storing `format_args!()` in a variable](https://github.com/rust-lang/rust/pull/140748)
|
||||
- [Add `#[must_use]` to `[T; N]::map`](https://github.com/rust-lang/rust/pull/140957)
|
||||
- [Implement `DerefMut` for `Lazy{Cell,Lock}`](https://github.com/rust-lang/rust/pull/129334)
|
||||
- [Implement `Default` for `array::IntoIter`](https://github.com/rust-lang/rust/pull/141574)
|
||||
- [Implement `Clone` for `slice::ChunkBy`](https://github.com/rust-lang/rust/pull/138016)
|
||||
- [Implement `io::Seek` for `io::Take`](https://github.com/rust-lang/rust/pull/138023)
|
||||
|
||||
|
||||
<a id="1.89.0-Stabilized-APIs"></a>
|
||||
|
||||
Stabilized APIs
|
||||
---------------
|
||||
|
||||
- [`NonZero<char>`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html)
|
||||
- Many intrinsics for x86, not enumerated here
|
||||
- [AVX512 intrinsics](https://github.com/rust-lang/rust/issues/111137)
|
||||
- [`SHA512`, `SM3` and `SM4` intrinsics](https://github.com/rust-lang/rust/issues/126624)
|
||||
- [`File::lock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.lock)
|
||||
- [`File::lock_shared`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.lock_shared)
|
||||
- [`File::try_lock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_lock)
|
||||
- [`File::try_lock_shared`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_lock_shared)
|
||||
- [`File::unlock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.unlock)
|
||||
- [`NonNull::from_ref`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.from_ref)
|
||||
- [`NonNull::from_mut`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.from_mut)
|
||||
- [`NonNull::without_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.without_provenance)
|
||||
- [`NonNull::with_exposed_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.with_exposed_provenance)
|
||||
- [`NonNull::expose_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.expose_provenance)
|
||||
- [`OsString::leak`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.leak)
|
||||
- [`PathBuf::leak`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.leak)
|
||||
- [`Result::flatten`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.flatten)
|
||||
- [`std::os::linux::net::TcpStreamExt::quickack`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.TcpStreamExt.html#tymethod.quickack)
|
||||
- [`std::os::linux::net::TcpStreamExt::set_quickack`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.TcpStreamExt.html#tymethod.set_quickack)
|
||||
|
||||
These previously stable APIs are now stable in const contexts:
|
||||
|
||||
- [`<[T; N]>::as_mut_slice`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.as_mut_slice)
|
||||
- [`<[u8]>::eq_ignore_ascii_case`](https://doc.rust-lang.org/stable/std/primitive.slice.html#impl-%5Bu8%5D/method.eq_ignore_ascii_case)
|
||||
- [`str::eq_ignore_ascii_case`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-str/method.eq_ignore_ascii_case)
|
||||
|
||||
|
||||
<a id="1.89.0-Cargo"></a>
|
||||
|
||||
Cargo
|
||||
-----
|
||||
- [`cargo fix` and `cargo clippy --fix` now default to the same Cargo target selection as other build commands.](https://github.com/rust-lang/cargo/pull/15192/) Previously it would apply to all targets (like binaries, examples, tests, etc.). The `--edition` flag still applies to all targets.
|
||||
- [Stabilize doctest-xcompile.](https://github.com/rust-lang/cargo/pull/15462/) Doctests are now tested when cross-compiling. Just like other tests, it will use the [`runner` setting](https://doc.rust-lang.org/cargo/reference/config.html#targettriplerunner) to run the tests. If you need to disable tests for a target, you can use the [ignore doctest attribute](https://doc.rust-lang.org/rustdoc/write-documentation/documentation-tests.html#ignoring-targets) to specify the targets to ignore.
|
||||
|
||||
|
||||
<a id="1.89.0-Rustdoc"></a>
|
||||
|
||||
Rustdoc
|
||||
-----
|
||||
- [On mobile, make the sidebar full width and linewrap](https://github.com/rust-lang/rust/pull/139831). This makes long section and item names much easier to deal with on mobile.
|
||||
|
||||
|
||||
<a id="1.89.0-Compatibility-Notes"></a>
|
||||
|
||||
Compatibility Notes
|
||||
-------------------
|
||||
- [Make `missing_fragment_specifier` an unconditional error](https://github.com/rust-lang/rust/pull/128425)
|
||||
- [Enabling the `neon` target feature on `aarch64-unknown-none-softfloat` causes a warning](https://github.com/rust-lang/rust/pull/135160) because mixing code with and without that target feature is not properly supported by LLVM
|
||||
- [Sized Hierarchy: Part I](https://github.com/rust-lang/rust/pull/137944)
|
||||
- Introduces a small breaking change affecting `?Sized` bounds on impls on recursive types which contain associated type projections. It is not expected to affect any existing published crates. Can be fixed by refactoring the involved types or opting into the `sized_hierarchy` unstable feature. See the [FCP report](https://github.com/rust-lang/rust/pull/137944#issuecomment-2912207485) for a code example.
|
||||
- The warn-by-default `elided_named_lifetimes` lint is [superseded by the warn-by-default `mismatched_lifetime_syntaxes` lint.](https://github.com/rust-lang/rust/pull/138677)
|
||||
- [Error on recursive opaque types earlier in the type checker](https://github.com/rust-lang/rust/pull/139419)
|
||||
- [Type inference side effects from requiring element types of array repeat expressions are `Copy` are now only available at the end of type checking](https://github.com/rust-lang/rust/pull/139635)
|
||||
- [The deprecated accidentally-stable `std::intrinsics::{copy,copy_nonoverlapping,write_bytes}` are now proper intrinsics](https://github.com/rust-lang/rust/pull/139916). There are no debug assertions guarding against UB, and they cannot be coerced to function pointers.
|
||||
- [Remove long-deprecated `std::intrinsics::drop_in_place`](https://github.com/rust-lang/rust/pull/140151)
|
||||
- [Make well-formedness predicates no longer coinductive](https://github.com/rust-lang/rust/pull/140208)
|
||||
- [Remove hack when checking impl method compatibility](https://github.com/rust-lang/rust/pull/140557)
|
||||
- [Remove unnecessary type inference due to built-in trait object impls](https://github.com/rust-lang/rust/pull/141352)
|
||||
- [Lint against "stdcall", "fastcall", and "cdecl" on non-x86-32 targets](https://github.com/rust-lang/rust/pull/141435)
|
||||
- [Future incompatibility warnings relating to the never type (`!`) are now reported in dependencies](https://github.com/rust-lang/rust/pull/141937)
|
||||
- [Ensure `std::ptr::copy_*` intrinsics also perform the static self-init checks](https://github.com/rust-lang/rust/pull/142575)
|
||||
- [`extern "C"` functions on the `wasm32-unknown-unknown` target now have a standards compliant ABI](https://blog.rust-lang.org/2025/04/04/c-abi-changes-for-wasm32-unknown-unknown/)
|
||||
|
||||
<a id="1.89.0-Internal-Changes"></a>
|
||||
|
||||
Internal Changes
|
||||
----------------
|
||||
|
||||
These changes do not affect any public interfaces of Rust, but they represent
|
||||
significant improvements to the performance or internals of rustc and related
|
||||
tools.
|
||||
|
||||
- [Correctly un-remap compiler sources paths with the `rustc-dev` component](https://github.com/rust-lang/rust/pull/142377)
|
||||
|
||||
|
||||
Version 1.88.0 (2025-06-26)
|
||||
==========================
|
||||
|
||||
|
|
|
|||
|
|
@ -465,6 +465,11 @@
|
|||
# What custom diff tool to use for displaying compiletest tests.
|
||||
#build.compiletest-diff-tool = <none>
|
||||
|
||||
# Whether to allow `compiletest` self-tests and `compiletest`-managed test
|
||||
# suites to be run against the stage 0 rustc. This is only intended to be used
|
||||
# when the stage 0 compiler is actually built from in-tree sources.
|
||||
#build.compiletest-allow-stage0 = false
|
||||
|
||||
# Whether to use the precompiled stage0 libtest with compiletest.
|
||||
#build.compiletest-use-stage0-libtest = true
|
||||
|
||||
|
|
@ -475,6 +480,9 @@
|
|||
# Note that if any value is manually given to bootstrap such as
|
||||
# `./x test tidy --extra-checks=js`, this value is ignored.
|
||||
# Use `--extra-checks=''` to temporarily disable all extra checks.
|
||||
#
|
||||
# Automatically enabled in the "tools" profile.
|
||||
# Set to the empty string to force disable (recommeded for hdd systems).
|
||||
#build.tidy-extra-checks = ""
|
||||
|
||||
# Indicates whether ccache is used when building certain artifacts (e.g. LLVM).
|
||||
|
|
@ -732,11 +740,19 @@
|
|||
# result (broken, compiling, testing) into this JSON file.
|
||||
#rust.save-toolstates = <none> (path)
|
||||
|
||||
# This is an array of the codegen backends that will be compiled for the rustc
|
||||
# that's being compiled. The default is to only build the LLVM codegen backend,
|
||||
# and currently the only standard options supported are `"llvm"`, `"cranelift"`
|
||||
# and `"gcc"`. The first backend in this list will be used as default by rustc
|
||||
# when no explicit backend is specified.
|
||||
# This array serves three distinct purposes:
|
||||
# - Backends in this list will be automatically compiled and included in the sysroot of each
|
||||
# rustc compiled by bootstrap.
|
||||
# - The first backend in this list will be configured as the **default codegen backend** by each
|
||||
# rustc compiled by bootstrap. In other words, if the first backend is e.g. cranelift, then when
|
||||
# we build a stage 1 rustc, it will by default compile Rust programs using the Cranelift backend.
|
||||
# This also means that stage 2 rustc would get built by the Cranelift backend.
|
||||
# - Running `x dist` (without additional arguments, or with `--include-default-paths`) will produce
|
||||
# a dist component/tarball for the Cranelift backend if it is included in this array.
|
||||
#
|
||||
# Note that the LLVM codegen backend is special and will always be built and distributed.
|
||||
#
|
||||
# Currently, the only standard options supported here are `"llvm"`, `"cranelift"` and `"gcc"`.
|
||||
#rust.codegen-backends = ["llvm"]
|
||||
|
||||
# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::collections::BTreeSet;
|
||||
use std::fmt::{self, Write};
|
||||
use std::ops::{Bound, Deref};
|
||||
use std::{cmp, iter};
|
||||
|
|
@ -5,7 +6,7 @@ use std::{cmp, iter};
|
|||
use rustc_hashes::Hash64;
|
||||
use rustc_index::Idx;
|
||||
use rustc_index::bit_set::BitMatrix;
|
||||
use tracing::debug;
|
||||
use tracing::{debug, trace};
|
||||
|
||||
use crate::{
|
||||
AbiAlign, Align, BackendRepr, FieldsShape, HasDataLayout, IndexSlice, IndexVec, Integer,
|
||||
|
|
@ -766,30 +767,63 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
|
|||
|
||||
let niche_filling_layout = calculate_niche_filling_layout();
|
||||
|
||||
let (mut min, mut max) = (i128::MAX, i128::MIN);
|
||||
let discr_type = repr.discr_type();
|
||||
let bits = Integer::from_attr(dl, discr_type).size().bits();
|
||||
for (i, mut val) in discriminants {
|
||||
if !repr.c() && variants[i].iter().any(|f| f.is_uninhabited()) {
|
||||
continue;
|
||||
}
|
||||
if discr_type.is_signed() {
|
||||
// sign extend the raw representation to be an i128
|
||||
val = (val << (128 - bits)) >> (128 - bits);
|
||||
}
|
||||
if val < min {
|
||||
min = val;
|
||||
}
|
||||
if val > max {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
// We might have no inhabited variants, so pretend there's at least one.
|
||||
if (min, max) == (i128::MAX, i128::MIN) {
|
||||
min = 0;
|
||||
max = 0;
|
||||
}
|
||||
assert!(min <= max, "discriminant range is {min}...{max}");
|
||||
let discr_int = Integer::from_attr(dl, discr_type);
|
||||
// Because we can only represent one range of valid values, we'll look for the
|
||||
// largest range of invalid values and pick everything else as the range of valid
|
||||
// values.
|
||||
|
||||
// First we need to sort the possible discriminant values so that we can look for the largest gap:
|
||||
let valid_discriminants: BTreeSet<i128> = discriminants
|
||||
.filter(|&(i, _)| repr.c() || variants[i].iter().all(|f| !f.is_uninhabited()))
|
||||
.map(|(_, val)| {
|
||||
if discr_type.is_signed() {
|
||||
// sign extend the raw representation to be an i128
|
||||
// FIXME: do this at the discriminant iterator creation sites
|
||||
discr_int.size().sign_extend(val as u128)
|
||||
} else {
|
||||
val
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
trace!(?valid_discriminants);
|
||||
let discriminants = valid_discriminants.iter().copied();
|
||||
//let next_discriminants = discriminants.clone().cycle().skip(1);
|
||||
let next_discriminants =
|
||||
discriminants.clone().chain(valid_discriminants.first().copied()).skip(1);
|
||||
// Iterate over pairs of each discriminant together with the next one.
|
||||
// Since they were sorted, we can now compute the niche sizes and pick the largest.
|
||||
let discriminants = discriminants.zip(next_discriminants);
|
||||
let largest_niche = discriminants.max_by_key(|&(start, end)| {
|
||||
trace!(?start, ?end);
|
||||
// If this is a wraparound range, the niche size is `MAX - abs(diff)`, as the diff between
|
||||
// the two end points is actually the size of the valid discriminants.
|
||||
let dist = if start > end {
|
||||
// Overflow can happen for 128 bit discriminants if `end` is negative.
|
||||
// But in that case casting to `u128` still gets us the right value,
|
||||
// as the distance must be positive if the lhs of the subtraction is larger than the rhs.
|
||||
let dist = start.wrapping_sub(end);
|
||||
if discr_type.is_signed() {
|
||||
discr_int.signed_max().wrapping_sub(dist) as u128
|
||||
} else {
|
||||
discr_int.size().unsigned_int_max() - dist as u128
|
||||
}
|
||||
} else {
|
||||
// Overflow can happen for 128 bit discriminants if `start` is negative.
|
||||
// But in that case casting to `u128` still gets us the right value,
|
||||
// as the distance must be positive if the lhs of the subtraction is larger than the rhs.
|
||||
end.wrapping_sub(start) as u128
|
||||
};
|
||||
trace!(?dist);
|
||||
dist
|
||||
});
|
||||
trace!(?largest_niche);
|
||||
|
||||
// `max` is the last valid discriminant before the largest niche
|
||||
// `min` is the first valid discriminant after the largest niche
|
||||
let (max, min) = largest_niche
|
||||
// We might have no inhabited variants, so pretend there's at least one.
|
||||
.unwrap_or((0, 0));
|
||||
let (min_ity, signed) = discr_range_of_repr(min, max); //Integer::repr_discr(tcx, ty, &repr, min, max);
|
||||
|
||||
let mut align = dl.aggregate_align;
|
||||
|
|
|
|||
|
|
@ -1205,6 +1205,19 @@ impl Integer {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns the smallest signed value that can be represented by this Integer.
|
||||
#[inline]
|
||||
pub fn signed_min(self) -> i128 {
|
||||
use Integer::*;
|
||||
match self {
|
||||
I8 => i8::MIN as i128,
|
||||
I16 => i16::MIN as i128,
|
||||
I32 => i32::MIN as i128,
|
||||
I64 => i64::MIN as i128,
|
||||
I128 => i128::MIN,
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds the smallest Integer type which can represent the signed value.
|
||||
#[inline]
|
||||
pub fn fit_signed(x: i128) -> Integer {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,6 @@
|
|||
use std::fmt;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::ptr::P;
|
||||
use crate::tokenstream::LazyAttrTokenStream;
|
||||
use crate::{
|
||||
Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField,
|
||||
|
|
@ -53,7 +52,7 @@ impl_has_node_id!(
|
|||
WherePredicate,
|
||||
);
|
||||
|
||||
impl<T: HasNodeId> HasNodeId for P<T> {
|
||||
impl<T: HasNodeId> HasNodeId for Box<T> {
|
||||
fn node_id(&self) -> NodeId {
|
||||
(**self).node_id()
|
||||
}
|
||||
|
|
@ -119,7 +118,7 @@ impl<T: HasTokens> HasTokens for Option<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: HasTokens> HasTokens for P<T> {
|
||||
impl<T: HasTokens> HasTokens for Box<T> {
|
||||
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
|
||||
(**self).tokens()
|
||||
}
|
||||
|
|
@ -245,7 +244,7 @@ impl_has_attrs!(
|
|||
);
|
||||
impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility);
|
||||
|
||||
impl<T: HasAttrs> HasAttrs for P<T> {
|
||||
impl<T: HasAttrs> HasAttrs for Box<T> {
|
||||
const SUPPORTS_CUSTOM_INNER_ATTRS: bool = T::SUPPORTS_CUSTOM_INNER_ATTRS;
|
||||
fn attrs(&self) -> &[Attribute] {
|
||||
(**self).attrs()
|
||||
|
|
@ -322,8 +321,8 @@ impl<Wrapped, Tag> AstNodeWrapper<Wrapped, Tag> {
|
|||
}
|
||||
|
||||
// FIXME: remove after `stmt_expr_attributes` is stabilized.
|
||||
impl<T, Tag> From<AstNodeWrapper<P<T>, Tag>> for AstNodeWrapper<T, Tag> {
|
||||
fn from(value: AstNodeWrapper<P<T>, Tag>) -> Self {
|
||||
impl<T, Tag> From<AstNodeWrapper<Box<T>, Tag>> for AstNodeWrapper<T, Tag> {
|
||||
fn from(value: AstNodeWrapper<Box<T>, Tag>) -> Self {
|
||||
AstNodeWrapper { wrapped: *value.wrapped, tag: value.tag }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ use crate::ast::{
|
|||
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
|
||||
PathSegment, Safety,
|
||||
};
|
||||
use crate::ptr::P;
|
||||
use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token};
|
||||
use crate::tokenstream::{
|
||||
DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree,
|
||||
|
|
@ -660,7 +659,7 @@ pub fn mk_attr_from_item(
|
|||
span: Span,
|
||||
) -> Attribute {
|
||||
Attribute {
|
||||
kind: AttrKind::Normal(P(NormalAttr { item, tokens })),
|
||||
kind: AttrKind::Normal(Box::new(NormalAttr { item, tokens })),
|
||||
id: g.mk_attr_id(),
|
||||
style,
|
||||
span,
|
||||
|
|
@ -710,7 +709,7 @@ pub fn mk_attr_name_value_str(
|
|||
span: Span,
|
||||
) -> Attribute {
|
||||
let lit = token::Lit::new(token::Str, escape_string_symbol(val), None);
|
||||
let expr = P(Expr {
|
||||
let expr = Box::new(Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::Lit(lit),
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ use std::fmt::{self, Display, Formatter};
|
|||
use std::str::FromStr;
|
||||
|
||||
use crate::expand::{Decodable, Encodable, HashStable_Generic};
|
||||
use crate::ptr::P;
|
||||
use crate::{Ty, TyKind};
|
||||
|
||||
/// Forward and Reverse Mode are well known names for automatic differentiation implementations.
|
||||
|
|
@ -162,7 +161,7 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
|
|||
/// since Duplicated expects a mutable ref/ptr and we would thus end up with a shadow value
|
||||
/// who is an indirect type, which doesn't match the primal scalar type. We can't prevent
|
||||
/// users here from marking scalars as Duplicated, due to type aliases.
|
||||
pub fn valid_ty_for_activity(ty: &P<Ty>, activity: DiffActivity) -> bool {
|
||||
pub fn valid_ty_for_activity(ty: &Box<Ty>, activity: DiffActivity) -> bool {
|
||||
use DiffActivity::*;
|
||||
// It's always allowed to mark something as Const, since we won't compute derivatives wrt. it.
|
||||
// Dual variants also support all types.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ use rustc_macros::{Decodable, Encodable, Walkable};
|
|||
use rustc_span::{Ident, Span, Symbol};
|
||||
|
||||
use crate::Expr;
|
||||
use crate::ptr::P;
|
||||
use crate::token::LitKind;
|
||||
|
||||
// Definitions:
|
||||
|
|
@ -147,7 +146,7 @@ impl FormatArguments {
|
|||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
pub struct FormatArgument {
|
||||
pub kind: FormatArgumentKind,
|
||||
pub expr: P<Expr>,
|
||||
pub expr: Box<Expr>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ pub mod expand;
|
|||
pub mod format;
|
||||
pub mod mut_visit;
|
||||
pub mod node_id;
|
||||
pub mod ptr;
|
||||
pub mod token;
|
||||
pub mod tokenstream;
|
||||
pub mod visit;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ use smallvec::{SmallVec, smallvec};
|
|||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::ast::*;
|
||||
use crate::ptr::P;
|
||||
use crate::tokenstream::*;
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, LifetimeCtxt, VisitorResult, try_visit};
|
||||
|
||||
|
|
@ -41,7 +40,7 @@ pub(crate) trait MutVisitable<V: MutVisitor> {
|
|||
fn visit_mut(&mut self, visitor: &mut V, extra: Self::Extra);
|
||||
}
|
||||
|
||||
impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for P<T>
|
||||
impl<V: MutVisitor, T: ?Sized> MutVisitable<V> for Box<T>
|
||||
where
|
||||
T: MutVisitable<V>,
|
||||
{
|
||||
|
|
@ -293,15 +292,15 @@ macro_rules! generate_flat_map_visitor_fns {
|
|||
}
|
||||
|
||||
generate_flat_map_visitor_fns! {
|
||||
visit_items, P<Item>, flat_map_item;
|
||||
visit_foreign_items, P<ForeignItem>, flat_map_foreign_item;
|
||||
visit_items, Box<Item>, flat_map_item;
|
||||
visit_foreign_items, Box<ForeignItem>, flat_map_foreign_item;
|
||||
visit_generic_params, GenericParam, flat_map_generic_param;
|
||||
visit_stmts, Stmt, flat_map_stmt;
|
||||
visit_exprs, P<Expr>, filter_map_expr;
|
||||
visit_exprs, Box<Expr>, filter_map_expr;
|
||||
visit_expr_fields, ExprField, flat_map_expr_field;
|
||||
visit_pat_fields, PatField, flat_map_pat_field;
|
||||
visit_variants, Variant, flat_map_variant;
|
||||
visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
|
||||
visit_assoc_items, Box<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
|
||||
visit_where_predicates, WherePredicate, flat_map_where_predicate;
|
||||
visit_params, Param, flat_map_param;
|
||||
visit_field_defs, FieldDef, flat_map_field_def;
|
||||
|
|
@ -333,12 +332,12 @@ generate_walk_flat_map_fns! {
|
|||
walk_flat_map_where_predicate(WherePredicate) => visit_where_predicate;
|
||||
walk_flat_map_field_def(FieldDef) => visit_field_def;
|
||||
walk_flat_map_expr_field(ExprField) => visit_expr_field;
|
||||
walk_flat_map_item(P<Item>) => visit_item;
|
||||
walk_flat_map_foreign_item(P<ForeignItem>) => visit_foreign_item;
|
||||
walk_flat_map_assoc_item(P<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
|
||||
walk_flat_map_item(Box<Item>) => visit_item;
|
||||
walk_flat_map_foreign_item(Box<ForeignItem>) => visit_foreign_item;
|
||||
walk_flat_map_assoc_item(Box<AssocItem>, ctxt: AssocCtxt) => visit_assoc_item;
|
||||
}
|
||||
|
||||
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
|
||||
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: Box<Expr>) -> Option<Box<Expr>> {
|
||||
vis.visit_expr(&mut e);
|
||||
Some(e)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
/// A pointer type that uniquely owns a heap allocation of type T.
|
||||
///
|
||||
/// This used to be its own type, but now it's just a typedef for `Box` and we are planning to
|
||||
/// remove it soon.
|
||||
pub type P<T> = Box<T>;
|
||||
|
||||
/// Construct a `P<T>` from a `T` value.
|
||||
#[allow(non_snake_case)]
|
||||
pub fn P<T>(value: T) -> P<T> {
|
||||
Box::new(value)
|
||||
}
|
||||
|
|
@ -190,15 +190,15 @@ impl fmt::Display for LitKind {
|
|||
LitKind::Int(n, ty) => {
|
||||
write!(f, "{n}")?;
|
||||
match ty {
|
||||
ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name())?,
|
||||
ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name())?,
|
||||
ast::LitIntType::Unsigned(ty) => write!(f, "{}", ty.name_str())?,
|
||||
ast::LitIntType::Signed(ty) => write!(f, "{}", ty.name_str())?,
|
||||
ast::LitIntType::Unsuffixed => {}
|
||||
}
|
||||
}
|
||||
LitKind::Float(symbol, ty) => {
|
||||
write!(f, "{symbol}")?;
|
||||
match ty {
|
||||
ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name())?,
|
||||
ast::LitFloatType::Suffixed(ty) => write!(f, "{}", ty.name_str())?,
|
||||
ast::LitFloatType::Unsuffixed => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ use rustc_span::{Ident, Span, Symbol};
|
|||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::ast::*;
|
||||
use crate::ptr::P;
|
||||
use crate::tokenstream::DelimSpan;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
|
|
@ -82,7 +81,7 @@ pub(crate) trait Visitable<'a, V: Visitor<'a>> {
|
|||
fn visit(&'a self, visitor: &mut V, extra: Self::Extra) -> V::Result;
|
||||
}
|
||||
|
||||
impl<'a, V: Visitor<'a>, T: ?Sized> Visitable<'a, V> for P<T>
|
||||
impl<'a, V: Visitor<'a>, T: ?Sized> Visitable<'a, V> for Box<T>
|
||||
where
|
||||
T: Visitable<'a, V>,
|
||||
{
|
||||
|
|
@ -322,7 +321,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
Fn(FnCtxt, &'a $($mut)? Visibility, &'a $($mut)? Fn),
|
||||
|
||||
/// E.g., `|x, y| body`.
|
||||
Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? P<FnDecl>, &'a $($mut)? P<Expr>),
|
||||
Closure(&'a $($mut)? ClosureBinder, &'a $($mut)? Option<CoroutineKind>, &'a $($mut)? Box<FnDecl>, &'a $($mut)? Box<Expr>),
|
||||
}
|
||||
|
||||
impl<'a> FnKind<'a> {
|
||||
|
|
@ -390,9 +389,9 @@ macro_rules! common_visitor_and_walkers {
|
|||
ThinVec<(NodeId, Path)>,
|
||||
ThinVec<PathSegment>,
|
||||
ThinVec<PreciseCapturingArg>,
|
||||
ThinVec<P<Pat>>,
|
||||
ThinVec<P<Ty>>,
|
||||
ThinVec<P<TyPat>>,
|
||||
ThinVec<Box<Pat>>,
|
||||
ThinVec<Box<Ty>>,
|
||||
ThinVec<Box<TyPat>>,
|
||||
);
|
||||
|
||||
// This macro generates `impl Visitable` and `impl MutVisitable` that forward to `Walkable`
|
||||
|
|
@ -676,11 +675,11 @@ macro_rules! common_visitor_and_walkers {
|
|||
// Do nothing.
|
||||
}
|
||||
|
||||
fn flat_map_foreign_item(&mut self, ni: P<ForeignItem>) -> SmallVec<[P<ForeignItem>; 1]> {
|
||||
fn flat_map_foreign_item(&mut self, ni: Box<ForeignItem>) -> SmallVec<[Box<ForeignItem>; 1]> {
|
||||
walk_flat_map_foreign_item(self, ni)
|
||||
}
|
||||
|
||||
fn flat_map_item(&mut self, i: P<Item>) -> SmallVec<[P<Item>; 1]> {
|
||||
fn flat_map_item(&mut self, i: Box<Item>) -> SmallVec<[Box<Item>; 1]> {
|
||||
walk_flat_map_item(self, i)
|
||||
}
|
||||
|
||||
|
|
@ -690,9 +689,9 @@ macro_rules! common_visitor_and_walkers {
|
|||
|
||||
fn flat_map_assoc_item(
|
||||
&mut self,
|
||||
i: P<AssocItem>,
|
||||
i: Box<AssocItem>,
|
||||
ctxt: AssocCtxt,
|
||||
) -> SmallVec<[P<AssocItem>; 1]> {
|
||||
) -> SmallVec<[Box<AssocItem>; 1]> {
|
||||
walk_flat_map_assoc_item(self, i, ctxt)
|
||||
}
|
||||
|
||||
|
|
@ -704,7 +703,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
walk_flat_map_arm(self, arm)
|
||||
}
|
||||
|
||||
fn filter_map_expr(&mut self, e: P<Expr>) -> Option<P<Expr>> {
|
||||
fn filter_map_expr(&mut self, e: Box<Expr>) -> Option<Box<Expr>> {
|
||||
walk_filter_map_expr(self, e)
|
||||
}
|
||||
|
||||
|
|
@ -1144,15 +1143,15 @@ macro_rules! generate_list_visit_fns {
|
|||
}
|
||||
|
||||
generate_list_visit_fns! {
|
||||
visit_items, P<Item>, visit_item;
|
||||
visit_foreign_items, P<ForeignItem>, visit_foreign_item;
|
||||
visit_items, Box<Item>, visit_item;
|
||||
visit_foreign_items, Box<ForeignItem>, visit_foreign_item;
|
||||
visit_generic_params, GenericParam, visit_generic_param;
|
||||
visit_stmts, Stmt, visit_stmt;
|
||||
visit_exprs, P<Expr>, visit_expr;
|
||||
visit_exprs, Box<Expr>, visit_expr;
|
||||
visit_expr_fields, ExprField, visit_expr_field;
|
||||
visit_pat_fields, PatField, visit_pat_field;
|
||||
visit_variants, Variant, visit_variant;
|
||||
visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
|
||||
visit_assoc_items, Box<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
|
||||
visit_where_predicates, WherePredicate, visit_where_predicate;
|
||||
visit_params, Param, visit_param;
|
||||
visit_field_defs, FieldDef, visit_field_def;
|
||||
|
|
|
|||
|
|
@ -8,12 +8,16 @@ edition = "2024"
|
|||
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
|
||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
||||
rustc_serialize = { path = "../rustc_serialize", optional = true }
|
||||
rustc_span = { path = "../rustc_span", optional = true }
|
||||
# tidy-alphabetical-end
|
||||
|
||||
[features]
|
||||
# tidy-alphabetical-start
|
||||
default = ["nightly"]
|
||||
nightly = [
|
||||
"dep:rustc_serialize",
|
||||
"dep:rustc_data_structures",
|
||||
"dep:rustc_macros",
|
||||
"dep:rustc_serialize",
|
||||
"dep:rustc_span",
|
||||
]
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -11,11 +11,221 @@
|
|||
#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
|
||||
#[cfg(feature = "nightly")]
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
pub mod visit;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
pub enum IntTy {
|
||||
Isize,
|
||||
I8,
|
||||
I16,
|
||||
I32,
|
||||
I64,
|
||||
I128,
|
||||
}
|
||||
|
||||
impl IntTy {
|
||||
pub fn name_str(&self) -> &'static str {
|
||||
match *self {
|
||||
IntTy::Isize => "isize",
|
||||
IntTy::I8 => "i8",
|
||||
IntTy::I16 => "i16",
|
||||
IntTy::I32 => "i32",
|
||||
IntTy::I64 => "i64",
|
||||
IntTy::I128 => "i128",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub fn name(self) -> Symbol {
|
||||
match self {
|
||||
IntTy::Isize => sym::isize,
|
||||
IntTy::I8 => sym::i8,
|
||||
IntTy::I16 => sym::i16,
|
||||
IntTy::I32 => sym::i32,
|
||||
IntTy::I64 => sym::i64,
|
||||
IntTy::I128 => sym::i128,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bit_width(&self) -> Option<u64> {
|
||||
Some(match *self {
|
||||
IntTy::Isize => return None,
|
||||
IntTy::I8 => 8,
|
||||
IntTy::I16 => 16,
|
||||
IntTy::I32 => 32,
|
||||
IntTy::I64 => 64,
|
||||
IntTy::I128 => 128,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn normalize(&self, target_width: u32) -> Self {
|
||||
match self {
|
||||
IntTy::Isize => match target_width {
|
||||
16 => IntTy::I16,
|
||||
32 => IntTy::I32,
|
||||
64 => IntTy::I64,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => *self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_unsigned(self) -> UintTy {
|
||||
match self {
|
||||
IntTy::Isize => UintTy::Usize,
|
||||
IntTy::I8 => UintTy::U8,
|
||||
IntTy::I16 => UintTy::U16,
|
||||
IntTy::I32 => UintTy::U32,
|
||||
IntTy::I64 => UintTy::U64,
|
||||
IntTy::I128 => UintTy::U128,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for IntTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.name_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
pub enum UintTy {
|
||||
Usize,
|
||||
U8,
|
||||
U16,
|
||||
U32,
|
||||
U64,
|
||||
U128,
|
||||
}
|
||||
|
||||
impl UintTy {
|
||||
pub fn name_str(&self) -> &'static str {
|
||||
match *self {
|
||||
UintTy::Usize => "usize",
|
||||
UintTy::U8 => "u8",
|
||||
UintTy::U16 => "u16",
|
||||
UintTy::U32 => "u32",
|
||||
UintTy::U64 => "u64",
|
||||
UintTy::U128 => "u128",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub fn name(self) -> Symbol {
|
||||
match self {
|
||||
UintTy::Usize => sym::usize,
|
||||
UintTy::U8 => sym::u8,
|
||||
UintTy::U16 => sym::u16,
|
||||
UintTy::U32 => sym::u32,
|
||||
UintTy::U64 => sym::u64,
|
||||
UintTy::U128 => sym::u128,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bit_width(&self) -> Option<u64> {
|
||||
Some(match *self {
|
||||
UintTy::Usize => return None,
|
||||
UintTy::U8 => 8,
|
||||
UintTy::U16 => 16,
|
||||
UintTy::U32 => 32,
|
||||
UintTy::U64 => 64,
|
||||
UintTy::U128 => 128,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn normalize(&self, target_width: u32) -> Self {
|
||||
match self {
|
||||
UintTy::Usize => match target_width {
|
||||
16 => UintTy::U16,
|
||||
32 => UintTy::U32,
|
||||
64 => UintTy::U64,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => *self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_signed(self) -> IntTy {
|
||||
match self {
|
||||
UintTy::Usize => IntTy::Isize,
|
||||
UintTy::U8 => IntTy::I8,
|
||||
UintTy::U16 => IntTy::I16,
|
||||
UintTy::U32 => IntTy::I32,
|
||||
UintTy::U64 => IntTy::I64,
|
||||
UintTy::U128 => IntTy::I128,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for UintTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.name_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(
|
||||
feature = "nightly",
|
||||
derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext)
|
||||
)]
|
||||
pub enum FloatTy {
|
||||
F16,
|
||||
F32,
|
||||
F64,
|
||||
F128,
|
||||
}
|
||||
|
||||
impl FloatTy {
|
||||
pub fn name_str(self) -> &'static str {
|
||||
match self {
|
||||
FloatTy::F16 => "f16",
|
||||
FloatTy::F32 => "f32",
|
||||
FloatTy::F64 => "f64",
|
||||
FloatTy::F128 => "f128",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "nightly")]
|
||||
pub fn name(self) -> Symbol {
|
||||
match self {
|
||||
FloatTy::F16 => sym::f16,
|
||||
FloatTy::F32 => sym::f32,
|
||||
FloatTy::F64 => sym::f64,
|
||||
FloatTy::F128 => sym::f128,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bit_width(self) -> u64 {
|
||||
match self {
|
||||
FloatTy::F16 => 16,
|
||||
FloatTy::F32 => 32,
|
||||
FloatTy::F64 => 64,
|
||||
FloatTy::F128 => 128,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FloatTy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.name_str())
|
||||
}
|
||||
}
|
||||
|
||||
/// The movability of a coroutine / closure literal:
|
||||
/// whether a coroutine contains self-references, causing it to be `!Unpin`.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ doctest = false
|
|||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
|
||||
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
| asm::InlineAsmArch::Arm64EC
|
||||
| asm::InlineAsmArch::RiscV32
|
||||
| asm::InlineAsmArch::RiscV64
|
||||
| asm::InlineAsmArch::LoongArch32
|
||||
| asm::InlineAsmArch::LoongArch64
|
||||
| asm::InlineAsmArch::S390x
|
||||
);
|
||||
|
|
|
|||
|
|
@ -95,7 +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 super_ = l.super_.map(|span| self.lower_span(span));
|
||||
let ty = l.ty.as_ref().map(|t| {
|
||||
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
use std::ops::ControlFlow;
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::ptr::P as AstP;
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::expr_to_string;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{HirId, find_attr};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::errors::report_lit_error;
|
||||
|
|
@ -53,7 +52,7 @@ impl<'v> rustc_ast::visit::Visitor<'v> for WillCreateDefIdsVisitor {
|
|||
}
|
||||
|
||||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
fn lower_exprs(&mut self, exprs: &[AstP<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
fn lower_exprs(&mut self, exprs: &[Box<Expr>]) -> &'hir [hir::Expr<'hir>] {
|
||||
self.arena.alloc_from_iter(exprs.iter().map(|x| self.lower_expr_mut(x)))
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
let expr_hir_id = self.lower_node_id(e.id);
|
||||
self.lower_attrs(expr_hir_id, &e.attrs, e.span);
|
||||
let attrs = self.lower_attrs(expr_hir_id, &e.attrs, e.span);
|
||||
|
||||
let kind = match &e.kind {
|
||||
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
|
||||
|
|
@ -232,10 +231,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
*fn_arg_span,
|
||||
),
|
||||
None => self.lower_expr_closure(
|
||||
attrs,
|
||||
binder,
|
||||
*capture_clause,
|
||||
e.id,
|
||||
expr_hir_id,
|
||||
*constness,
|
||||
*movability,
|
||||
fn_decl,
|
||||
|
|
@ -282,9 +281,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::Field(el, ident) => {
|
||||
hir::ExprKind::Field(self.lower_expr(el), self.lower_ident(*ident))
|
||||
}
|
||||
ExprKind::Index(el, er, brackets_span) => {
|
||||
hir::ExprKind::Index(self.lower_expr(el), self.lower_expr(er), *brackets_span)
|
||||
}
|
||||
ExprKind::Index(el, er, brackets_span) => hir::ExprKind::Index(
|
||||
self.lower_expr(el),
|
||||
self.lower_expr(er),
|
||||
self.lower_span(*brackets_span),
|
||||
),
|
||||
ExprKind::Range(e1, e2, lims) => {
|
||||
self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
|
||||
}
|
||||
|
|
@ -334,7 +335,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ExprKind::Struct(se) => {
|
||||
let rest = match &se.rest {
|
||||
StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)),
|
||||
StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp),
|
||||
StructRest::Rest(sp) => {
|
||||
hir::StructTailExpr::DefaultFields(self.lower_span(*sp))
|
||||
}
|
||||
StructRest::None => hir::StructTailExpr::None,
|
||||
};
|
||||
hir::ExprKind::Struct(
|
||||
|
|
@ -451,7 +454,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn lower_legacy_const_generics(
|
||||
&mut self,
|
||||
mut f: Expr,
|
||||
args: ThinVec<AstP<Expr>>,
|
||||
args: ThinVec<Box<Expr>>,
|
||||
legacy_args_idx: &[usize],
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let ExprKind::Path(None, path) = &mut f.kind else {
|
||||
|
|
@ -491,7 +494,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.create_def(node_id, None, DefKind::AnonConst, f.span);
|
||||
let mut visitor = WillCreateDefIdsVisitor {};
|
||||
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
|
||||
AstP(Expr {
|
||||
Box::new(Expr {
|
||||
id: self.next_node_id(),
|
||||
kind: ExprKind::Err(invalid_expr_error(self.tcx, span)),
|
||||
span: f.span,
|
||||
|
|
@ -512,7 +515,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// Add generic args to the last element of the path.
|
||||
let last_segment = path.segments.last_mut().unwrap();
|
||||
assert!(last_segment.args.is_none());
|
||||
last_segment.args = Some(AstP(GenericArgs::AngleBracketed(AngleBracketedArgs {
|
||||
last_segment.args = Some(Box::new(GenericArgs::AngleBracketed(AngleBracketedArgs {
|
||||
span: DUMMY_SP,
|
||||
args: generic_args,
|
||||
})));
|
||||
|
|
@ -678,6 +681,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::Arm { hir_id, pat, guard, body, span }
|
||||
}
|
||||
|
||||
fn lower_capture_clause(&mut self, capture_clause: CaptureBy) -> CaptureBy {
|
||||
match capture_clause {
|
||||
CaptureBy::Ref => CaptureBy::Ref,
|
||||
CaptureBy::Use { use_kw } => CaptureBy::Use { use_kw: self.lower_span(use_kw) },
|
||||
CaptureBy::Value { move_kw } => CaptureBy::Value { move_kw: self.lower_span(move_kw) },
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower/desugar a coroutine construct.
|
||||
///
|
||||
/// In particular, this creates the correct async resume argument and `_task_context`.
|
||||
|
|
@ -769,7 +780,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
hir::ExprKind::Closure(self.arena.alloc(hir::Closure {
|
||||
def_id: closure_def_id,
|
||||
binder: hir::ClosureBinder::Default,
|
||||
capture_clause,
|
||||
capture_clause: self.lower_capture_clause(capture_clause),
|
||||
bound_generic_params: &[],
|
||||
fn_decl,
|
||||
body,
|
||||
|
|
@ -800,7 +811,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.lower_attrs(
|
||||
inner_hir_id,
|
||||
&[Attribute {
|
||||
kind: AttrKind::Normal(ptr::P(NormalAttr::from_ident(Ident::new(
|
||||
kind: AttrKind::Normal(Box::new(NormalAttr::from_ident(Ident::new(
|
||||
sym::track_caller,
|
||||
span,
|
||||
)))),
|
||||
|
|
@ -1035,15 +1046,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
|
||||
hir::ExprKind::Use(self.lower_expr(expr), use_kw_span)
|
||||
hir::ExprKind::Use(self.lower_expr(expr), self.lower_span(use_kw_span))
|
||||
}
|
||||
|
||||
fn lower_expr_closure(
|
||||
&mut self,
|
||||
attrs: &[rustc_hir::Attribute],
|
||||
binder: &ClosureBinder,
|
||||
capture_clause: CaptureBy,
|
||||
closure_id: NodeId,
|
||||
closure_hir_id: hir::HirId,
|
||||
constness: Const,
|
||||
movability: Movability,
|
||||
decl: &FnDecl,
|
||||
|
|
@ -1055,15 +1066,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||
|
||||
let (body_id, closure_kind) = self.with_new_scopes(fn_decl_span, move |this| {
|
||||
let mut coroutine_kind = if this
|
||||
.attrs
|
||||
.get(&closure_hir_id.local_id)
|
||||
.is_some_and(|attrs| attrs.iter().any(|attr| attr.has_name(sym::coroutine)))
|
||||
{
|
||||
Some(hir::CoroutineKind::Coroutine(Movability::Movable))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut coroutine_kind = find_attr!(attrs, AttributeKind::Coroutine(_) => hir::CoroutineKind::Coroutine(Movability::Movable));
|
||||
|
||||
// FIXME(contracts): Support contracts on closures?
|
||||
let body_id = this.lower_fn_body(decl, None, |this| {
|
||||
this.coroutine_kind = coroutine_kind;
|
||||
|
|
@ -1083,7 +1088,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: closure_def_id,
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
capture_clause: self.lower_capture_clause(capture_clause),
|
||||
bound_generic_params,
|
||||
fn_decl,
|
||||
body: body_id,
|
||||
|
|
@ -1197,7 +1202,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let c = self.arena.alloc(hir::Closure {
|
||||
def_id: closure_def_id,
|
||||
binder: binder_clause,
|
||||
capture_clause,
|
||||
capture_clause: self.lower_capture_clause(capture_clause),
|
||||
bound_generic_params,
|
||||
fn_decl,
|
||||
body,
|
||||
|
|
@ -1279,7 +1284,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn extract_tuple_struct_path<'a>(
|
||||
&mut self,
|
||||
expr: &'a Expr,
|
||||
) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> {
|
||||
) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {
|
||||
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||
// Does the path resolve to something disallowed in a tuple struct/variant pattern?
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||
|
|
@ -1301,7 +1306,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn extract_unit_struct_path<'a>(
|
||||
&mut self,
|
||||
expr: &'a Expr,
|
||||
) -> Option<(&'a Option<AstP<QSelf>>, &'a Path)> {
|
||||
) -> Option<(&'a Option<Box<QSelf>>, &'a Path)> {
|
||||
if let ExprKind::Path(qself, path) = &expr.kind {
|
||||
// Does the path resolve to something disallowed in a unit struct/variant pattern?
|
||||
if let Some(partial_res) = self.resolver.get_partial_res(expr.id) {
|
||||
|
|
@ -1472,7 +1477,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
/// Each sub-assignment is recorded in `assignments`.
|
||||
fn destructure_sequence(
|
||||
&mut self,
|
||||
elements: &[AstP<Expr>],
|
||||
elements: &[Box<Expr>],
|
||||
ctx: &str,
|
||||
eq_sign_span: Span,
|
||||
assignments: &mut Vec<hir::Stmt<'hir>>,
|
||||
|
|
@ -2101,7 +2106,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> {
|
||||
let lit = hir::Lit {
|
||||
span: sp,
|
||||
span: self.lower_span(sp),
|
||||
node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)),
|
||||
};
|
||||
self.expr(sp, hir::ExprKind::Lit(lit))
|
||||
|
|
@ -2120,7 +2125,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
|
||||
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
|
||||
let lit = hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) };
|
||||
let lit = hir::Lit {
|
||||
span: self.lower_span(sp),
|
||||
node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
|
||||
};
|
||||
self.expr(sp, hir::ExprKind::Lit(lit))
|
||||
}
|
||||
|
||||
|
|
@ -2206,7 +2214,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
self.arena.alloc(hir::Path {
|
||||
span: self.lower_span(span),
|
||||
res,
|
||||
segments: arena_vec![self; hir::PathSegment::new(ident, hir_id, res)],
|
||||
segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
|
||||
}),
|
||||
));
|
||||
|
||||
|
|
|
|||
|
|
@ -402,6 +402,8 @@ fn expand_format_args<'hir>(
|
|||
fmt: &FormatArgs,
|
||||
allow_const: bool,
|
||||
) -> hir::ExprKind<'hir> {
|
||||
let macsp = ctx.lower_span(macsp);
|
||||
|
||||
let mut incomplete_lit = String::new();
|
||||
let lit_pieces =
|
||||
ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
|
||||
|
|
|
|||
|
|
@ -164,11 +164,11 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
fn visit_item(&mut self, i: &'hir Item<'hir>) {
|
||||
debug_assert_eq!(i.owner_id, self.owner);
|
||||
self.with_parent(i.hir_id(), |this| {
|
||||
if let ItemKind::Struct(_, _, struct_def) = &i.kind {
|
||||
if let ItemKind::Struct(_, _, struct_def) = &i.kind
|
||||
// If this is a tuple or unit-like struct, register the constructor.
|
||||
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
|
||||
this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
|
||||
}
|
||||
&& let Some(ctor_hir_id) = struct_def.ctor_hir_id()
|
||||
{
|
||||
this.insert(i.span, ctor_hir_id, Node::Ctor(struct_def));
|
||||
}
|
||||
intravisit::walk_item(this, i);
|
||||
});
|
||||
|
|
@ -311,7 +311,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
|
|||
);
|
||||
|
||||
self.with_parent(const_arg.hir_id, |this| {
|
||||
intravisit::walk_ambig_const_arg(this, const_arg);
|
||||
intravisit::walk_const_arg(this, const_arg);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::AssocCtxt;
|
||||
use rustc_ast::*;
|
||||
use rustc_attr_data_structures::{AttributeKind, find_attr};
|
||||
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::{DefKind, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
|
||||
use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin};
|
||||
use rustc_hir::{self as hir, HirId, LifetimeSource, PredicateOrigin, find_attr};
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
|
|
@ -102,7 +101,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
impl<'hir> LoweringContext<'_, 'hir> {
|
||||
pub(super) fn lower_mod(
|
||||
&mut self,
|
||||
items: &[P<Item>],
|
||||
items: &[Box<Item>],
|
||||
spans: &ModSpans,
|
||||
) -> &'hir hir::Mod<'hir> {
|
||||
self.arena.alloc(hir::Mod {
|
||||
|
|
@ -462,7 +461,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
ItemKind::MacroDef(ident, MacroDef { body, macro_rules }) => {
|
||||
let ident = self.lower_ident(*ident);
|
||||
let body = P(self.lower_delim_args(body));
|
||||
let body = Box::new(self.lower_delim_args(body));
|
||||
let def_id = self.local_def_id(id);
|
||||
let def_kind = self.tcx.def_kind(def_id);
|
||||
let DefKind::Macro(macro_kind) = def_kind else {
|
||||
|
|
@ -627,6 +626,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
} else {
|
||||
// For non-empty lists we can just drop all the data, the prefix is already
|
||||
// present in HIR as a part of nested imports.
|
||||
let span = self.lower_span(span);
|
||||
self.arena.alloc(hir::UsePath { res: PerNS::default(), segments: &[], span })
|
||||
};
|
||||
hir::ItemKind::Use(path, hir::UseKind::ListStem)
|
||||
|
|
@ -1567,7 +1567,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
attrs: &[hir::Attribute],
|
||||
) -> hir::FnHeader {
|
||||
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
|
||||
hir::IsAsync::Async(span)
|
||||
hir::IsAsync::Async(self.lower_span(span))
|
||||
} else {
|
||||
hir::IsAsync::NotAsync
|
||||
};
|
||||
|
|
@ -1804,7 +1804,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let res = Res::Def(DefKind::TyParam, def_id);
|
||||
let ident = self.lower_ident(ident);
|
||||
let ty_path = self.arena.alloc(hir::Path {
|
||||
span: param_span,
|
||||
span: self.lower_span(param_span),
|
||||
res,
|
||||
segments: self
|
||||
.arena
|
||||
|
|
|
|||
|
|
@ -675,7 +675,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let bodies = SortedMap::from_presorted_elements(bodies);
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) =
|
||||
let rustc_middle::hir::Hashes { opt_hash_including_bodies, attrs_hash, delayed_lints_hash } =
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
|
||||
let num_nodes = self.item_local_id_counter.as_usize();
|
||||
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
|
||||
|
|
@ -1217,7 +1217,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_path_ty(
|
||||
&mut self,
|
||||
t: &Ty,
|
||||
qself: &Option<ptr::P<QSelf>>,
|
||||
qself: &Option<Box<QSelf>>,
|
||||
path: &Path,
|
||||
param_mode: ParamMode,
|
||||
itctx: ImplTraitContext,
|
||||
|
|
@ -2368,7 +2368,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
&mut self,
|
||||
modifiers: TraitBoundModifiers,
|
||||
) -> hir::TraitBoundModifiers {
|
||||
hir::TraitBoundModifiers { constness: modifiers.constness, polarity: modifiers.polarity }
|
||||
let constness = match modifiers.constness {
|
||||
BoundConstness::Never => BoundConstness::Never,
|
||||
BoundConstness::Always(span) => BoundConstness::Always(self.lower_span(span)),
|
||||
BoundConstness::Maybe(span) => BoundConstness::Maybe(self.lower_span(span)),
|
||||
};
|
||||
let polarity = match modifiers.polarity {
|
||||
BoundPolarity::Positive => BoundPolarity::Positive,
|
||||
BoundPolarity::Negative(span) => BoundPolarity::Negative(self.lower_span(span)),
|
||||
BoundPolarity::Maybe(span) => BoundPolarity::Maybe(self.lower_span(span)),
|
||||
};
|
||||
hir::TraitBoundModifiers { constness, polarity }
|
||||
}
|
||||
|
||||
// Helper methods for building HIR.
|
||||
|
|
@ -2414,6 +2424,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
init: Option<&'hir hir::Expr<'hir>>,
|
||||
) -> hir::Stmt<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
let span = self.lower_span(span);
|
||||
let local = hir::LetStmt {
|
||||
super_: Some(span),
|
||||
hir_id,
|
||||
|
|
@ -2421,7 +2432,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
pat,
|
||||
els: None,
|
||||
source: hir::LocalSource::Normal,
|
||||
span: self.lower_span(span),
|
||||
span,
|
||||
ty: None,
|
||||
};
|
||||
self.stmt(span, hir::StmtKind::Let(self.arena.alloc(local)))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::*;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
|
|
@ -154,7 +153,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
|
||||
fn lower_pat_tuple(
|
||||
&mut self,
|
||||
pats: &[P<Pat>],
|
||||
pats: &[Box<Pat>],
|
||||
ctx: &str,
|
||||
) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
|
||||
let mut elems = Vec::with_capacity(pats.len());
|
||||
|
|
@ -209,7 +208,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
/// When encountering `($binding_mode $ident @)? ..` (`slice`),
|
||||
/// this is interpreted as a sub-slice pattern semantically.
|
||||
/// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
|
||||
fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
|
||||
fn lower_pat_slice(&mut self, pats: &[Box<Pat>]) -> hir::PatKind<'hir> {
|
||||
let mut before = Vec::new();
|
||||
let mut after = Vec::new();
|
||||
let mut slice = None;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
pub(crate) fn lower_qpath(
|
||||
&mut self,
|
||||
id: NodeId,
|
||||
qself: &Option<ptr::P<QSelf>>,
|
||||
qself: &Option<Box<QSelf>>,
|
||||
p: &Path,
|
||||
param_mode: ParamMode,
|
||||
allow_return_type_notation: AllowReturnTypeNotation,
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ ast_passes_auto_generic = auto traits cannot have generic parameters
|
|||
|
||||
ast_passes_auto_items = auto traits cannot have associated items
|
||||
.label = {ast_passes_auto_items}
|
||||
.suggestion = remove these associated items
|
||||
.suggestion = remove the associated items
|
||||
|
||||
ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
|
||||
.label = {ast_passes_auto_super_lifetime}
|
||||
|
|
@ -241,6 +241,10 @@ ast_passes_tilde_const_disallowed = `[const]` is not allowed here
|
|||
.trait_assoc_ty = associated types in non-`const` traits cannot have `[const]` trait bounds
|
||||
.trait_impl_assoc_ty = associated types in non-const impls cannot have `[const]` trait bounds
|
||||
.inherent_assoc_ty = inherent associated types cannot have `[const]` trait bounds
|
||||
.struct = structs cannot have `[const]` trait bounds
|
||||
.enum = enums cannot have `[const]` trait bounds
|
||||
.union = unions cannot have `[const]` trait bounds
|
||||
.anon_const = anonymous constants cannot have `[const]` trait bounds
|
||||
.object = trait objects cannot have `[const]` trait bounds
|
||||
.item = this item cannot have `[const]` trait bounds
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ use std::str::FromStr;
|
|||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
||||
use rustc_ast::*;
|
||||
use rustc_ast_pretty::pprust::{self, State};
|
||||
|
|
@ -640,16 +639,16 @@ impl<'a> AstValidator<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
if let Some(header) = fk.header() {
|
||||
if let Const::Yes(const_span) = header.constness {
|
||||
let mut spans = variadic_spans.clone();
|
||||
spans.push(const_span);
|
||||
self.dcx().emit_err(errors::ConstAndCVariadic {
|
||||
spans,
|
||||
const_span,
|
||||
variadic_spans: variadic_spans.clone(),
|
||||
});
|
||||
}
|
||||
if let Some(header) = fk.header()
|
||||
&& let Const::Yes(const_span) = header.constness
|
||||
{
|
||||
let mut spans = variadic_spans.clone();
|
||||
spans.push(const_span);
|
||||
self.dcx().emit_err(errors::ConstAndCVariadic {
|
||||
spans,
|
||||
const_span,
|
||||
variadic_spans: variadic_spans.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
match (fk.ctxt(), fk.header()) {
|
||||
|
|
@ -699,23 +698,27 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
|
||||
fn deny_super_traits(&self, bounds: &GenericBounds, ident: Span) {
|
||||
if let [.., last] = &bounds[..] {
|
||||
let span = ident_span.shrink_to_hi().to(last.span());
|
||||
self.dcx().emit_err(errors::AutoTraitBounds { span, ident: ident_span });
|
||||
let span = bounds.iter().map(|b| b.span()).collect();
|
||||
let removal = ident.shrink_to_hi().to(last.span());
|
||||
self.dcx().emit_err(errors::AutoTraitBounds { span, removal, ident });
|
||||
}
|
||||
}
|
||||
|
||||
fn deny_where_clause(&self, where_clause: &WhereClause, ident_span: Span) {
|
||||
fn deny_where_clause(&self, where_clause: &WhereClause, ident: Span) {
|
||||
if !where_clause.predicates.is_empty() {
|
||||
// FIXME: The current diagnostic is misleading since it only talks about
|
||||
// super trait and lifetime bounds while we should just say “bounds”.
|
||||
self.dcx()
|
||||
.emit_err(errors::AutoTraitBounds { span: where_clause.span, ident: ident_span });
|
||||
self.dcx().emit_err(errors::AutoTraitBounds {
|
||||
span: vec![where_clause.span],
|
||||
removal: where_clause.span,
|
||||
ident,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn deny_items(&self, trait_items: &[P<AssocItem>], ident_span: Span) {
|
||||
fn deny_items(&self, trait_items: &[Box<AssocItem>], ident_span: Span) {
|
||||
if !trait_items.is_empty() {
|
||||
let spans: Vec<_> = trait_items.iter().map(|i| i.kind.ident().unwrap().span).collect();
|
||||
let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
|
||||
|
|
@ -1124,7 +1127,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
);
|
||||
}
|
||||
}
|
||||
visit::walk_item(self, item)
|
||||
self.with_tilde_const(Some(TildeConstReason::Enum { span: item.span }), |this| {
|
||||
visit::walk_item(this, item)
|
||||
});
|
||||
}
|
||||
ItemKind::Trait(box Trait {
|
||||
constness,
|
||||
|
|
@ -1175,26 +1180,32 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
visit::walk_item(self, item)
|
||||
}
|
||||
ItemKind::Struct(ident, generics, vdata) => match vdata {
|
||||
VariantData::Struct { fields, .. } => {
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
self.visit_generics(generics);
|
||||
walk_list!(self, visit_field_def, fields);
|
||||
}
|
||||
_ => visit::walk_item(self, item),
|
||||
},
|
||||
ItemKind::Struct(ident, generics, vdata) => {
|
||||
self.with_tilde_const(Some(TildeConstReason::Struct { span: item.span }), |this| {
|
||||
match vdata {
|
||||
VariantData::Struct { fields, .. } => {
|
||||
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_field_def, fields);
|
||||
}
|
||||
_ => visit::walk_item(this, item),
|
||||
}
|
||||
})
|
||||
}
|
||||
ItemKind::Union(ident, generics, vdata) => {
|
||||
if vdata.fields().is_empty() {
|
||||
self.dcx().emit_err(errors::FieldlessUnion { span: item.span });
|
||||
}
|
||||
match vdata {
|
||||
VariantData::Struct { fields, .. } => {
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
self.visit_generics(generics);
|
||||
walk_list!(self, visit_field_def, fields);
|
||||
self.with_tilde_const(Some(TildeConstReason::Union { span: item.span }), |this| {
|
||||
match vdata {
|
||||
VariantData::Struct { fields, .. } => {
|
||||
this.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_field_def, fields);
|
||||
}
|
||||
_ => visit::walk_item(this, item),
|
||||
}
|
||||
_ => visit::walk_item(self, item),
|
||||
}
|
||||
});
|
||||
}
|
||||
ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
|
||||
self.check_defaultness(item.span, *defaultness);
|
||||
|
|
@ -1623,6 +1634,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, anon_const: &'a AnonConst) {
|
||||
self.with_tilde_const(
|
||||
Some(TildeConstReason::AnonConst { span: anon_const.value.span }),
|
||||
|this| visit::walk_anon_const(this, anon_const),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// When encountering an equality constraint in a `where` clause, emit an error. If the code seems
|
||||
|
|
|
|||
|
|
@ -344,7 +344,7 @@ pub(crate) struct ModuleNonAscii {
|
|||
#[diag(ast_passes_auto_generic, code = E0567)]
|
||||
pub(crate) struct AutoTraitGeneric {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
|
||||
pub span: Span,
|
||||
#[label]
|
||||
pub ident: Span,
|
||||
|
|
@ -354,8 +354,9 @@ pub(crate) struct AutoTraitGeneric {
|
|||
#[diag(ast_passes_auto_super_lifetime, code = E0568)]
|
||||
pub(crate) struct AutoTraitBounds {
|
||||
#[primary_span]
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
pub span: Vec<Span>,
|
||||
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
|
||||
pub removal: Span,
|
||||
#[label]
|
||||
pub ident: Span,
|
||||
}
|
||||
|
|
@ -365,7 +366,7 @@ pub(crate) struct AutoTraitBounds {
|
|||
pub(crate) struct AutoTraitItems {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
#[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
|
||||
pub total: Span,
|
||||
#[label]
|
||||
pub ident: Span,
|
||||
|
|
@ -623,6 +624,26 @@ pub(crate) enum TildeConstReason {
|
|||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_struct)]
|
||||
Struct {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_enum)]
|
||||
Enum {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_union)]
|
||||
Union {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_anon_const)]
|
||||
AnonConst {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
},
|
||||
#[note(ast_passes_object)]
|
||||
TraitObject,
|
||||
#[note(ast_passes_item)]
|
||||
|
|
|
|||
|
|
@ -630,16 +630,11 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
|
|||
.iter()
|
||||
.filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2))
|
||||
{
|
||||
if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) {
|
||||
if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
|
||||
{
|
||||
let spans = vec![f1_span, f2_span];
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures {
|
||||
spans,
|
||||
f1: f1_name,
|
||||
f2: f2_name,
|
||||
});
|
||||
}
|
||||
if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1)
|
||||
&& let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2)
|
||||
{
|
||||
let spans = vec![f1_span, f2_span];
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use std::borrow::Cow;
|
|||
use std::sync::Arc;
|
||||
|
||||
use rustc_ast::attr::AttrIdGenerator;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
|
||||
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
|
||||
use rustc_ast::util::classify;
|
||||
|
|
@ -572,10 +571,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
}
|
||||
|
||||
fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
|
||||
if let Some(cmnts) = self.comments_mut() {
|
||||
if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
|
||||
self.print_comment(cmnt);
|
||||
}
|
||||
if let Some(cmnts) = self.comments_mut()
|
||||
&& let Some(cmnt) = cmnts.trailing_comment(span, next_pos)
|
||||
{
|
||||
self.print_comment(cmnt);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1178,7 +1177,7 @@ impl<'a> State<'a> {
|
|||
self.end(rb);
|
||||
}
|
||||
|
||||
fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<ast::Expr>]) {
|
||||
fn commasep_exprs(&mut self, b: Breaks, exprs: &[Box<ast::Expr>]) {
|
||||
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e, FixupContext::default()), |e| e.span)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use std::fmt::Write;
|
|||
|
||||
use ast::{ForLoopKind, MatchKind};
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
|
||||
|
|
@ -54,7 +53,7 @@ impl<'a> State<'a> {
|
|||
self.print_else(elseopt)
|
||||
}
|
||||
|
||||
fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
|
||||
fn print_call_post(&mut self, args: &[Box<ast::Expr>]) {
|
||||
self.popen();
|
||||
self.commasep_exprs(Inconsistent, args);
|
||||
self.pclose()
|
||||
|
|
@ -111,7 +110,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
|
||||
fn print_expr_vec(&mut self, exprs: &[Box<ast::Expr>]) {
|
||||
let ib = self.ibox(INDENT_UNIT);
|
||||
self.word("[");
|
||||
self.commasep_exprs(Inconsistent, exprs);
|
||||
|
|
@ -149,7 +148,7 @@ impl<'a> State<'a> {
|
|||
|
||||
fn print_expr_struct(
|
||||
&mut self,
|
||||
qself: &Option<P<ast::QSelf>>,
|
||||
qself: &Option<Box<ast::QSelf>>,
|
||||
path: &ast::Path,
|
||||
fields: &[ast::ExprField],
|
||||
rest: &ast::StructRest,
|
||||
|
|
@ -204,7 +203,7 @@ impl<'a> State<'a> {
|
|||
self.word("}");
|
||||
}
|
||||
|
||||
fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
|
||||
fn print_expr_tup(&mut self, exprs: &[Box<ast::Expr>]) {
|
||||
self.popen();
|
||||
self.commasep_exprs(Inconsistent, exprs);
|
||||
if exprs.len() == 1 {
|
||||
|
|
@ -213,7 +212,7 @@ impl<'a> State<'a> {
|
|||
self.pclose()
|
||||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[Box<ast::Expr>], fixup: FixupContext) {
|
||||
// Independent of parenthesization related to precedence, we must
|
||||
// parenthesize `func` if this is a statement context in which without
|
||||
// parentheses, a statement boundary would occur inside `func` or
|
||||
|
|
@ -247,7 +246,7 @@ impl<'a> State<'a> {
|
|||
&mut self,
|
||||
segment: &ast::PathSegment,
|
||||
receiver: &ast::Expr,
|
||||
base_args: &[P<ast::Expr>],
|
||||
base_args: &[Box<ast::Expr>],
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
// The fixup here is different than in `print_expr_call` because
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ use ast::StaticItem;
|
|||
use itertools::{Itertools, Position};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ModKind;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_span::Ident;
|
||||
|
||||
use crate::pp::BoxMarker;
|
||||
|
|
@ -628,10 +627,10 @@ impl<'a> State<'a> {
|
|||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
vis: &ast::Visibility,
|
||||
qself: &Option<P<ast::QSelf>>,
|
||||
qself: &Option<Box<ast::QSelf>>,
|
||||
path: &ast::Path,
|
||||
kind: DelegationKind<'_>,
|
||||
body: &Option<P<ast::Block>>,
|
||||
body: &Option<Box<ast::Block>>,
|
||||
) {
|
||||
let body_cb_ib = body.as_ref().map(|body| (body, self.head("")));
|
||||
self.print_visibility(vis);
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
[package]
|
||||
name = "rustc_attr_data_structures"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
# tidy-alphabetical-start
|
||||
rustc_abi = {path = "../rustc_abi"}
|
||||
rustc_ast = {path = "../rustc_ast"}
|
||||
rustc_ast_pretty = {path = "../rustc_ast_pretty"}
|
||||
rustc_data_structures = {path = "../rustc_data_structures"}
|
||||
rustc_macros = {path = "../rustc_macros"}
|
||||
rustc_serialize = {path = "../rustc_serialize"}
|
||||
rustc_span = {path = "../rustc_span"}
|
||||
thin-vec = "0.2.12"
|
||||
# tidy-alphabetical-end
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub struct AttributeLint<Id> {
|
||||
pub id: Id,
|
||||
pub span: Span,
|
||||
pub kind: AttributeLintKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub enum AttributeLintKind {
|
||||
UnusedDuplicate { this: Span, other: Span, warning: bool },
|
||||
IllFormedAttributeInput { suggestions: Vec<String> },
|
||||
EmptyAttribute { first_span: Span },
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ edition = "2024"
|
|||
rustc_abi = { path = "../rustc_abi" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::{CombineAttributeParser, ConvertFn};
|
||||
|
|
|
|||
15
compiler/rustc_attr_parsing/src/attributes/body.rs
Normal file
15
compiler/rustc_attr_parsing/src/attributes/body.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
//! Attributes that can be found in function body.
|
||||
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use super::{NoArgsAttributeParser, OnDuplicate};
|
||||
use crate::context::Stage;
|
||||
|
||||
pub(crate) struct CoroutineParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for CoroutineParser {
|
||||
const PATH: &[Symbol] = &[sym::coroutine];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const CREATE: fn(rustc_span::Span) -> AttributeKind = |span| AttributeKind::Coroutine(span);
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use rustc_ast::{LitKind, NodeId};
|
||||
use rustc_attr_data_structures::{CfgEntry, RustcVersion};
|
||||
use rustc_feature::{AttributeTemplate, Features, template};
|
||||
use rustc_hir::RustcVersion;
|
||||
use rustc_hir::attrs::CfgEntry;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::ExpectedValues;
|
||||
use rustc_session::lint::BuiltinLintDiag;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_data_structures::RustcVersion;
|
||||
use rustc_feature::{Features, GatedCfg, find_gated_cfg};
|
||||
use rustc_hir::RustcVersion;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::ExpectedValues;
|
||||
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::{AttributeKind, CoverageStatus, OptimizeAttr, UsedBy};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
|
|
@ -78,16 +78,16 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser {
|
|||
return None;
|
||||
};
|
||||
|
||||
let status = match arg.path().word_sym() {
|
||||
Some(sym::off) => CoverageStatus::Off,
|
||||
Some(sym::on) => CoverageStatus::On,
|
||||
let kind = match arg.path().word_sym() {
|
||||
Some(sym::off) => CoverageAttrKind::Off,
|
||||
Some(sym::on) => CoverageAttrKind::On,
|
||||
None | Some(_) => {
|
||||
fail_incorrect_argument(arg.span());
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
Some(AttributeKind::Coverage(cx.attr_span, status))
|
||||
Some(AttributeKind::Coverage(cx.attr_span, kind))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -374,11 +374,3 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
|||
features
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct OmitGdbPrettyPrinterSectionParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for OmitGdbPrettyPrinterSectionParser {
|
||||
const PATH: &[Symbol] = &[sym::omit_gdb_pretty_printer_section];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::OmitGdbPrettyPrinterSection;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::template;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::util::parse_version;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
// note: need to model better how duplicate attr errors work when not using
|
||||
// SingleAttributeParser which is what we have two of here.
|
||||
|
||||
use rustc_attr_data_structures::lints::AttributeLintKind;
|
||||
use rustc_attr_data_structures::{AttributeKind, InlineAttr};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::{AttributeKind, InlineAttr};
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use super::{AcceptContext, AttributeOrder, OnDuplicate};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_attr_data_structures::{AttributeKind, MacroUseArgs};
|
||||
use rustc_errors::DiagArgValue;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::{AttributeKind, MacroUseArgs};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
|
@ -26,6 +26,7 @@ use crate::parser::ArgParser;
|
|||
use crate::session_diagnostics::UnusedMultiple;
|
||||
|
||||
pub(crate) mod allow_unstable;
|
||||
pub(crate) mod body;
|
||||
pub(crate) mod cfg;
|
||||
pub(crate) mod cfg_old;
|
||||
pub(crate) mod codegen_attrs;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_errors::DiagArgValue;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, sym};
|
||||
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_abi::Align;
|
||||
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
|
||||
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::{AttributeKind, IntType, ReprAttr};
|
||||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use std::num::NonZero;
|
||||
|
||||
use rustc_attr_data_structures::{
|
||||
AttributeKind, DefaultBodyStability, PartialConstStability, Stability, StabilityLevel,
|
||||
StableSince, UnstableReason, VERSION_PLACEHOLDER,
|
||||
};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_feature::template;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::{
|
||||
DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, StableSince,
|
||||
UnstableReason, VERSION_PLACEHOLDER,
|
||||
};
|
||||
use rustc_span::{Ident, Span, Symbol, sym};
|
||||
|
||||
use super::util::parse_version;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::lints::AttributeLintKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::AttributeLintKind;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
|
|
@ -44,3 +44,55 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ShouldPanicParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
|
||||
const PATH: &[Symbol] = &[sym::should_panic];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::ShouldPanic {
|
||||
span: cx.attr_span,
|
||||
reason: match args {
|
||||
ArgParser::NoArgs => None,
|
||||
ArgParser::NameValue(name_value) => {
|
||||
let Some(str_value) = name_value.value_as_str() else {
|
||||
cx.expected_string_literal(
|
||||
name_value.value_span,
|
||||
Some(name_value.value_as_lit()),
|
||||
);
|
||||
return None;
|
||||
};
|
||||
Some(str_value)
|
||||
}
|
||||
ArgParser::List(list) => {
|
||||
let Some(single) = list.single() else {
|
||||
cx.expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
let Some(single) = single.meta_item() else {
|
||||
cx.expected_name_value(single.span(), Some(sym::expected));
|
||||
return None;
|
||||
};
|
||||
if !single.path().word_is(sym::expected) {
|
||||
cx.expected_specific_argument_strings(list.span, vec!["expected"]);
|
||||
return None;
|
||||
}
|
||||
let Some(nv) = single.args().name_value() else {
|
||||
cx.expected_name_value(single.span(), Some(sym::expected));
|
||||
return None;
|
||||
};
|
||||
let Some(expected) = nv.value_as_str() else {
|
||||
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
Some(expected)
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use core::mem;
|
||||
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name};
|
||||
use rustc_attr_data_structures::RustcVersion;
|
||||
use rustc_feature::is_builtin_attr_name;
|
||||
use rustc_hir::RustcVersion;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
/// Parse a rustc version number written inside string literal in an attribute,
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ use std::sync::LazyLock;
|
|||
|
||||
use private::Sealed;
|
||||
use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_errors::{DiagCtxtHandle, Diagnostic};
|
||||
use rustc_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
|
@ -16,10 +16,10 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
|||
use crate::attributes::allow_unstable::{
|
||||
AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser,
|
||||
};
|
||||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser,
|
||||
OmitGdbPrettyPrinterSectionParser, OptimizeParser, TargetFeatureParser, TrackCallerParser,
|
||||
UsedParser,
|
||||
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
|
||||
TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
|
|
@ -50,7 +50,7 @@ use crate::attributes::semantics::MayDangleParser;
|
|||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
};
|
||||
use crate::attributes::test_attrs::IgnoreParser;
|
||||
use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
|
||||
use crate::attributes::traits::{
|
||||
AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
|
||||
DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
|
||||
|
|
@ -62,15 +62,23 @@ use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
|
|||
use crate::parser::{ArgParser, MetaItemParser, PathParser};
|
||||
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
|
||||
|
||||
macro_rules! group_type {
|
||||
($stage: ty) => {
|
||||
LazyLock<(
|
||||
BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
|
||||
Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
|
||||
)>
|
||||
};
|
||||
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
|
||||
|
||||
struct GroupTypeInner<S: Stage> {
|
||||
accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
|
||||
finalizers: Vec<FinalizeFn<S>>,
|
||||
}
|
||||
|
||||
struct GroupTypeInnerAccept<S: Stage> {
|
||||
template: AttributeTemplate,
|
||||
accept_fn: AcceptFn<S>,
|
||||
}
|
||||
|
||||
type AcceptFn<S> =
|
||||
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser<'a>) + Send + Sync>;
|
||||
type FinalizeFn<S> =
|
||||
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
|
||||
|
||||
macro_rules! attribute_parsers {
|
||||
(
|
||||
pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
|
|
@ -93,11 +101,11 @@ macro_rules! attribute_parsers {
|
|||
}
|
||||
};
|
||||
(
|
||||
@[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
|
||||
let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
|
||||
let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
|
||||
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
|
||||
let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
|
||||
let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
|
|
@ -105,11 +113,14 @@ macro_rules! attribute_parsers {
|
|||
};
|
||||
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
accept_fn(s, cx, args)
|
||||
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
|
||||
template: *template,
|
||||
accept_fn: Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
})
|
||||
})));
|
||||
});
|
||||
}
|
||||
|
||||
finalizes.push(Box::new(|cx| {
|
||||
|
|
@ -119,7 +130,7 @@ macro_rules! attribute_parsers {
|
|||
}
|
||||
)*
|
||||
|
||||
(accepts, finalizes)
|
||||
GroupTypeInner { accepters:accepts, finalizers:finalizes }
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -163,6 +174,7 @@ attribute_parsers!(
|
|||
Single<RustcLayoutScalarValidRangeEnd>,
|
||||
Single<RustcLayoutScalarValidRangeStart>,
|
||||
Single<RustcObjectLifetimeDefaultParser>,
|
||||
Single<ShouldPanicParser>,
|
||||
Single<SkipDuringMethodDispatchParser>,
|
||||
Single<TransparencyParser>,
|
||||
Single<WithoutArgs<AllowIncoherentImplParser>>,
|
||||
|
|
@ -174,6 +186,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<ConstContinueParser>>,
|
||||
Single<WithoutArgs<ConstStabilityIndirectParser>>,
|
||||
Single<WithoutArgs<ConstTraitParser>>,
|
||||
Single<WithoutArgs<CoroutineParser>>,
|
||||
Single<WithoutArgs<DenyExplicitImplParser>>,
|
||||
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
|
||||
Single<WithoutArgs<ExportStableParser>>,
|
||||
|
|
@ -187,7 +200,6 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<NoImplicitPreludeParser>>,
|
||||
Single<WithoutArgs<NoMangleParser>>,
|
||||
Single<WithoutArgs<NonExhaustiveParser>>,
|
||||
Single<WithoutArgs<OmitGdbPrettyPrinterSectionParser>>,
|
||||
Single<WithoutArgs<ParenSugarParser>>,
|
||||
Single<WithoutArgs<PassByValueParser>>,
|
||||
Single<WithoutArgs<PointeeParser>>,
|
||||
|
|
@ -213,24 +225,24 @@ mod private {
|
|||
#[allow(private_interfaces)]
|
||||
pub trait Stage: Sized + 'static + Sealed {
|
||||
type Id: Copy;
|
||||
const SHOULD_EMIT_LINTS: bool;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self);
|
||||
fn parsers() -> &'static GroupType<Self>;
|
||||
|
||||
fn emit_err<'sess>(
|
||||
&self,
|
||||
sess: &'sess Session,
|
||||
diag: impl for<'x> Diagnostic<'x>,
|
||||
) -> ErrorGuaranteed;
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit;
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
impl Stage for Early {
|
||||
type Id = NodeId;
|
||||
const SHOULD_EMIT_LINTS: bool = false;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
fn parsers() -> &'static GroupType<Self> {
|
||||
&early::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(
|
||||
|
|
@ -244,15 +256,18 @@ impl Stage for Early {
|
|||
sess.dcx().create_err(diag).delay_as_bug()
|
||||
}
|
||||
}
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit {
|
||||
self.emit_errors
|
||||
}
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
impl Stage for Late {
|
||||
type Id = HirId;
|
||||
const SHOULD_EMIT_LINTS: bool = true;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
fn parsers() -> &'static GroupType<Self> {
|
||||
&late::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(
|
||||
|
|
@ -262,6 +277,10 @@ impl Stage for Late {
|
|||
) -> ErrorGuaranteed {
|
||||
tcx.dcx().emit_err(diag)
|
||||
}
|
||||
|
||||
fn should_emit(&self) -> ShouldEmit {
|
||||
ShouldEmit::ErrorsAndLints
|
||||
}
|
||||
}
|
||||
|
||||
/// used when parsing attributes for miscellaneous things *before* ast lowering
|
||||
|
|
@ -300,7 +319,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
|
|||
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||
/// that.
|
||||
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
|
||||
if !S::SHOULD_EMIT_LINTS {
|
||||
if !self.stage.should_emit().should_emit() {
|
||||
return;
|
||||
}
|
||||
let id = self.target_id;
|
||||
|
|
@ -811,8 +830,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
let args = parser.args();
|
||||
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
|
||||
for (template, accept) in accepts {
|
||||
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
|
||||
for accept in accepts {
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
shared: SharedContext {
|
||||
cx: self,
|
||||
|
|
@ -821,11 +840,11 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span: lower_span(attr.span),
|
||||
template,
|
||||
template: &accept.template,
|
||||
attr_path: path.get_attribute_path(),
|
||||
};
|
||||
|
||||
accept(&mut cx, args)
|
||||
(accept.accept_fn)(&mut cx, args)
|
||||
}
|
||||
} else {
|
||||
// If we're here, we must be compiling a tool attribute... Or someone
|
||||
|
|
@ -856,7 +875,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
}
|
||||
|
||||
let mut parsed_attributes = Vec::new();
|
||||
for f in &S::parsers().1 {
|
||||
for f in &S::parsers().finalizers {
|
||||
if let Some(attr) = f(&mut FinalizeContext {
|
||||
shared: SharedContext {
|
||||
cx: self,
|
||||
|
|
@ -877,7 +896,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
|||
|
||||
/// Returns whether there is a parser for an attribute with this name
|
||||
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
|
||||
Late::parsers().0.contains_key(path)
|
||||
Late::parsers().accepters.contains_key(path)
|
||||
}
|
||||
|
||||
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
//! Centralized logic for parsing and attributes.
|
||||
//!
|
||||
//! ## Architecture
|
||||
//! This crate is part of a series of crates that handle attribute processing.
|
||||
//! - [rustc_attr_data_structures](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_data_structures/index.html): Defines the data structures that store parsed attributes
|
||||
//! This crate is part of a series of crates and modules that handle attribute processing.
|
||||
//! - [rustc_hir::attrs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/index.html): Defines the data structures that store parsed attributes
|
||||
//! - [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html): This crate, handles the parsing of attributes
|
||||
//! - (planned) rustc_attr_validation: Will handle attribute validation
|
||||
//! - (planned) rustc_attr_validation: Will handle attribute validation, logic currently handled in `rustc_passes`
|
||||
//!
|
||||
//! The separation between data structures and parsing follows the principle of separation of concerns.
|
||||
//! Data structures (`rustc_attr_data_structures`) define what attributes look like after parsing.
|
||||
//! Data structures (`rustc_hir::attrs`) define what attributes look like after parsing.
|
||||
//! This crate (`rustc_attr_parsing`) handles how to convert raw tokens into those structures.
|
||||
//! This split allows other parts of the compiler to use the data structures without needing
|
||||
//! the parsing logic, making the codebase more modular and maintainable.
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
//! a "stability" of an item. So, the stability attribute has an
|
||||
//! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]`
|
||||
//! and `#[unstable()]` syntactic attributes, and at the end produce a single
|
||||
//! [`AttributeKind::Stability`](rustc_attr_data_structures::AttributeKind::Stability).
|
||||
//! [`AttributeKind::Stability`](rustc_hir::attrs::AttributeKind::Stability).
|
||||
//!
|
||||
//! When multiple instances of the same attribute are allowed, they're combined into a single
|
||||
//! semantic attribute. For example:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_errors::{DiagArgValue, LintEmitter};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
|
||||
|
||||
use crate::session_diagnostics;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::rc::Rc;
|
|||
|
||||
use rustc_errors::Diag;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use rustc_infer::infer::region_constraints::{Constraint, ConstraintKind, RegionConstraintData};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, RegionResolutionError, RegionVariableOrigin, SubregionOrigin, TyCtxtInferExt as _,
|
||||
};
|
||||
|
|
@ -277,7 +277,7 @@ where
|
|||
// `QueryNormalizeExt::query_normalize` used in the query and `normalize` called below:
|
||||
// the former fails to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs`
|
||||
// test. Check after #85499 lands to see if its fixes have erased this difference.
|
||||
let (param_env, value) = key.into_parts();
|
||||
let ty::ParamEnvAnd { param_env, value } = key;
|
||||
let _ = ocx.normalize(&cause, param_env, value.value);
|
||||
|
||||
let diag = try_extract_error_from_fulfill_cx(
|
||||
|
|
@ -324,7 +324,7 @@ where
|
|||
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let (param_env, value) = key.into_parts();
|
||||
let ty::ParamEnvAnd { param_env, value } = key;
|
||||
let _ = ocx.deeply_normalize(&cause, param_env, value.value);
|
||||
|
||||
let diag = try_extract_error_from_fulfill_cx(
|
||||
|
|
@ -454,25 +454,24 @@ fn try_extract_error_from_region_constraints<'a, 'tcx>(
|
|||
(RePlaceholder(a_p), RePlaceholder(b_p)) => a_p.bound == b_p.bound,
|
||||
_ => a_region == b_region,
|
||||
};
|
||||
let mut check =
|
||||
|constraint: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match *constraint {
|
||||
Constraint::RegSubReg(sub, sup)
|
||||
if ((exact && sup == placeholder_region)
|
||||
|| (!exact && regions_the_same(sup, placeholder_region)))
|
||||
&& sup != sub =>
|
||||
{
|
||||
Some((sub, cause.clone()))
|
||||
}
|
||||
Constraint::VarSubReg(vid, sup)
|
||||
if (exact
|
||||
&& sup == placeholder_region
|
||||
&& !universe_of_region(vid).can_name(placeholder_universe))
|
||||
|| (!exact && regions_the_same(sup, placeholder_region)) =>
|
||||
{
|
||||
Some((ty::Region::new_var(infcx.tcx, vid), cause.clone()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
let mut check = |c: &Constraint<'tcx>, cause: &SubregionOrigin<'tcx>, exact| match c.kind {
|
||||
ConstraintKind::RegSubReg
|
||||
if ((exact && c.sup == placeholder_region)
|
||||
|| (!exact && regions_the_same(c.sup, placeholder_region)))
|
||||
&& c.sup != c.sub =>
|
||||
{
|
||||
Some((c.sub, cause.clone()))
|
||||
}
|
||||
ConstraintKind::VarSubReg
|
||||
if (exact
|
||||
&& c.sup == placeholder_region
|
||||
&& !universe_of_region(c.sub.as_var()).can_name(placeholder_universe))
|
||||
|| (!exact && regions_the_same(c.sup, placeholder_region)) =>
|
||||
{
|
||||
Some((c.sub, cause.clone()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let mut find_culprit = |exact_match: bool| {
|
||||
region_constraints
|
||||
|
|
|
|||
|
|
@ -410,18 +410,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
let typeck = self.infcx.tcx.typeck(self.mir_def_id());
|
||||
let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
|
||||
let (def_id, call_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
|
||||
let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
|
||||
{
|
||||
let def_id = typeck.type_dependent_def_id(parent_expr.hir_id);
|
||||
(def_id, Some(parent_expr.hir_id), args, 1)
|
||||
(def_id, args, 1)
|
||||
} else if let hir::Node::Expr(parent_expr) = parent
|
||||
&& let hir::ExprKind::Call(call, args) = parent_expr.kind
|
||||
&& let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind()
|
||||
{
|
||||
(Some(*def_id), Some(call.hir_id), args, 0)
|
||||
(Some(*def_id), args, 0)
|
||||
} else {
|
||||
(None, None, &[][..], 0)
|
||||
(None, &[][..], 0)
|
||||
};
|
||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
|
||||
|
|
@ -459,11 +459,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// If the moved place is used generically by the callee and a reference to it
|
||||
// would still satisfy any bounds on its type, suggest borrowing.
|
||||
if let Some(¶m) = arg_param
|
||||
&& let Some(generic_args) = call_id.and_then(|id| typeck.node_args_opt(id))
|
||||
&& let hir::Node::Expr(call_expr) = parent
|
||||
&& let Some(ref_mutability) = self.suggest_borrow_generic_arg(
|
||||
err,
|
||||
typeck,
|
||||
call_expr,
|
||||
def_id,
|
||||
generic_args,
|
||||
param,
|
||||
moved_place,
|
||||
pos + offset,
|
||||
|
|
@ -627,8 +628,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
fn suggest_borrow_generic_arg(
|
||||
&self,
|
||||
err: &mut Diag<'_>,
|
||||
typeck: &ty::TypeckResults<'tcx>,
|
||||
call_expr: &hir::Expr<'tcx>,
|
||||
callee_did: DefId,
|
||||
generic_args: ty::GenericArgsRef<'tcx>,
|
||||
param: ty::ParamTy,
|
||||
moved_place: PlaceRef<'tcx>,
|
||||
moved_arg_pos: usize,
|
||||
|
|
@ -639,6 +641,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder();
|
||||
let clauses = tcx.predicates_of(callee_did);
|
||||
|
||||
let generic_args = match call_expr.kind {
|
||||
// For method calls, generic arguments are attached to the call node.
|
||||
hir::ExprKind::MethodCall(..) => typeck.node_args_opt(call_expr.hir_id)?,
|
||||
// For normal calls, generic arguments are in the callee's type.
|
||||
// This diagnostic is only run for `FnDef` callees.
|
||||
hir::ExprKind::Call(callee, _)
|
||||
if let &ty::FnDef(_, args) = typeck.node_type(callee.hir_id).kind() =>
|
||||
{
|
||||
args
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// First, is there at least one method on one of `param`'s trait bounds?
|
||||
// This keeps us from suggesting borrowing the argument to `mem::drop`, e.g.
|
||||
if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| {
|
||||
|
|
@ -2384,7 +2399,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
if let Some(body_expr) = finder.body_expr
|
||||
&& let Some(loop_span) = finder.loop_span
|
||||
&& let Some(def_id) = typeck_results.type_dependent_def_id(body_expr.hir_id)
|
||||
&& let Some(trait_did) = tcx.trait_of_item(def_id)
|
||||
&& let Some(trait_did) = tcx.trait_of_assoc(def_id)
|
||||
&& tcx.is_diagnostic_item(sym::Iterator, trait_did)
|
||||
{
|
||||
if let Some(loop_bind) = finder.loop_bind {
|
||||
|
|
@ -2533,13 +2548,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
|
||||
// Check that the parent of the closure is a method call,
|
||||
// with receiver matching with local's type (modulo refs)
|
||||
if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) {
|
||||
if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
|
||||
let recv_ty = typeck_results.expr_ty(recv);
|
||||
if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id)
|
||||
&& let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind
|
||||
{
|
||||
let recv_ty = typeck_results.expr_ty(recv);
|
||||
|
||||
if recv_ty.peel_refs() != local_ty {
|
||||
return;
|
||||
}
|
||||
if recv_ty.peel_refs() != local_ty {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2805,16 +2820,16 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// With the place of a union and a field access into it, we traverse the second
|
||||
// borrowed place and look for an access to a different field of the same union.
|
||||
for (place_base, elem) in second_borrowed_place.iter_projections().rev() {
|
||||
if let ProjectionElem::Field(field, _) = elem {
|
||||
if let Some(union_ty) = union_ty(place_base) {
|
||||
if field != target_field && place_base == target_base {
|
||||
return Some((
|
||||
self.describe_any_place(place_base),
|
||||
self.describe_any_place(first_borrowed_place.as_ref()),
|
||||
self.describe_any_place(second_borrowed_place.as_ref()),
|
||||
union_ty.to_string(),
|
||||
));
|
||||
}
|
||||
if let ProjectionElem::Field(field, _) = elem
|
||||
&& let Some(union_ty) = union_ty(place_base)
|
||||
{
|
||||
if field != target_field && place_base == target_base {
|
||||
return Some((
|
||||
self.describe_any_place(place_base),
|
||||
self.describe_any_place(first_borrowed_place.as_ref()),
|
||||
self.describe_any_place(second_borrowed_place.as_ref()),
|
||||
union_ty.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3001,16 +3016,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
from_closure: false,
|
||||
..
|
||||
} = explanation
|
||||
{
|
||||
if let Err(diag) = self.try_report_cannot_return_reference_to_local(
|
||||
&& let Err(diag) = self.try_report_cannot_return_reference_to_local(
|
||||
borrow,
|
||||
borrow_span,
|
||||
span,
|
||||
category,
|
||||
opt_place_desc.as_ref(),
|
||||
) {
|
||||
return diag;
|
||||
}
|
||||
)
|
||||
{
|
||||
return diag;
|
||||
}
|
||||
|
||||
let name = format!("`{name}`");
|
||||
|
|
@ -3772,30 +3786,30 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let loan_span = loan_spans.args_or_use();
|
||||
|
||||
let descr_place = self.describe_any_place(place.as_ref());
|
||||
if let BorrowKind::Fake(_) = loan.kind {
|
||||
if let Some(section) = self.classify_immutable_section(loan.assigned_place) {
|
||||
let mut err = self.cannot_mutate_in_immutable_section(
|
||||
span,
|
||||
loan_span,
|
||||
&descr_place,
|
||||
section,
|
||||
"assign",
|
||||
);
|
||||
if let BorrowKind::Fake(_) = loan.kind
|
||||
&& let Some(section) = self.classify_immutable_section(loan.assigned_place)
|
||||
{
|
||||
let mut err = self.cannot_mutate_in_immutable_section(
|
||||
span,
|
||||
loan_span,
|
||||
&descr_place,
|
||||
section,
|
||||
"assign",
|
||||
);
|
||||
|
||||
loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUseInClosure { var_span }
|
||||
}
|
||||
loan_spans.var_subdiag(&mut err, Some(loan.kind), |kind, var_span| {
|
||||
use crate::session_diagnostics::CaptureVarCause::*;
|
||||
match kind {
|
||||
hir::ClosureKind::Coroutine(_) => BorrowUseInCoroutine { var_span },
|
||||
hir::ClosureKind::Closure | hir::ClosureKind::CoroutineClosure(_) => {
|
||||
BorrowUseInClosure { var_span }
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
self.buffer_error(err);
|
||||
self.buffer_error(err);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
|
||||
|
|
@ -4048,119 +4062,116 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
"annotate_argument_and_return_for_borrow: target={:?} stmt={:?}",
|
||||
target, stmt
|
||||
);
|
||||
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
|
||||
if let Some(assigned_to) = place.as_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind
|
||||
&& let Some(assigned_to) = place.as_local()
|
||||
{
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} \
|
||||
rvalue={:?}",
|
||||
assigned_to, rvalue
|
||||
);
|
||||
// Check if our `target` was captured by a closure.
|
||||
if let Rvalue::Aggregate(
|
||||
box AggregateKind::Closure(def_id, args),
|
||||
operands,
|
||||
) = rvalue
|
||||
{
|
||||
let def_id = def_id.expect_local();
|
||||
for operand in operands {
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
|
||||
operand
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from
|
||||
);
|
||||
assigned_to, rvalue
|
||||
);
|
||||
// Check if our `target` was captured by a closure.
|
||||
if let Rvalue::Aggregate(box AggregateKind::Closure(def_id, args), operands) =
|
||||
rvalue
|
||||
{
|
||||
let def_id = def_id.expect_local();
|
||||
for operand in operands {
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
|
||||
operand
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from
|
||||
);
|
||||
|
||||
// Find the local from the operand.
|
||||
let Some(assigned_from_local) =
|
||||
assigned_from.local_or_deref_local()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
// Find the local from the operand.
|
||||
let Some(assigned_from_local) = assigned_from.local_or_deref_local()
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a closure captured our `target` and then assigned
|
||||
// into a place then we should annotate the closure in
|
||||
// case it ends up being assigned into the return place.
|
||||
annotated_closure =
|
||||
self.annotate_fn_sig(def_id, args.as_closure().sig());
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
annotated_closure={:?} assigned_from_local={:?} \
|
||||
assigned_to={:?}",
|
||||
annotated_closure, assigned_from_local, assigned_to
|
||||
);
|
||||
|
||||
if assigned_to == mir::RETURN_PLACE {
|
||||
// If it was assigned directly into the return place, then
|
||||
// return now.
|
||||
return annotated_closure;
|
||||
} else {
|
||||
// Otherwise, update the target.
|
||||
target = assigned_to;
|
||||
}
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If none of our closure's operands matched, then skip to the next
|
||||
// statement.
|
||||
continue;
|
||||
// If a closure captured our `target` and then assigned
|
||||
// into a place then we should annotate the closure in
|
||||
// case it ends up being assigned into the return place.
|
||||
annotated_closure =
|
||||
self.annotate_fn_sig(def_id, args.as_closure().sig());
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
annotated_closure={:?} assigned_from_local={:?} \
|
||||
assigned_to={:?}",
|
||||
annotated_closure, assigned_from_local, assigned_to
|
||||
);
|
||||
|
||||
if assigned_to == mir::RETURN_PLACE {
|
||||
// If it was assigned directly into the return place, then
|
||||
// return now.
|
||||
return annotated_closure;
|
||||
} else {
|
||||
// Otherwise, update the target.
|
||||
target = assigned_to;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, look at other types of assignment.
|
||||
let assigned_from = match rvalue {
|
||||
Rvalue::Ref(_, _, assigned_from) => assigned_from,
|
||||
Rvalue::Use(operand) => match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from={:?}",
|
||||
assigned_from,
|
||||
);
|
||||
|
||||
// Find the local from the rvalue.
|
||||
let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
|
||||
continue;
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
// Check if our local matches the target - if so, we've assigned our
|
||||
// borrow to a new place.
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we assigned our `target` into a new place, then we should
|
||||
// check if it was the return place.
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?} assigned_to={:?}",
|
||||
assigned_from_local, assigned_to
|
||||
);
|
||||
if assigned_to == mir::RETURN_PLACE {
|
||||
// If it was then return the annotated closure if there was one,
|
||||
// else, annotate this function.
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
|
||||
// If we didn't assign into the return place, then we just update
|
||||
// the target.
|
||||
target = assigned_to;
|
||||
// If none of our closure's operands matched, then skip to the next
|
||||
// statement.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, look at other types of assignment.
|
||||
let assigned_from = match rvalue {
|
||||
Rvalue::Ref(_, _, assigned_from) => assigned_from,
|
||||
Rvalue::Use(operand) => match operand {
|
||||
Operand::Copy(assigned_from) | Operand::Move(assigned_from) => {
|
||||
assigned_from
|
||||
}
|
||||
_ => continue,
|
||||
},
|
||||
_ => continue,
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from={:?}",
|
||||
assigned_from,
|
||||
);
|
||||
|
||||
// Find the local from the rvalue.
|
||||
let Some(assigned_from_local) = assigned_from.local_or_deref_local() else {
|
||||
continue;
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
// Check if our local matches the target - if so, we've assigned our
|
||||
// borrow to a new place.
|
||||
if assigned_from_local != target {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we assigned our `target` into a new place, then we should
|
||||
// check if it was the return place.
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: \
|
||||
assigned_from_local={:?} assigned_to={:?}",
|
||||
assigned_from_local, assigned_to
|
||||
);
|
||||
if assigned_to == mir::RETURN_PLACE {
|
||||
// If it was then return the annotated closure if there was one,
|
||||
// else, annotate this function.
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
|
||||
// If we didn't assign into the return place, then we just update
|
||||
// the target.
|
||||
target = assigned_to;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4172,32 +4183,31 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
);
|
||||
if let TerminatorKind::Call { destination, target: Some(_), args, .. } =
|
||||
&terminator.kind
|
||||
&& let Some(assigned_to) = destination.as_local()
|
||||
{
|
||||
if let Some(assigned_to) = destination.as_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
|
||||
assigned_to, args
|
||||
);
|
||||
for operand in args {
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
|
||||
&operand.node
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_to={:?} args={:?}",
|
||||
assigned_to, args
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from,
|
||||
);
|
||||
for operand in args {
|
||||
let (Operand::Copy(assigned_from) | Operand::Move(assigned_from)) =
|
||||
&operand.node
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from={:?}",
|
||||
assigned_from,
|
||||
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
if let Some(assigned_from_local) = assigned_from.local_or_deref_local() {
|
||||
debug!(
|
||||
"annotate_argument_and_return_for_borrow: assigned_from_local={:?}",
|
||||
assigned_from_local,
|
||||
);
|
||||
|
||||
if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
if assigned_to == mir::RETURN_PLACE && assigned_from_local == target {
|
||||
return annotated_closure.or_else(fallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4296,10 +4306,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
// as the HIR doesn't have full types for closure arguments.
|
||||
let return_ty = sig.output().skip_binder();
|
||||
let mut return_span = fn_decl.output.span();
|
||||
if let hir::FnRetTy::Return(ty) = &fn_decl.output {
|
||||
if let hir::TyKind::Ref(lifetime, _) = ty.kind {
|
||||
return_span = lifetime.ident.span;
|
||||
}
|
||||
if let hir::FnRetTy::Return(ty) = &fn_decl.output
|
||||
&& let hir::TyKind::Ref(lifetime, _) = ty.kind
|
||||
{
|
||||
return_span = lifetime.ident.span;
|
||||
}
|
||||
|
||||
Some(AnnotatedBorrowFnSignature::NamedFunction {
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
}
|
||||
}
|
||||
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
|
||||
let sp = info.span.find_oldest_ancestor_in_same_ctxt();
|
||||
let sp = info.span.find_ancestor_not_from_macro().unwrap_or(info.span);
|
||||
if info.tail_result_is_ignored {
|
||||
// #85581: If the first mutable borrow's scope contains
|
||||
// the second borrow, this suggestion isn't helpful.
|
||||
|
|
@ -917,30 +917,29 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
|
||||
if let TerminatorKind::Call { destination, target: Some(block), args, .. } =
|
||||
&terminator.kind
|
||||
&& let Some(dest) = destination.as_local()
|
||||
{
|
||||
if let Some(dest) = destination.as_local() {
|
||||
debug!(
|
||||
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
|
||||
target, dest, args
|
||||
);
|
||||
// Check if one of the arguments to this function is the target place.
|
||||
let found_target = args.iter().any(|arg| {
|
||||
if let Operand::Move(place) = arg.node {
|
||||
if let Some(potential) = place.as_local() {
|
||||
potential == target
|
||||
} else {
|
||||
false
|
||||
}
|
||||
debug!(
|
||||
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
|
||||
target, dest, args
|
||||
);
|
||||
// Check if one of the arguments to this function is the target place.
|
||||
let found_target = args.iter().any(|arg| {
|
||||
if let Operand::Move(place) = arg.node {
|
||||
if let Some(potential) = place.as_local() {
|
||||
potential == target
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// If it is, follow this to the next block and update the target.
|
||||
if found_target {
|
||||
target = dest;
|
||||
queue.push(block.start_location());
|
||||
} else {
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
// If it is, follow this to the next block and update the target.
|
||||
if found_target {
|
||||
target = dest;
|
||||
queue.push(block.start_location());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ mod conflict_errors;
|
|||
mod explain_borrow;
|
||||
mod move_errors;
|
||||
mod mutability_errors;
|
||||
mod opaque_suggestions;
|
||||
mod opaque_types;
|
||||
mod region_errors;
|
||||
|
||||
pub(crate) use bound_region_errors::{ToUniverseInfo, UniverseInfo};
|
||||
|
|
@ -266,48 +266,44 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
args,
|
||||
..
|
||||
} = &terminator.kind
|
||||
&& let ty::FnDef(id, _) = *const_.ty().kind()
|
||||
{
|
||||
if let ty::FnDef(id, _) = *const_.ty().kind() {
|
||||
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
||||
if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
|
||||
let closure = match args.first() {
|
||||
Some(Spanned {
|
||||
node: Operand::Copy(place) | Operand::Move(place), ..
|
||||
}) if target == place.local_or_deref_local() => {
|
||||
place.local_or_deref_local().unwrap()
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
||||
if self.infcx.tcx.is_lang_item(self.infcx.tcx.parent(id), LangItem::FnOnce) {
|
||||
let closure = match args.first() {
|
||||
Some(Spanned { node: Operand::Copy(place) | Operand::Move(place), .. })
|
||||
if target == place.local_or_deref_local() =>
|
||||
{
|
||||
place.local_or_deref_local().unwrap()
|
||||
}
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
|
||||
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.subdiagnostic(OnClosureNote::InvokedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(
|
||||
self.infcx.tcx,
|
||||
hir_place,
|
||||
),
|
||||
span: *span,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
debug!("add_moved_or_invoked_closure_note: closure={:?}", closure);
|
||||
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.subdiagnostic(OnClosureNote::InvokedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
span: *span,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are just moving a closure after it has been invoked.
|
||||
if let Some(target) = target {
|
||||
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.subdiagnostic(OnClosureNote::MovedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
span: *span,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if let Some(target) = target
|
||||
&& let ty::Closure(did, _) = self.body.local_decls[target].ty.kind()
|
||||
{
|
||||
let did = did.expect_local();
|
||||
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
|
||||
diag.subdiagnostic(OnClosureNote::MovedTwice {
|
||||
place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
|
||||
span: *span,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
|
|
@ -617,7 +613,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
/// Return the name of the provided `Ty` (that must be a reference) with a synthesized lifetime
|
||||
/// name where required.
|
||||
pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
|
||||
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
||||
let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
||||
|
||||
// We need to add synthesized lifetimes where appropriate. We do
|
||||
// this by hooking into the pretty printer and telling it to label the
|
||||
|
|
@ -628,19 +624,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
| ty::RePlaceholder(ty::PlaceholderRegion {
|
||||
bound: ty::BoundRegion { kind: br, .. },
|
||||
..
|
||||
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
|
||||
}) => p.region_highlight_mode.highlighting_bound_region(br, counter),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
ty.print(&mut printer).unwrap();
|
||||
printer.into_buffer()
|
||||
ty.print(&mut p).unwrap();
|
||||
p.into_buffer()
|
||||
}
|
||||
|
||||
/// Returns the name of the provided `Ty` (that must be a reference)'s region with a
|
||||
/// synthesized lifetime name where required.
|
||||
pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
|
||||
let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
||||
let mut p = ty::print::FmtPrinter::new(self.infcx.tcx, Namespace::TypeNS);
|
||||
|
||||
let region = if let ty::Ref(region, ..) = ty.kind() {
|
||||
match region.kind() {
|
||||
|
|
@ -648,7 +644,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
| ty::RePlaceholder(ty::PlaceholderRegion {
|
||||
bound: ty::BoundRegion { kind: br, .. },
|
||||
..
|
||||
}) => printer.region_highlight_mode.highlighting_bound_region(br, counter),
|
||||
}) => p.region_highlight_mode.highlighting_bound_region(br, counter),
|
||||
_ => {}
|
||||
}
|
||||
region
|
||||
|
|
@ -656,8 +652,8 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
bug!("ty for annotation of borrow region is not a reference");
|
||||
};
|
||||
|
||||
region.print(&mut printer).unwrap();
|
||||
printer.into_buffer()
|
||||
region.print(&mut p).unwrap();
|
||||
p.into_buffer()
|
||||
}
|
||||
|
||||
/// Add a note to region errors and borrow explanations when higher-ranked regions in predicates
|
||||
|
|
@ -942,7 +938,7 @@ impl<'tcx> BorrowedContentSource<'tcx> {
|
|||
fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option<Self> {
|
||||
match *func.kind() {
|
||||
ty::FnDef(def_id, args) => {
|
||||
let trait_id = tcx.trait_of_item(def_id)?;
|
||||
let trait_id = tcx.trait_of_assoc(def_id)?;
|
||||
|
||||
if tcx.is_lang_item(trait_id, LangItem::Deref)
|
||||
|| tcx.is_lang_item(trait_id, LangItem::DerefMut)
|
||||
|
|
|
|||
|
|
@ -126,36 +126,35 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
.statements
|
||||
.get(location.statement_index)
|
||||
.map(|stmt| &stmt.kind)
|
||||
&& let Some(local) = place.as_local()
|
||||
{
|
||||
if let Some(local) = place.as_local() {
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
// opt_match_place is the
|
||||
// match_span is the span of the expression being matched on
|
||||
// match *x.y { ... } match_place is Some(*x.y)
|
||||
// ^^^^ match_span is the span of *x.y
|
||||
//
|
||||
// opt_match_place is None for let [mut] x = ... statements,
|
||||
// whether or not the right-hand side is a place expression
|
||||
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
pat_span: _,
|
||||
})) = *local_decl.local_info()
|
||||
{
|
||||
let stmt_source_info = self.body.source_info(location);
|
||||
self.append_binding_error(
|
||||
grouped_errors,
|
||||
kind,
|
||||
original_path,
|
||||
*move_from,
|
||||
local,
|
||||
opt_match_place,
|
||||
match_span,
|
||||
stmt_source_info.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
let local_decl = &self.body.local_decls[local];
|
||||
// opt_match_place is the
|
||||
// match_span is the span of the expression being matched on
|
||||
// match *x.y { ... } match_place is Some(*x.y)
|
||||
// ^^^^ match_span is the span of *x.y
|
||||
//
|
||||
// opt_match_place is None for let [mut] x = ... statements,
|
||||
// whether or not the right-hand side is a place expression
|
||||
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
|
||||
opt_match_place: Some((opt_match_place, match_span)),
|
||||
binding_mode: _,
|
||||
opt_ty_info: _,
|
||||
pat_span: _,
|
||||
})) = *local_decl.local_info()
|
||||
{
|
||||
let stmt_source_info = self.body.source_info(location);
|
||||
self.append_binding_error(
|
||||
grouped_errors,
|
||||
kind,
|
||||
original_path,
|
||||
*move_from,
|
||||
local,
|
||||
opt_match_place,
|
||||
match_span,
|
||||
stmt_source_info.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -682,7 +682,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
}
|
||||
let my_def = self.body.source.def_id();
|
||||
let Some(td) =
|
||||
self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
|
||||
self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
|
||||
else {
|
||||
return (false, false, None);
|
||||
};
|
||||
|
|
@ -880,7 +880,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
let opt_suggestions = tcx
|
||||
.typeck(path_segment.hir_id.owner.def_id)
|
||||
.type_dependent_def_id(expr.hir_id)
|
||||
.and_then(|def_id| tcx.impl_of_method(def_id))
|
||||
.and_then(|def_id| tcx.impl_of_assoc(def_id))
|
||||
.map(|def_id| tcx.associated_items(def_id))
|
||||
.map(|assoc_items| {
|
||||
assoc_items
|
||||
|
|
@ -1056,7 +1056,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
.tcx
|
||||
.typeck(path_segment.hir_id.owner.def_id)
|
||||
.type_dependent_def_id(cur_expr.hir_id)
|
||||
.and_then(|def_id| self.infcx.tcx.impl_of_method(def_id))
|
||||
.and_then(|def_id| self.infcx.tcx.impl_of_assoc(def_id))
|
||||
.map(|def_id| self.infcx.tcx.associated_items(def_id))
|
||||
.map(|assoc_items| {
|
||||
assoc_items.filter_by_name_unhygienic(sym::iter_mut).peekable()
|
||||
|
|
|
|||
|
|
@ -18,9 +18,28 @@ use rustc_trait_selection::errors::impl_trait_overcapture_suggestion;
|
|||
use crate::MirBorrowckCtxt;
|
||||
use crate::borrow_set::BorrowData;
|
||||
use crate::consumers::RegionInferenceContext;
|
||||
use crate::region_infer::opaque_types::DeferredOpaqueTypeError;
|
||||
use crate::type_check::Locations;
|
||||
|
||||
impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
||||
pub(crate) fn report_opaque_type_errors(&mut self, errors: Vec<DeferredOpaqueTypeError<'tcx>>) {
|
||||
if errors.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut guar = None;
|
||||
for error in errors {
|
||||
guar = Some(match error {
|
||||
DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err) => err.report(self.infcx),
|
||||
DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(err) => {
|
||||
self.infcx.dcx().emit_err(err)
|
||||
}
|
||||
});
|
||||
}
|
||||
let guar = guar.unwrap();
|
||||
self.root_cx.set_tainted_by_errors(guar);
|
||||
self.infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
/// Try to note when an opaque is involved in a borrowck error and that
|
||||
/// opaque captures lifetimes due to edition 2024.
|
||||
// FIXME: This code is otherwise somewhat general, and could easily be adapted
|
||||
|
|
@ -92,9 +92,6 @@ impl<'tcx> RegionErrors<'tcx> {
|
|||
) -> impl Iterator<Item = (RegionErrorKind<'tcx>, ErrorGuaranteed)> {
|
||||
self.0.into_iter()
|
||||
}
|
||||
pub(crate) fn has_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.0.get(0).map(|x| x.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for RegionErrors<'_> {
|
||||
|
|
|
|||
|
|
@ -528,15 +528,15 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
|
|||
// match_adt_and_segment in this case.
|
||||
Res::Def(DefKind::TyAlias, _) => (),
|
||||
_ => {
|
||||
if let Some(last_segment) = path.segments.last() {
|
||||
if let Some(highlight) = self.match_adt_and_segment(
|
||||
if let Some(last_segment) = path.segments.last()
|
||||
&& let Some(highlight) = self.match_adt_and_segment(
|
||||
args,
|
||||
needle_fr,
|
||||
last_segment,
|
||||
search_stack,
|
||||
) {
|
||||
return Some(highlight);
|
||||
}
|
||||
)
|
||||
{
|
||||
return Some(highlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ fn region_definitions<'tcx>(
|
|||
for info in var_infos.iter() {
|
||||
let origin = match info.origin {
|
||||
RegionVariableOrigin::Nll(origin) => origin,
|
||||
_ => NllRegionVariableOrigin::Existential { from_forall: false },
|
||||
_ => NllRegionVariableOrigin::Existential { from_forall: false, name: None },
|
||||
};
|
||||
|
||||
let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
|
||||
|
|
@ -216,22 +216,11 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>(
|
|||
placeholder_index_to_region: _,
|
||||
liveness_constraints,
|
||||
mut outlives_constraints,
|
||||
mut member_constraints,
|
||||
member_constraints,
|
||||
universe_causes,
|
||||
type_tests,
|
||||
} = constraints;
|
||||
|
||||
if let Some(guar) = universal_regions.tainted_by_errors() {
|
||||
debug!("Universal regions tainted by errors; removing constraints!");
|
||||
// Suppress unhelpful extra errors in `infer_opaque_types` by clearing out all
|
||||
// outlives bounds that we may end up checking.
|
||||
outlives_constraints = Default::default();
|
||||
member_constraints = Default::default();
|
||||
|
||||
// Also taint the entire scope.
|
||||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
let fr_static = universal_regions.fr_static;
|
||||
let compute_sccs =
|
||||
|constraints: &OutlivesConstraintSet<'tcx>,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use std::borrow::Cow;
|
|||
use std::cell::{OnceCell, RefCell};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
use std::rc::Rc;
|
||||
|
||||
use borrow_set::LocalsStateAtExit;
|
||||
use root_cx::BorrowCheckRootCtxt;
|
||||
|
|
@ -44,6 +45,7 @@ use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces}
|
|||
use rustc_mir_dataflow::move_paths::{
|
||||
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
|
||||
};
|
||||
use rustc_mir_dataflow::points::DenseLocationMap;
|
||||
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
|
||||
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
|
||||
use rustc_span::{ErrorGuaranteed, Span, Symbol};
|
||||
|
|
@ -60,11 +62,14 @@ use crate::path_utils::*;
|
|||
use crate::place_ext::PlaceExt;
|
||||
use crate::places_conflict::{PlaceConflictBias, places_conflict};
|
||||
use crate::polonius::PoloniusDiagnosticsContext;
|
||||
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
};
|
||||
use crate::prefixes::PrefixSet;
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::renumber::RegionCtxt;
|
||||
use crate::session_diagnostics::VarNeedNotMut;
|
||||
use crate::type_check::MirTypeckResults;
|
||||
|
||||
mod borrow_set;
|
||||
mod borrowck_errors;
|
||||
|
|
@ -321,7 +326,34 @@ fn do_mir_borrowck<'tcx>(
|
|||
let locals_are_invalidated_at_exit = tcx.hir_body_owner_kind(def).is_fn_or_closure();
|
||||
let borrow_set = BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &move_data);
|
||||
|
||||
// Compute non-lexical lifetimes.
|
||||
let location_map = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input())
|
||||
|| infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
||||
let mut polonius_facts =
|
||||
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults {
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
opaque_type_values,
|
||||
polonius_context,
|
||||
} = type_check::type_check(
|
||||
root_cx,
|
||||
&infcx,
|
||||
body,
|
||||
&promoted,
|
||||
universal_regions,
|
||||
&location_table,
|
||||
&borrow_set,
|
||||
&mut polonius_facts,
|
||||
&move_data,
|
||||
Rc::clone(&location_map),
|
||||
);
|
||||
|
||||
// Compute non-lexical lifetimes using the constraints computed
|
||||
// by typechecking the MIR body.
|
||||
let nll::NllOutput {
|
||||
regioncx,
|
||||
polonius_input,
|
||||
|
|
@ -332,14 +364,19 @@ fn do_mir_borrowck<'tcx>(
|
|||
} = nll::compute_regions(
|
||||
root_cx,
|
||||
&infcx,
|
||||
universal_regions,
|
||||
body,
|
||||
&promoted,
|
||||
&location_table,
|
||||
&move_data,
|
||||
&borrow_set,
|
||||
location_map,
|
||||
universal_region_relations,
|
||||
constraints,
|
||||
polonius_facts,
|
||||
polonius_context,
|
||||
);
|
||||
|
||||
let opaque_type_errors = regioncx.infer_opaque_types(root_cx, &infcx, opaque_type_values);
|
||||
|
||||
// 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);
|
||||
|
|
@ -434,7 +471,11 @@ fn do_mir_borrowck<'tcx>(
|
|||
};
|
||||
|
||||
// Compute and report region errors, if any.
|
||||
mbcx.report_region_errors(nll_errors);
|
||||
if nll_errors.is_empty() {
|
||||
mbcx.report_opaque_type_errors(opaque_type_errors);
|
||||
} else {
|
||||
mbcx.report_region_errors(nll_errors);
|
||||
}
|
||||
|
||||
let (mut flow_analysis, flow_entry_states) =
|
||||
get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ use std::path::PathBuf;
|
|||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
|
||||
use polonius_engine::{Algorithm, Output};
|
||||
use polonius_engine::{Algorithm, AllFacts, Output};
|
||||
use rustc_data_structures::frozen::Frozen;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_middle::mir::pretty::{PrettyPrintMirOptions, dump_mir_with_options};
|
||||
use rustc_middle::mir::{Body, PassWhere, Promoted, create_dump_file, dump_enabled, dump_mir};
|
||||
|
|
@ -18,14 +19,16 @@ use rustc_span::sym;
|
|||
use tracing::{debug, instrument};
|
||||
|
||||
use crate::borrow_set::BorrowSet;
|
||||
use crate::consumers::RustcFacts;
|
||||
use crate::diagnostics::RegionErrors;
|
||||
use crate::handle_placeholders::compute_sccs_applying_placeholder_outlives_constraints;
|
||||
use crate::polonius::PoloniusDiagnosticsContext;
|
||||
use crate::polonius::legacy::{
|
||||
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
|
||||
};
|
||||
use crate::polonius::{PoloniusContext, PoloniusDiagnosticsContext};
|
||||
use crate::region_infer::RegionInferenceContext;
|
||||
use crate::type_check::{self, MirTypeckResults};
|
||||
use crate::type_check::MirTypeckRegionConstraints;
|
||||
use crate::type_check::free_region_relations::UniversalRegionRelations;
|
||||
use crate::universal_regions::UniversalRegions;
|
||||
use crate::{
|
||||
BorrowCheckRootCtxt, BorrowckInferCtxt, ClosureOutlivesSubject, ClosureRegionRequirements,
|
||||
|
|
@ -76,41 +79,18 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
|
|||
pub(crate) fn compute_regions<'tcx>(
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &BorrowckInferCtxt<'tcx>,
|
||||
universal_regions: UniversalRegions<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
promoted: &IndexSlice<Promoted, Body<'tcx>>,
|
||||
location_table: &PoloniusLocationTable,
|
||||
move_data: &MoveData<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
location_map: Rc<DenseLocationMap>,
|
||||
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
mut polonius_facts: Option<AllFacts<RustcFacts>>,
|
||||
polonius_context: Option<PoloniusContext>,
|
||||
) -> NllOutput<'tcx> {
|
||||
let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
||||
let polonius_input = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_input())
|
||||
|| is_polonius_legacy_enabled;
|
||||
let polonius_output = root_cx.consumer.as_ref().map_or(false, |c| c.polonius_output())
|
||||
|| is_polonius_legacy_enabled;
|
||||
let mut polonius_facts =
|
||||
(polonius_input || PoloniusFacts::enabled(infcx.tcx)).then_some(PoloniusFacts::default());
|
||||
|
||||
let location_map = Rc::new(DenseLocationMap::new(body));
|
||||
|
||||
// Run the MIR type-checker.
|
||||
let MirTypeckResults {
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
opaque_type_values,
|
||||
polonius_context,
|
||||
} = type_check::type_check(
|
||||
root_cx,
|
||||
infcx,
|
||||
body,
|
||||
promoted,
|
||||
universal_regions,
|
||||
location_table,
|
||||
borrow_set,
|
||||
&mut polonius_facts,
|
||||
move_data,
|
||||
Rc::clone(&location_map),
|
||||
);
|
||||
|| infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled();
|
||||
|
||||
let lowered_constraints = compute_sccs_applying_placeholder_outlives_constraints(
|
||||
constraints,
|
||||
|
|
@ -168,13 +148,6 @@ pub(crate) fn compute_regions<'tcx>(
|
|||
let (closure_region_requirements, nll_errors) =
|
||||
regioncx.solve(infcx, body, polonius_output.clone());
|
||||
|
||||
if let Some(guar) = nll_errors.has_errors() {
|
||||
// Suppress unhelpful extra errors in `infer_opaque_types`.
|
||||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
regioncx.infer_opaque_types(root_cx, infcx, opaque_type_values);
|
||||
|
||||
NllOutput {
|
||||
regioncx,
|
||||
polonius_input: polonius_facts.map(Box::new),
|
||||
|
|
|
|||
|
|
@ -7,9 +7,7 @@ use rustc_mir_dataflow::points::PointIndex;
|
|||
///
|
||||
/// This models two sources of constraints:
|
||||
/// - constraints that traverse the subsets between regions at a given point, `a@p: b@p`. These
|
||||
/// depend on typeck constraints generated via assignments, calls, etc. (In practice there are
|
||||
/// subtleties where a statement's effect only starts being visible at the successor point, via
|
||||
/// the "result" of that statement).
|
||||
/// depend on typeck constraints generated via assignments, calls, etc.
|
||||
/// - constraints that traverse the CFG via the same region, `a@p: a@q`, where `p` is a predecessor
|
||||
/// of `q`. These depend on the liveness of the regions at these points, as well as their
|
||||
/// variance.
|
||||
|
|
|
|||
|
|
@ -105,22 +105,14 @@ fn propagate_loans_between_points(
|
|||
});
|
||||
}
|
||||
|
||||
let Some(current_live_regions) = live_regions.row(current_point) else {
|
||||
// There are no constraints to add: there are no live regions at the current point.
|
||||
return;
|
||||
};
|
||||
let Some(next_live_regions) = live_regions.row(next_point) else {
|
||||
// There are no constraints to add: there are no live regions at the next point.
|
||||
return;
|
||||
};
|
||||
|
||||
for region in next_live_regions.iter() {
|
||||
if !current_live_regions.contains(region) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// `region` is indeed live at both points, add a constraint between them, according to
|
||||
// variance.
|
||||
// `region` could be live at the current point, and is live at the next point: add a
|
||||
// constraint between them, according to variance.
|
||||
if let Some(&direction) = live_region_variances.get(®ion) {
|
||||
add_liveness_constraint(
|
||||
region,
|
||||
|
|
|
|||
|
|
@ -1,27 +1,18 @@
|
|||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
|
||||
use rustc_middle::mir::visit::Visitor;
|
||||
use rustc_middle::mir::{
|
||||
Body, Local, Location, Place, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::{RegionVid, TyCtxt};
|
||||
use rustc_middle::ty::RegionVid;
|
||||
use rustc_mir_dataflow::points::PointIndex;
|
||||
|
||||
use super::{LiveLoans, LocalizedOutlivesConstraintSet};
|
||||
use crate::BorrowSet;
|
||||
use crate::constraints::OutlivesConstraint;
|
||||
use crate::dataflow::BorrowIndex;
|
||||
use crate::region_infer::values::LivenessValues;
|
||||
use crate::type_check::Locations;
|
||||
use crate::{BorrowSet, PlaceConflictBias, places_conflict};
|
||||
|
||||
/// Compute loan reachability, stop at kills, and trace loan liveness throughout the CFG, by
|
||||
/// Compute loan reachability to approximately trace loan liveness throughout the CFG, by
|
||||
/// traversing the full graph of constraints that combines:
|
||||
/// - the localized constraints (the physical edges),
|
||||
/// - with the constraints that hold at all points (the logical edges).
|
||||
pub(super) fn compute_loan_liveness<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
outlives_constraints: impl Iterator<Item = OutlivesConstraint<'tcx>>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
|
|
@ -29,11 +20,6 @@ pub(super) fn compute_loan_liveness<'tcx>(
|
|||
) -> LiveLoans {
|
||||
let mut live_loans = LiveLoans::new(borrow_set.len());
|
||||
|
||||
// FIXME: it may be preferable for kills to be encoded in the edges themselves, to simplify and
|
||||
// likely make traversal (and constraint generation) more efficient. We also display kills on
|
||||
// edges when visualizing the constraint graph anyways.
|
||||
let kills = collect_kills(body, tcx, borrow_set);
|
||||
|
||||
// Create the full graph with the physical edges we've localized earlier, and the logical edges
|
||||
// of constraints that hold at all points.
|
||||
let logical_constraints =
|
||||
|
|
@ -59,15 +45,15 @@ pub(super) fn compute_loan_liveness<'tcx>(
|
|||
continue;
|
||||
}
|
||||
|
||||
// Record the loan as being live on entry to this point.
|
||||
live_loans.insert(node.point, loan_idx);
|
||||
|
||||
// Here, we have a conundrum. There's currently a weakness in our theory, in that
|
||||
// we're using a single notion of reachability to represent what used to be _two_
|
||||
// different transitive closures. It didn't seem impactful when coming up with the
|
||||
// single-graph and reachability through space (regions) + time (CFG) concepts, but in
|
||||
// practice the combination of time-traveling with kills is more impactful than
|
||||
// initially anticipated.
|
||||
// Record the loan as being live on entry to this point if it reaches a live region
|
||||
// there.
|
||||
//
|
||||
// This is an approximation of liveness (which is the thing we want), in that we're
|
||||
// using a single notion of reachability to represent what used to be _two_ different
|
||||
// transitive closures. It didn't seem impactful when coming up with the single-graph
|
||||
// and reachability through space (regions) + time (CFG) concepts, but in practice the
|
||||
// combination of time-traveling with kills is more impactful than initially
|
||||
// anticipated.
|
||||
//
|
||||
// Kills should prevent a loan from reaching its successor points in the CFG, but not
|
||||
// while time-traveling: we're not actually at that CFG point, but looking for
|
||||
|
|
@ -92,40 +78,20 @@ pub(super) fn compute_loan_liveness<'tcx>(
|
|||
// two-step traversal described above: only kills encountered on exit via a backward
|
||||
// edge are ignored.
|
||||
//
|
||||
// In our test suite, there are a couple of cases where kills are encountered while
|
||||
// time-traveling, however as far as we can tell, always in cases where they would be
|
||||
// unreachable. We have reason to believe that this is a property of the single-graph
|
||||
// approach (but haven't proved it yet):
|
||||
// - reachable kills while time-traveling would also be encountered via regular
|
||||
// traversal
|
||||
// - it makes _some_ sense to ignore unreachable kills, but subtleties around dead code
|
||||
// in general need to be better thought through (like they were for NLLs).
|
||||
// - ignoring kills is a conservative approximation: the loan is still live and could
|
||||
// cause false positive errors at another place access. Soundness issues in this
|
||||
// domain should look more like the absence of reachability instead.
|
||||
// This version of the analysis, however, is enough in practice to pass the tests that
|
||||
// we care about and NLLs reject, without regressions on crater, and is an actionable
|
||||
// subset of the full analysis. It also naturally points to areas of improvement that we
|
||||
// wish to explore later, namely handling kills appropriately during traversal, instead
|
||||
// of continuing traversal to all the reachable nodes.
|
||||
//
|
||||
// This is enough in practice to pass tests, and therefore is what we have implemented
|
||||
// for now.
|
||||
//
|
||||
// FIXME: all of the above. Analyze potential unsoundness, possibly in concert with a
|
||||
// borrowck implementation in a-mir-formality, fuzzing, or manually crafting
|
||||
// counter-examples.
|
||||
// FIXME: analyze potential unsoundness, possibly in concert with a borrowck
|
||||
// implementation in a-mir-formality, fuzzing, or manually crafting counter-examples.
|
||||
|
||||
// Continuing traversal will depend on whether the loan is killed at this point, and
|
||||
// whether we're time-traveling.
|
||||
let current_location = liveness.location_from_point(node.point);
|
||||
let is_loan_killed =
|
||||
kills.get(¤t_location).is_some_and(|kills| kills.contains(&loan_idx));
|
||||
if liveness.is_live_at(node.region, liveness.location_from_point(node.point)) {
|
||||
live_loans.insert(node.point, loan_idx);
|
||||
}
|
||||
|
||||
for succ in graph.outgoing_edges(node) {
|
||||
// If the loan is killed at this point, it is killed _on exit_. But only during
|
||||
// forward traversal.
|
||||
if is_loan_killed {
|
||||
let destination = liveness.location_from_point(succ.point);
|
||||
if current_location.is_predecessor_of(destination, body) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
stack.push(succ);
|
||||
}
|
||||
}
|
||||
|
|
@ -192,116 +158,3 @@ impl LocalizedConstraintGraph {
|
|||
physical_edges.chain(materialized_edges)
|
||||
}
|
||||
}
|
||||
|
||||
/// Traverses the MIR and collects kills.
|
||||
fn collect_kills<'tcx>(
|
||||
body: &Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
borrow_set: &BorrowSet<'tcx>,
|
||||
) -> BTreeMap<Location, BTreeSet<BorrowIndex>> {
|
||||
let mut collector = KillsCollector { borrow_set, tcx, body, kills: BTreeMap::default() };
|
||||
for (block, data) in body.basic_blocks.iter_enumerated() {
|
||||
collector.visit_basic_block_data(block, data);
|
||||
}
|
||||
collector.kills
|
||||
}
|
||||
|
||||
struct KillsCollector<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
borrow_set: &'a BorrowSet<'tcx>,
|
||||
|
||||
/// The set of loans killed at each location.
|
||||
kills: BTreeMap<Location, BTreeSet<BorrowIndex>>,
|
||||
}
|
||||
|
||||
// This visitor has a similar structure to the `Borrows` dataflow computation with respect to kills,
|
||||
// and the datalog polonius fact generation for the `loan_killed_at` relation.
|
||||
impl<'tcx> KillsCollector<'_, 'tcx> {
|
||||
/// Records the borrows on the specified place as `killed`. For example, when assigning to a
|
||||
/// local, or on a call's return destination.
|
||||
fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) {
|
||||
// For the reasons described in graph traversal, we also filter out kills
|
||||
// unreachable from the loan's introduction point, as they would stop traversal when
|
||||
// e.g. checking for reachability in the subset graph through invariance constraints
|
||||
// higher up.
|
||||
let filter_unreachable_kills = |loan| {
|
||||
let introduction = self.borrow_set[loan].reserve_location;
|
||||
let reachable = introduction.is_predecessor_of(location, self.body);
|
||||
reachable
|
||||
};
|
||||
|
||||
let other_borrows_of_local = self
|
||||
.borrow_set
|
||||
.local_map
|
||||
.get(&place.local)
|
||||
.into_iter()
|
||||
.flat_map(|bs| bs.iter())
|
||||
.copied();
|
||||
|
||||
// If the borrowed place is a local with no projections, all other borrows of this
|
||||
// local must conflict. This is purely an optimization so we don't have to call
|
||||
// `places_conflict` for every borrow.
|
||||
if place.projection.is_empty() {
|
||||
if !self.body.local_decls[place.local].is_ref_to_static() {
|
||||
self.kills
|
||||
.entry(location)
|
||||
.or_default()
|
||||
.extend(other_borrows_of_local.filter(|&loan| filter_unreachable_kills(loan)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given
|
||||
// pair of array indices are not equal, so that when `places_conflict` returns true, we
|
||||
// will be assured that two places being compared definitely denotes the same sets of
|
||||
// locations.
|
||||
let definitely_conflicting_borrows = other_borrows_of_local
|
||||
.filter(|&i| {
|
||||
places_conflict(
|
||||
self.tcx,
|
||||
self.body,
|
||||
self.borrow_set[i].borrowed_place,
|
||||
place,
|
||||
PlaceConflictBias::NoOverlap,
|
||||
)
|
||||
})
|
||||
.filter(|&loan| filter_unreachable_kills(loan));
|
||||
|
||||
self.kills.entry(location).or_default().extend(definitely_conflicting_borrows);
|
||||
}
|
||||
|
||||
/// Records the borrows on the specified local as `killed`.
|
||||
fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) {
|
||||
if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
|
||||
self.kills.entry(location).or_default().extend(borrow_indices.iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for KillsCollector<'_, 'tcx> {
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
// Make sure there are no remaining borrows for locals that have gone out of scope.
|
||||
if let StatementKind::StorageDead(local) = statement.kind {
|
||||
self.record_killed_borrows_for_local(local, location);
|
||||
}
|
||||
|
||||
self.super_statement(statement, location);
|
||||
}
|
||||
|
||||
fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
|
||||
// When we see `X = ...`, then kill borrows of `(*X).foo` and so forth.
|
||||
self.record_killed_borrows_for_place(*place, location);
|
||||
self.super_assign(place, rvalue, location);
|
||||
}
|
||||
|
||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
||||
// A `Call` terminator's return value can be a local which has borrows, so we need to record
|
||||
// those as killed as well.
|
||||
if let TerminatorKind::Call { destination, .. } = terminator.kind {
|
||||
self.record_killed_borrows_for_place(destination, location);
|
||||
}
|
||||
|
||||
self.super_terminator(terminator, location);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,8 +146,8 @@ impl PoloniusContext {
|
|||
/// - converting NLL typeck constraints to be localized
|
||||
/// - encoding liveness constraints
|
||||
///
|
||||
/// Then, this graph is traversed, and combined with kills, reachability is recorded as loan
|
||||
/// liveness, to be used by the loan scope and active loans computations.
|
||||
/// Then, this graph is traversed, reachability is recorded as loan liveness, to be used by the
|
||||
/// loan scope and active loans computations.
|
||||
///
|
||||
/// The constraint data will be used to compute errors and diagnostics.
|
||||
pub(crate) fn compute_loan_liveness<'tcx>(
|
||||
|
|
@ -182,8 +182,6 @@ impl PoloniusContext {
|
|||
// Now that we have a complete graph, we can compute reachability to trace the liveness of
|
||||
// loans for the next step in the chain, the NLL loan scope and active loans computations.
|
||||
let live_loans = compute_loan_liveness(
|
||||
tcx,
|
||||
body,
|
||||
regioncx.liveness_constraints(),
|
||||
regioncx.outlives_constraints(),
|
||||
borrow_set,
|
||||
|
|
|
|||
|
|
@ -47,9 +47,7 @@ pub(super) fn convert_typeck_constraints<'tcx>(
|
|||
tcx,
|
||||
body,
|
||||
stmt,
|
||||
liveness,
|
||||
&outlives_constraint,
|
||||
location,
|
||||
point,
|
||||
universal_regions,
|
||||
)
|
||||
|
|
@ -78,9 +76,7 @@ fn localize_statement_constraint<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
stmt: &Statement<'tcx>,
|
||||
liveness: &LivenessValues,
|
||||
outlives_constraint: &OutlivesConstraint<'tcx>,
|
||||
current_location: Location,
|
||||
current_point: PointIndex,
|
||||
universal_regions: &UniversalRegions<'tcx>,
|
||||
) -> LocalizedOutlivesConstraint {
|
||||
|
|
@ -98,8 +94,8 @@ fn localize_statement_constraint<'tcx>(
|
|||
// - and that should be impossible in MIR
|
||||
//
|
||||
// When we have a more complete implementation in the future, tested with crater, etc,
|
||||
// we can relax this to a debug assert instead, or remove it.
|
||||
assert!(
|
||||
// we can remove this assertion. It's a debug assert because it can be expensive.
|
||||
debug_assert!(
|
||||
{
|
||||
let mut lhs_regions = FxHashSet::default();
|
||||
tcx.for_each_free_region(lhs, |region| {
|
||||
|
|
@ -119,16 +115,8 @@ fn localize_statement_constraint<'tcx>(
|
|||
"there should be no common regions between the LHS and RHS of an assignment"
|
||||
);
|
||||
|
||||
// As mentioned earlier, we should be tracking these better upstream but: we want to
|
||||
// relate the types on entry to the type of the place on exit. That is, outlives
|
||||
// constraints on the RHS are on entry, and outlives constraints to/from the LHS are on
|
||||
// exit (i.e. on entry to the successor location).
|
||||
let lhs_ty = body.local_decls[lhs.local].ty;
|
||||
let successor_location = Location {
|
||||
block: current_location.block,
|
||||
statement_index: current_location.statement_index + 1,
|
||||
};
|
||||
let successor_point = liveness.point_from_location(successor_location);
|
||||
let successor_point = current_point;
|
||||
compute_constraint_direction(
|
||||
tcx,
|
||||
outlives_constraint,
|
||||
|
|
@ -195,6 +183,7 @@ fn localize_terminator_constraint<'tcx>(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// For a given outlives constraint and CFG edge, returns the localized constraint with the
|
||||
/// appropriate `from`-`to` direction. This is computed according to whether the constraint flows to
|
||||
/// or from a free region in the given `value`, some kind of result for an effectful operation, like
|
||||
|
|
|
|||
|
|
@ -41,7 +41,22 @@ fn render_region_vid<'tcx>(
|
|||
"".to_string()
|
||||
};
|
||||
|
||||
format!("{:?}{universe_str}{external_name_str}", rvid)
|
||||
let extra_info = match regioncx.region_definition(rvid).origin {
|
||||
NllRegionVariableOrigin::FreeRegion => "".to_string(),
|
||||
NllRegionVariableOrigin::Placeholder(p) => match p.bound.kind {
|
||||
ty::BoundRegionKind::Named(def_id) => {
|
||||
format!(" (for<{}>)", tcx.item_name(def_id))
|
||||
}
|
||||
ty::BoundRegionKind::ClosureEnv | ty::BoundRegionKind::Anon => " (for<'_>)".to_string(),
|
||||
ty::BoundRegionKind::NamedAnon(_) => {
|
||||
bug!("only used for pretty printing")
|
||||
}
|
||||
},
|
||||
NllRegionVariableOrigin::Existential { name: Some(name), .. } => format!(" (ex<{name}>)"),
|
||||
NllRegionVariableOrigin::Existential { .. } => format!(" (ex<'_>)"),
|
||||
};
|
||||
|
||||
format!("{:?}{universe_str}{external_name_str}{extra_info}", rvid)
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ use crate::{
|
|||
|
||||
mod dump_mir;
|
||||
mod graphviz;
|
||||
mod opaque_types;
|
||||
pub(crate) mod opaque_types;
|
||||
mod reverse_sccs;
|
||||
|
||||
pub(crate) mod values;
|
||||
|
|
@ -417,7 +417,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
/// minimum values.
|
||||
///
|
||||
/// For example:
|
||||
/// ```
|
||||
/// ```ignore (illustrative)
|
||||
/// fn foo<'a, 'b>( /* ... */ ) where 'a: 'b { /* ... */ }
|
||||
/// ```
|
||||
/// would initialize two variables like so:
|
||||
|
|
@ -822,10 +822,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
continue;
|
||||
}
|
||||
|
||||
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements {
|
||||
if self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements) {
|
||||
continue;
|
||||
}
|
||||
if let Some(propagated_outlives_requirements) = &mut propagated_outlives_requirements
|
||||
&& self.try_promote_type_test(infcx, type_test, propagated_outlives_requirements)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Type-test failed. Report the error.
|
||||
|
|
@ -1479,40 +1479,36 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
shorter_fr: RegionVid,
|
||||
propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'tcx>>>,
|
||||
) -> RegionRelationCheckResult {
|
||||
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements {
|
||||
if let Some(propagated_outlives_requirements) = propagated_outlives_requirements
|
||||
// Shrink `longer_fr` until we find a non-local region (if we do).
|
||||
// We'll call it `fr-` -- it's ever so slightly smaller than
|
||||
// `longer_fr`.
|
||||
if let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
|
||||
{
|
||||
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
|
||||
&& let Some(fr_minus) = self.universal_region_relations.non_local_lower_bound(longer_fr)
|
||||
{
|
||||
debug!("try_propagate_universal_region_error: fr_minus={:?}", fr_minus);
|
||||
|
||||
let blame_span_category = self.find_outlives_blame_span(
|
||||
longer_fr,
|
||||
NllRegionVariableOrigin::FreeRegion,
|
||||
shorter_fr,
|
||||
);
|
||||
let blame_span_category = self.find_outlives_blame_span(
|
||||
longer_fr,
|
||||
NllRegionVariableOrigin::FreeRegion,
|
||||
shorter_fr,
|
||||
);
|
||||
|
||||
// Grow `shorter_fr` until we find some non-local regions. (We
|
||||
// always will.) We'll call them `shorter_fr+` -- they're ever
|
||||
// so slightly larger than `shorter_fr`.
|
||||
let shorter_fr_plus =
|
||||
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
|
||||
debug!(
|
||||
"try_propagate_universal_region_error: shorter_fr_plus={:?}",
|
||||
shorter_fr_plus
|
||||
);
|
||||
for fr in shorter_fr_plus {
|
||||
// Push the constraint `fr-: shorter_fr+`
|
||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
subject: ClosureOutlivesSubject::Region(fr_minus),
|
||||
outlived_free_region: fr,
|
||||
blame_span: blame_span_category.1.span,
|
||||
category: blame_span_category.0,
|
||||
});
|
||||
}
|
||||
return RegionRelationCheckResult::Propagated;
|
||||
// Grow `shorter_fr` until we find some non-local regions. (We
|
||||
// always will.) We'll call them `shorter_fr+` -- they're ever
|
||||
// so slightly larger than `shorter_fr`.
|
||||
let shorter_fr_plus =
|
||||
self.universal_region_relations.non_local_upper_bounds(shorter_fr);
|
||||
debug!("try_propagate_universal_region_error: shorter_fr_plus={:?}", shorter_fr_plus);
|
||||
for fr in shorter_fr_plus {
|
||||
// Push the constraint `fr-: shorter_fr+`
|
||||
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
|
||||
subject: ClosureOutlivesSubject::Region(fr_minus),
|
||||
outlived_free_region: fr,
|
||||
blame_span: blame_span_category.1.span,
|
||||
category: blame_span_category.0,
|
||||
});
|
||||
}
|
||||
return RegionRelationCheckResult::Propagated;
|
||||
}
|
||||
|
||||
RegionRelationCheckResult::Error
|
||||
|
|
@ -1944,9 +1940,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// and here we prefer to blame the source (the y = x statement).
|
||||
let blame_source = match from_region_origin {
|
||||
NllRegionVariableOrigin::FreeRegion
|
||||
| NllRegionVariableOrigin::Existential { from_forall: false } => true,
|
||||
| NllRegionVariableOrigin::Existential { from_forall: false, name: _ } => true,
|
||||
NllRegionVariableOrigin::Placeholder(_)
|
||||
| NllRegionVariableOrigin::Existential { from_forall: true } => false,
|
||||
| NllRegionVariableOrigin::Existential { from_forall: true, name: _ } => false,
|
||||
};
|
||||
|
||||
// To pick a constraint to blame, we organize constraints by how interesting we expect them
|
||||
|
|
@ -2085,11 +2081,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
let locations = self.scc_values.locations_outlived_by(scc);
|
||||
for location in locations {
|
||||
let bb = &body[location.block];
|
||||
if let Some(terminator) = &bb.terminator {
|
||||
if let Some(terminator) = &bb.terminator
|
||||
// terminator of a loop should be TerminatorKind::FalseUnwind
|
||||
if let TerminatorKind::FalseUnwind { .. } = terminator.kind {
|
||||
return Some(location);
|
||||
}
|
||||
&& let TerminatorKind::FalseUnwind { .. } = terminator.kind
|
||||
{
|
||||
return Some(location);
|
||||
}
|
||||
}
|
||||
None
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ use rustc_middle::ty::{
|
|||
TypeVisitableExt, fold_regions,
|
||||
};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::check_opaque_type_parameter_valid;
|
||||
use rustc_trait_selection::opaque_types::{
|
||||
InvalidOpaqueTypeArgs, check_opaque_type_parameter_valid,
|
||||
};
|
||||
use tracing::{debug, instrument};
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
|
|
@ -14,6 +16,11 @@ use crate::BorrowCheckRootCtxt;
|
|||
use crate::session_diagnostics::LifetimeMismatchOpaqueParam;
|
||||
use crate::universal_regions::RegionClassification;
|
||||
|
||||
pub(crate) enum DeferredOpaqueTypeError<'tcx> {
|
||||
InvalidOpaqueTypeArgs(InvalidOpaqueTypeArgs<'tcx>),
|
||||
LifetimeMismatchOpaqueParam(LifetimeMismatchOpaqueParam<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> RegionInferenceContext<'tcx> {
|
||||
/// Resolve any opaque types that were encountered while borrow checking
|
||||
/// this item. This is then used to get the type in the `type_of` query.
|
||||
|
|
@ -58,13 +65,14 @@ 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, root_cx, infcx), ret)]
|
||||
#[instrument(level = "debug", skip(self, root_cx, infcx))]
|
||||
pub(crate) fn infer_opaque_types(
|
||||
&self,
|
||||
root_cx: &mut BorrowCheckRootCtxt<'tcx>,
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
opaque_ty_decls: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
|
||||
) {
|
||||
) -> Vec<DeferredOpaqueTypeError<'tcx>> {
|
||||
let mut errors = Vec::new();
|
||||
let mut decls_modulo_regions: FxIndexMap<OpaqueTypeKey<'tcx>, (OpaqueTypeKey<'tcx>, Span)> =
|
||||
FxIndexMap::default();
|
||||
|
||||
|
|
@ -124,8 +132,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
});
|
||||
debug!(?concrete_type);
|
||||
|
||||
let ty =
|
||||
infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type);
|
||||
let ty = match infcx
|
||||
.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type)
|
||||
{
|
||||
Ok(ty) => ty,
|
||||
Err(err) => {
|
||||
errors.push(DeferredOpaqueTypeError::InvalidOpaqueTypeArgs(err));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Sometimes, when the hidden type is an inference variable, it can happen that
|
||||
// the hidden type becomes the opaque type itself. In this case, this was an opaque
|
||||
|
|
@ -149,25 +164,27 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
// 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
|
||||
// that don't hold.
|
||||
if !ty.references_error()
|
||||
&& let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
|
||||
infcx.tcx.erase_regions(opaque_type_key),
|
||||
(opaque_type_key, concrete_type.span),
|
||||
)
|
||||
&& let Some((arg1, arg2)) = std::iter::zip(
|
||||
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
|
||||
opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
|
||||
)
|
||||
.find(|(arg1, arg2)| arg1 != arg2)
|
||||
if let Some((prev_decl_key, prev_span)) = decls_modulo_regions.insert(
|
||||
infcx.tcx.erase_regions(opaque_type_key),
|
||||
(opaque_type_key, concrete_type.span),
|
||||
) && let Some((arg1, arg2)) = std::iter::zip(
|
||||
prev_decl_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
|
||||
opaque_type_key.iter_captured_args(infcx.tcx).map(|(_, arg)| arg),
|
||||
)
|
||||
.find(|(arg1, arg2)| arg1 != arg2)
|
||||
{
|
||||
infcx.dcx().emit_err(LifetimeMismatchOpaqueParam {
|
||||
arg: arg1,
|
||||
prev: arg2,
|
||||
span: prev_span,
|
||||
prev_span: concrete_type.span,
|
||||
});
|
||||
errors.push(DeferredOpaqueTypeError::LifetimeMismatchOpaqueParam(
|
||||
LifetimeMismatchOpaqueParam {
|
||||
arg: arg1,
|
||||
prev: arg2,
|
||||
span: prev_span,
|
||||
prev_span: concrete_type.span,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
errors
|
||||
}
|
||||
|
||||
/// Map the regions in the type to named regions. This is similar to what
|
||||
|
|
@ -260,19 +277,13 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
&self,
|
||||
opaque_type_key: OpaqueTypeKey<'tcx>,
|
||||
instantiated_ty: OpaqueHiddenType<'tcx>,
|
||||
) -> Ty<'tcx> {
|
||||
if let Some(e) = self.tainted_by_errors() {
|
||||
return Ty::new_error(self.tcx, e);
|
||||
}
|
||||
|
||||
if let Err(err) = check_opaque_type_parameter_valid(
|
||||
) -> Result<Ty<'tcx>, InvalidOpaqueTypeArgs<'tcx>> {
|
||||
check_opaque_type_parameter_valid(
|
||||
self,
|
||||
opaque_type_key,
|
||||
instantiated_ty.span,
|
||||
DefiningScopeKind::MirBorrowck,
|
||||
) {
|
||||
return Ty::new_error(self.tcx, err.report(self));
|
||||
}
|
||||
)?;
|
||||
|
||||
let definition_ty = instantiated_ty
|
||||
.remap_generic_params_to_declaration_params(
|
||||
|
|
@ -282,10 +293,7 @@ impl<'tcx> InferCtxt<'tcx> {
|
|||
)
|
||||
.ty;
|
||||
|
||||
if let Err(e) = definition_ty.error_reported() {
|
||||
return Ty::new_error(self.tcx, e);
|
||||
}
|
||||
|
||||
definition_ty
|
||||
definition_ty.error_reported()?;
|
||||
Ok(definition_ty)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
|
|||
T: TypeFoldable<TyCtxt<'tcx>>,
|
||||
F: Fn() -> RegionCtxt,
|
||||
{
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall: false };
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall: false, name: None };
|
||||
fold_regions(self.infcx.tcx, value, |_region, _depth| {
|
||||
self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
|
||||
})
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
// them with fresh ty vars.
|
||||
resume_ty: next_ty_var(),
|
||||
yield_ty: next_ty_var(),
|
||||
witness: next_ty_var(),
|
||||
},
|
||||
)
|
||||
.args,
|
||||
|
|
|
|||
|
|
@ -182,6 +182,17 @@ pub(crate) fn type_check<'tcx>(
|
|||
)
|
||||
});
|
||||
|
||||
// In case type check encountered an error region, we suppress unhelpful extra
|
||||
// errors in by clearing out all outlives bounds that we may end up checking.
|
||||
if let Some(guar) = universal_region_relations.universal_regions.encountered_re_error() {
|
||||
debug!("encountered an error region; removing constraints!");
|
||||
constraints.outlives_constraints = Default::default();
|
||||
constraints.member_constraints = Default::default();
|
||||
constraints.type_tests = Default::default();
|
||||
root_cx.set_tainted_by_errors(guar);
|
||||
infcx.set_tainted_by_errors(guar);
|
||||
}
|
||||
|
||||
MirTypeckResults {
|
||||
constraints,
|
||||
universal_region_relations,
|
||||
|
|
@ -669,24 +680,24 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
if let Some(annotation_index) = self.rvalue_user_ty(rv) {
|
||||
if let Err(terr) = self.relate_type_and_user_type(
|
||||
if let Some(annotation_index) = self.rvalue_user_ty(rv)
|
||||
&& let Err(terr) = self.relate_type_and_user_type(
|
||||
rv_ty,
|
||||
ty::Invariant,
|
||||
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
||||
location.to_locations(),
|
||||
ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg),
|
||||
) {
|
||||
let annotation = &self.user_type_annotations[annotation_index];
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
"bad user type on rvalue ({:?} = {:?}): {:?}",
|
||||
annotation,
|
||||
rv_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
)
|
||||
{
|
||||
let annotation = &self.user_type_annotations[annotation_index];
|
||||
span_mirbug!(
|
||||
self,
|
||||
stmt,
|
||||
"bad user type on rvalue ({:?} = {:?}): {:?}",
|
||||
annotation,
|
||||
rv_ty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
|
||||
if !self.unsized_feature_enabled() {
|
||||
|
|
@ -769,9 +780,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
TerminatorKind::Call { func, args, .. }
|
||||
| TerminatorKind::TailCall { func, args, .. } => {
|
||||
let call_source = match term.kind {
|
||||
TerminatorKind::Call { call_source, .. } => call_source,
|
||||
TerminatorKind::TailCall { .. } => CallSource::Normal,
|
||||
let (call_source, destination, is_diverging) = match term.kind {
|
||||
TerminatorKind::Call { call_source, destination, target, .. } => {
|
||||
(call_source, destination, target.is_none())
|
||||
}
|
||||
TerminatorKind::TailCall { .. } => {
|
||||
(CallSource::Normal, RETURN_PLACE.into(), false)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
@ -845,9 +860,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
if let TerminatorKind::Call { destination, target, .. } = term.kind {
|
||||
self.check_call_dest(term, &sig, destination, target, term_location);
|
||||
}
|
||||
self.check_call_dest(term, &sig, destination, is_diverging, term_location);
|
||||
|
||||
// The ordinary liveness rules will ensure that all
|
||||
// regions in the type of the callee are live here. We
|
||||
|
|
@ -1761,7 +1774,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
|
||||
assert!(!matches!(
|
||||
tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)),
|
||||
tcx.impl_of_assoc(def_id).map(|imp| tcx.def_kind(imp)),
|
||||
Some(DefKind::Impl { of_trait: true })
|
||||
));
|
||||
self.prove_predicates(
|
||||
|
|
@ -1874,65 +1887,61 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
term: &Terminator<'tcx>,
|
||||
sig: &ty::FnSig<'tcx>,
|
||||
destination: Place<'tcx>,
|
||||
target: Option<BasicBlock>,
|
||||
is_diverging: bool,
|
||||
term_location: Location,
|
||||
) {
|
||||
let tcx = self.tcx();
|
||||
match target {
|
||||
Some(_) => {
|
||||
let dest_ty = destination.ty(self.body, tcx).ty;
|
||||
let dest_ty = self.normalize(dest_ty, term_location);
|
||||
let category = match destination.as_local() {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) =
|
||||
self.universal_regions.defining_ty
|
||||
{
|
||||
if tcx.is_static(def_id) {
|
||||
ConstraintCategory::UseAsStatic
|
||||
} else {
|
||||
ConstraintCategory::UseAsConst
|
||||
}
|
||||
} else {
|
||||
ConstraintCategory::Return(ReturnConstraint::Normal)
|
||||
}
|
||||
}
|
||||
Some(l) if !self.body.local_decls[l].is_user_variable() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
// The return type of a call is interesting for diagnostics.
|
||||
_ => ConstraintCategory::Assignment,
|
||||
};
|
||||
|
||||
let locations = term_location.to_locations();
|
||||
|
||||
if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
"call dest mismatch ({:?} <- {:?}): {:?}",
|
||||
dest_ty,
|
||||
sig.output(),
|
||||
terr
|
||||
);
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` is not enabled,
|
||||
// this check is done at `check_local`.
|
||||
if self.unsized_feature_enabled() {
|
||||
let span = term.source_info.span;
|
||||
self.ensure_place_sized(dest_ty, span);
|
||||
}
|
||||
if is_diverging {
|
||||
// The signature in this call can reference region variables,
|
||||
// so erase them before calling a query.
|
||||
let output_ty = self.tcx().erase_regions(sig.output());
|
||||
if !output_ty
|
||||
.is_privately_uninhabited(self.tcx(), self.infcx.typing_env(self.infcx.param_env))
|
||||
{
|
||||
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||
}
|
||||
None => {
|
||||
// The signature in this call can reference region variables,
|
||||
// so erase them before calling a query.
|
||||
let output_ty = self.tcx().erase_regions(sig.output());
|
||||
if !output_ty.is_privately_uninhabited(
|
||||
self.tcx(),
|
||||
self.infcx.typing_env(self.infcx.param_env),
|
||||
) {
|
||||
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||
} else {
|
||||
let dest_ty = destination.ty(self.body, tcx).ty;
|
||||
let dest_ty = self.normalize(dest_ty, term_location);
|
||||
let category = match destination.as_local() {
|
||||
Some(RETURN_PLACE) => {
|
||||
if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) =
|
||||
self.universal_regions.defining_ty
|
||||
{
|
||||
if tcx.is_static(def_id) {
|
||||
ConstraintCategory::UseAsStatic
|
||||
} else {
|
||||
ConstraintCategory::UseAsConst
|
||||
}
|
||||
} else {
|
||||
ConstraintCategory::Return(ReturnConstraint::Normal)
|
||||
}
|
||||
}
|
||||
Some(l) if !self.body.local_decls[l].is_user_variable() => {
|
||||
ConstraintCategory::Boring
|
||||
}
|
||||
// The return type of a call is interesting for diagnostics.
|
||||
_ => ConstraintCategory::Assignment,
|
||||
};
|
||||
|
||||
let locations = term_location.to_locations();
|
||||
|
||||
if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
term,
|
||||
"call dest mismatch ({:?} <- {:?}): {:?}",
|
||||
dest_ty,
|
||||
sig.output(),
|
||||
terr
|
||||
);
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` is not enabled,
|
||||
// this check is done at `check_local`.
|
||||
if self.unsized_feature_enabled() {
|
||||
let span = term.source_info.span;
|
||||
self.ensure_place_sized(dest_ty, span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar| {
|
||||
consts: &mut |_bound_const: ty::BoundConst| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -226,7 +226,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
types: &mut |_bound_ty: ty::BoundTy| {
|
||||
unreachable!("we only replace regions in nll_relate, not types")
|
||||
},
|
||||
consts: &mut |_bound_var: ty::BoundVar| {
|
||||
consts: &mut |_bound_const: ty::BoundConst| {
|
||||
unreachable!("we only replace regions in nll_relate, not consts")
|
||||
},
|
||||
};
|
||||
|
|
@ -249,7 +249,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
|
|||
from_forall: bool,
|
||||
name: Option<Symbol>,
|
||||
) -> ty::Region<'tcx> {
|
||||
let origin = NllRegionVariableOrigin::Existential { from_forall };
|
||||
let origin = NllRegionVariableOrigin::Existential { name, from_forall };
|
||||
|
||||
let reg_var =
|
||||
self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ struct UniversalRegionIndices<'tcx> {
|
|||
|
||||
/// Whether we've encountered an error region. If we have, cancel all
|
||||
/// outlives errors, as they are likely bogus.
|
||||
pub tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
|
||||
pub encountered_re_error: Cell<Option<ErrorGuaranteed>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
|
@ -442,8 +442,8 @@ impl<'tcx> UniversalRegions<'tcx> {
|
|||
self.fr_fn_body
|
||||
}
|
||||
|
||||
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
|
||||
self.indices.tainted_by_errors.get()
|
||||
pub(crate) fn encountered_re_error(&self) -> Option<ErrorGuaranteed> {
|
||||
self.indices.encountered_re_error.get()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -706,7 +706,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
|||
UniversalRegionIndices {
|
||||
indices: global_mapping.chain(arg_mapping).collect(),
|
||||
fr_static,
|
||||
tainted_by_errors: Cell::new(None),
|
||||
encountered_re_error: Cell::new(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -916,7 +916,7 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
|
|||
match r.kind() {
|
||||
ty::ReVar(..) => r.as_var(),
|
||||
ty::ReError(guar) => {
|
||||
self.tainted_by_errors.set(Some(guar));
|
||||
self.encountered_re_error.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.
|
||||
|
|
@ -969,13 +969,28 @@ fn for_each_late_bound_region_in_item<'tcx>(
|
|||
mir_def_id: LocalDefId,
|
||||
mut f: impl FnMut(ty::Region<'tcx>),
|
||||
) {
|
||||
if !tcx.def_kind(mir_def_id).is_fn_like() {
|
||||
return;
|
||||
}
|
||||
let bound_vars = match tcx.def_kind(mir_def_id) {
|
||||
DefKind::Fn | DefKind::AssocFn => {
|
||||
tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id))
|
||||
}
|
||||
// We extract the bound vars from the deduced closure signature, since we may have
|
||||
// only deduced that a param in the closure signature is late-bound from a constraint
|
||||
// that we discover during typeck.
|
||||
DefKind::Closure => {
|
||||
let ty = tcx.type_of(mir_def_id).instantiate_identity();
|
||||
match *ty.kind() {
|
||||
ty::Closure(_, args) => args.as_closure().sig().bound_vars(),
|
||||
ty::CoroutineClosure(_, args) => {
|
||||
args.as_coroutine_closure().coroutine_closure_sig().bound_vars()
|
||||
}
|
||||
ty::Coroutine(_, _) | ty::Error(_) => return,
|
||||
_ => unreachable!("unexpected type for closure: {ty}"),
|
||||
}
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
for (idx, bound_var) in
|
||||
tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)).iter().enumerate()
|
||||
{
|
||||
for (idx, bound_var) in bound_vars.iter().enumerate() {
|
||||
if let ty::BoundVariableKind::Region(kind) = bound_var {
|
||||
let kind = ty::LateParamRegionKind::from_bound(ty::BoundVar::from_usize(idx), kind);
|
||||
let liberated_region = ty::Region::new_late_param(tcx, mir_def_id.to_def_id(), kind);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ doctest = false
|
|||
# tidy-alphabetical-start
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
|
||||
rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
|
||||
rustc_attr_parsing = { path = "../rustc_attr_parsing" }
|
||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||
rustc_errors = { path = "../rustc_errors" }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{
|
||||
self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind,
|
||||
};
|
||||
|
|
@ -46,7 +45,7 @@ pub(crate) fn expand(
|
|||
let const_body = ecx.expr_block(ecx.block(span, stmts));
|
||||
let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
|
||||
let const_item = if is_stmt {
|
||||
Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
|
||||
Annotatable::Stmt(Box::new(ecx.stmt_item(span, const_item)))
|
||||
} else {
|
||||
Annotatable::Item(const_item)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use lint::BuiltinLintDiag;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::tokenstream::TokenStream;
|
||||
use rustc_ast::{AsmMacro, token};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
|
|
@ -19,7 +18,7 @@ use crate::{errors, fluent_generated as fluent};
|
|||
|
||||
/// Validated assembly arguments, ready for macro expansion.
|
||||
struct ValidatedAsmArgs {
|
||||
pub templates: Vec<P<ast::Expr>>,
|
||||
pub templates: Vec<Box<ast::Expr>>,
|
||||
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
|
||||
named_args: FxIndexMap<Symbol, usize>,
|
||||
reg_args: GrowableBitSet<usize>,
|
||||
|
|
@ -600,9 +599,9 @@ pub(super) fn expand_asm<'cx>(
|
|||
return ExpandResult::Retry(());
|
||||
};
|
||||
let expr = match mac {
|
||||
Ok(inline_asm) => P(ast::Expr {
|
||||
Ok(inline_asm) => Box::new(ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||
kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)),
|
||||
span: sp,
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
|
|
@ -630,9 +629,9 @@ pub(super) fn expand_naked_asm<'cx>(
|
|||
return ExpandResult::Retry(());
|
||||
};
|
||||
let expr = match mac {
|
||||
Ok(inline_asm) => P(ast::Expr {
|
||||
Ok(inline_asm) => Box::new(ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::InlineAsm(P(inline_asm)),
|
||||
kind: ast::ExprKind::InlineAsm(Box::new(inline_asm)),
|
||||
span: sp,
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
|
|
@ -660,7 +659,7 @@ pub(super) fn expand_global_asm<'cx>(
|
|||
return ExpandResult::Retry(());
|
||||
};
|
||||
match mac {
|
||||
Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
|
||||
Ok(inline_asm) => MacEager::items(smallvec![Box::new(ast::Item {
|
||||
attrs: ast::AttrVec::new(),
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)),
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
mod context;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::Delimiter;
|
||||
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
|
||||
use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp, token};
|
||||
|
|
@ -55,9 +54,9 @@ pub(crate) fn expand_assert<'cx>(
|
|||
let expr = if let Some(tokens) = custom_message {
|
||||
let then = cx.expr(
|
||||
call_site_span,
|
||||
ExprKind::MacCall(P(MacCall {
|
||||
ExprKind::MacCall(Box::new(MacCall {
|
||||
path: panic_path(),
|
||||
args: P(DelimArgs {
|
||||
args: Box::new(DelimArgs {
|
||||
dspan: DelimSpan::from_single(call_site_span),
|
||||
delim: Delimiter::Parenthesis,
|
||||
tokens,
|
||||
|
|
@ -96,7 +95,7 @@ pub(crate) fn expand_assert<'cx>(
|
|||
}
|
||||
|
||||
struct Assert {
|
||||
cond_expr: P<Expr>,
|
||||
cond_expr: Box<Expr>,
|
||||
custom_message: Option<TokenStream>,
|
||||
}
|
||||
|
||||
|
|
@ -104,10 +103,10 @@ struct Assert {
|
|||
fn expr_if_not(
|
||||
cx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
cond: P<Expr>,
|
||||
then: P<Expr>,
|
||||
els: Option<P<Expr>>,
|
||||
) -> P<Expr> {
|
||||
cond: Box<Expr>,
|
||||
then: Box<Expr>,
|
||||
els: Option<Box<Expr>>,
|
||||
) -> Box<Expr> {
|
||||
cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
|
||||
}
|
||||
|
||||
|
|
|
|||
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