Merge pull request #4398 from rust-lang/rustup-2025-06-14
Automatic Rustup
This commit is contained in:
commit
974779746f
962 changed files with 16886 additions and 8809 deletions
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
|
@ -64,12 +64,18 @@ jobs:
|
|||
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||
with:
|
||||
workspaces: src/ci/citool
|
||||
- name: Test citool
|
||||
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
|
||||
# on PR/try builds.
|
||||
if: ${{ github.ref == 'refs/heads/auto' }}
|
||||
run: |
|
||||
cd src/ci/citool
|
||||
CARGO_INCREMENTAL=0 cargo test
|
||||
- name: Calculate the CI job matrix
|
||||
env:
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
run: |
|
||||
cd src/ci/citool
|
||||
CARGO_INCREMENTAL=0 cargo test
|
||||
CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT
|
||||
id: jobs
|
||||
job:
|
||||
|
|
|
|||
279
Cargo.lock
279
Cargo.lock
|
|
@ -80,9 +80,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
version = "0.6.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
|
|
@ -95,58 +95,58 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-lossy"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "934ff8719effd2023a48cf63e69536c1c3ced9d3895068f6f5cc9a4ff845e59b"
|
||||
checksum = "04d3a5dc826f84d0ea11882bb8054ff7f3d482602e11bb181101303a279ea01f"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-svg"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3607949e9f6de49ea4bafe12f5e4fd73613ebf24795e48587302a8cc0e4bb35"
|
||||
checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"anstyle-lossy",
|
||||
"anstyle-parse",
|
||||
"html-escape",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
|
|
@ -266,9 +266,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
|
|
@ -341,15 +341,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
version = "3.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
|
||||
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
|
|
@ -359,9 +359,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
|||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.9"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
|
||||
checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -487,9 +487,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.38"
|
||||
version = "4.5.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -507,9 +507,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.38"
|
||||
version = "4.5.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -642,16 +642,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "color-eyre"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec"
|
||||
checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"color-spantrace",
|
||||
"eyre",
|
||||
"indenter",
|
||||
"once_cell",
|
||||
"owo-colors 4.2.0",
|
||||
"owo-colors 4.2.1",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
|
|
@ -678,21 +678,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "color-spantrace"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5"
|
||||
checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"owo-colors 4.2.0",
|
||||
"owo-colors 4.2.1",
|
||||
"tracing-core",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
|
|
@ -851,9 +851,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "curl"
|
||||
version = "0.4.47"
|
||||
version = "0.4.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265"
|
||||
checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b"
|
||||
dependencies = [
|
||||
"curl-sys",
|
||||
"libc",
|
||||
|
|
@ -861,14 +861,14 @@ dependencies = [
|
|||
"openssl-sys",
|
||||
"schannel",
|
||||
"socket2",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.80+curl-8.12.1"
|
||||
version = "0.4.82+curl-8.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734"
|
||||
checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -876,7 +876,7 @@ dependencies = [
|
|||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1142,9 +1142,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.11"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
|
|
@ -1207,9 +1207,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
|
|
@ -1487,9 +1487,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
|
|
@ -1511,9 +1511,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
|
|
@ -1700,9 +1700,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
|||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
|
||||
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
|
|
@ -1716,9 +1716,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
|
||||
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
|
|
@ -1933,9 +1933,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
|
||||
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
|
|
@ -1946,9 +1946,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
|
||||
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2002,9 +2002,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jsonpath-rust"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9"
|
||||
checksum = "5b37465feaf9d41f74df7da98c6c1c31ca8ea06d11b5bf7869c8f1ccc51a793f"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
|
|
@ -2080,9 +2080,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
|
||||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.53.0",
|
||||
|
|
@ -2170,9 +2170,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
|
|
@ -2463,9 +2463,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
|
|
@ -2538,6 +2538,12 @@ version = "1.21.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.7.2"
|
||||
|
|
@ -2558,9 +2564,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.108"
|
||||
version = "0.9.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -2611,9 +2617,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
|||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "4.2.0"
|
||||
version = "4.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
||||
checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec"
|
||||
|
||||
[[package]]
|
||||
name = "pad"
|
||||
|
|
@ -2637,9 +2643,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
|
|
@ -2647,9 +2653,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.10"
|
||||
version = "0.9.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -2802,9 +2808,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
|
|
@ -3228,9 +3234,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc_apfloat"
|
||||
version = "0.2.2+llvm-462a31f5a5ab"
|
||||
version = "0.2.3+llvm-462a31f5a5ab"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f"
|
||||
checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"smallvec",
|
||||
|
|
@ -3787,6 +3793,7 @@ dependencies = [
|
|||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
|
|
@ -4768,9 +4775,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "ruzstd"
|
||||
|
|
@ -4866,9 +4873,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -4933,15 +4940,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
|
|
@ -5111,9 +5118,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.35.0"
|
||||
version = "0.35.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422"
|
||||
checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
|
|
@ -5354,9 +5361,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.45.0"
|
||||
version = "1.45.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
|
||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
|
@ -5386,9 +5393,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.9"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -5420,9 +5427,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.28"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -5504,11 +5511,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "type-map"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f"
|
||||
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
|
||||
dependencies = [
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5729,11 +5736,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5892,12 +5901,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.230.0"
|
||||
version = "0.233.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4349d0943718e6e434b51b9639e876293093dca4b96384fb136ab5bd5ce6660"
|
||||
checksum = "9679ae3cf7cfa2ca3a327f7fab97f27f3294d402fd1a76ca8ab514e17973e4d3"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.230.0",
|
||||
"wasmparser 0.233.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5935,17 +5944,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.230.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808198a69b5a0535583370a51d459baa14261dfab04800c4864ee9e1a14346ed"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.232.0"
|
||||
|
|
@ -5956,23 +5954,34 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "230.0.0"
|
||||
name = "wasmparser"
|
||||
version = "0.233.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8edac03c5fa691551531533928443faf3dc61a44f814a235c7ec5d17b7b34f1"
|
||||
checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "233.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eaf4099d8d0c922b83bf3c90663f5666f0769db9e525184284ebbbdb1dd2180"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.0",
|
||||
"wasm-encoder 0.230.0",
|
||||
"wasm-encoder 0.233.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.230.0"
|
||||
version = "1.233.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d77d62229e38db83eac32bacb5f61ebb952366ab0dae90cf2b3c07a65eea894"
|
||||
checksum = "3d9bc80f5e4b25ea086ef41b91ccd244adde45d931c384d94a8ff64ab8bd7d87"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
|
@ -6033,13 +6042,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.61.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90"
|
||||
checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6053,9 +6062,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.0"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
|
|
@ -6066,12 +6075,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
|
||||
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-link",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6114,18 +6124,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.2"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
|
@ -6204,6 +6214,15 @@ dependencies = [
|
|||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
|
|
|
|||
|
|
@ -381,6 +381,15 @@
|
|||
# "miri", "cargo-miri" # for dev/nightly channels
|
||||
#]
|
||||
|
||||
# Specify build configuration specific for some tool, such as enabled features.
|
||||
# This option has no effect on which tools are enabled: refer to the `tools` option for that.
|
||||
#
|
||||
# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]`
|
||||
#
|
||||
# The default value for the `features` array is `[]`. However, please note that other flags in
|
||||
# `bootstrap.toml` might influence the features enabled for some tools.
|
||||
#tool.TOOL_NAME.features = [FEATURE1, FEATURE2]
|
||||
|
||||
# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
|
||||
#verbose = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ pub enum CanonAbi {
|
|||
Rust,
|
||||
RustCold,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
||||
/// ABIs relevant to 32-bit Arm targets
|
||||
Arm(ArmCall),
|
||||
/// ABI relevant to GPUs: the entry point for a GPU kernel
|
||||
|
|
@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ pub enum ExternAbi {
|
|||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define. Functions with this ABI can
|
||||
/// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
|
||||
/// be called from inline assembly.
|
||||
Custom,
|
||||
|
||||
/// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
|
||||
/// and only valid on platforms that have a UEFI standard
|
||||
EfiApi,
|
||||
|
|
@ -141,6 +146,7 @@ abi_impls! {
|
|||
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
|
||||
Cdecl { unwind: false } =><= "cdecl",
|
||||
Cdecl { unwind: true } =><= "cdecl-unwind",
|
||||
Custom =><= "custom",
|
||||
EfiApi =><= "efiapi",
|
||||
Fastcall { unwind: false } =><= "fastcall",
|
||||
Fastcall { unwind: true } =><= "fastcall-unwind",
|
||||
|
|
|
|||
|
|
@ -97,12 +97,12 @@ pub struct Path {
|
|||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
// Succeeds if the path has a single segment that is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
if let [segment] = self.segments.as_ref()
|
||||
&& segment.args.is_none()
|
||||
&& segment.ident.name == *name
|
||||
&& segment == name
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
|
@ -111,6 +111,15 @@ impl PartialEq<Symbol> for Path {
|
|||
}
|
||||
}
|
||||
|
||||
// Succeeds if the path has segments that are arg-free and match the given symbols.
|
||||
impl PartialEq<&[Symbol]> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, names: &&[Symbol]) -> bool {
|
||||
self.segments.len() == names.len()
|
||||
&& self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.segments.len().hash_stable(hcx, hasher);
|
||||
|
|
@ -166,6 +175,14 @@ pub struct PathSegment {
|
|||
pub args: Option<P<GenericArgs>>,
|
||||
}
|
||||
|
||||
// Succeeds if the path segment is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for PathSegment {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
self.args.is_none() && self.ident.name == *name
|
||||
}
|
||||
}
|
||||
|
||||
impl PathSegment {
|
||||
pub fn from_ident(ident: Ident) -> Self {
|
||||
PathSegment { ident, id: DUMMY_NODE_ID, args: None }
|
||||
|
|
@ -1441,11 +1458,15 @@ impl Expr {
|
|||
}
|
||||
}
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Become(..) => ExprPrecedence::Jump,
|
||||
ExprKind::Break(_ /*label*/, value)
|
||||
| ExprKind::Ret(value)
|
||||
| ExprKind::Yield(YieldKind::Prefix(value))
|
||||
| ExprKind::Yeet(value) => match value {
|
||||
Some(_) => ExprPrecedence::Jump,
|
||||
None => ExprPrecedence::Unambiguous,
|
||||
},
|
||||
|
||||
ExprKind::Become(_) => ExprPrecedence::Jump,
|
||||
|
||||
// `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
|
||||
// parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
|
||||
|
|
@ -1502,6 +1523,7 @@ impl Expr {
|
|||
| ExprKind::Underscore
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Yield(YieldKind::Postfix(..))
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
}
|
||||
|
|
@ -3520,6 +3542,38 @@ impl FnHeader {
|
|||
|| matches!(constness, Const::Yes(_))
|
||||
|| !matches!(ext, Extern::None)
|
||||
}
|
||||
|
||||
/// Return a span encompassing the header, or none if all options are default.
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
fn append(a: &mut Option<Span>, b: Span) {
|
||||
*a = match a {
|
||||
None => Some(b),
|
||||
Some(x) => Some(x.to(b)),
|
||||
}
|
||||
}
|
||||
|
||||
let mut full_span = None;
|
||||
|
||||
match self.safety {
|
||||
Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
|
||||
Safety::Default => {}
|
||||
};
|
||||
|
||||
if let Some(coroutine_kind) = self.coroutine_kind {
|
||||
append(&mut full_span, coroutine_kind.span());
|
||||
}
|
||||
|
||||
if let Const::Yes(span) = self.constness {
|
||||
append(&mut full_span, span);
|
||||
}
|
||||
|
||||
match self.ext {
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
|
||||
Extern::None => {}
|
||||
}
|
||||
|
||||
full_span
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FnHeader {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::ops::DerefMut;
|
|||
use std::panic;
|
||||
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Ident, Span};
|
||||
use smallvec::{Array, SmallVec, smallvec};
|
||||
use thin_vec::ThinVec;
|
||||
|
|
@ -19,7 +19,7 @@ use thin_vec::ThinVec;
|
|||
use crate::ast::*;
|
||||
use crate::ptr::P;
|
||||
use crate::tokenstream::*;
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit, visit_opt, walk_list};
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list};
|
||||
|
||||
pub trait ExpectOne<A: Array> {
|
||||
fn expect_one(self, err: &'static str) -> A::Item;
|
||||
|
|
@ -32,7 +32,22 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MutVisitor: Sized {
|
||||
mod sealed {
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
|
||||
/// This is for compatibility with the regular `Visitor`.
|
||||
pub trait MutVisitorResult {
|
||||
type Result: VisitorResult;
|
||||
}
|
||||
|
||||
impl<T> MutVisitorResult for T {
|
||||
type Result = ();
|
||||
}
|
||||
}
|
||||
|
||||
use sealed::MutVisitorResult;
|
||||
|
||||
pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
|
||||
// Methods in this trait have one of three forms:
|
||||
//
|
||||
// fn visit_t(&mut self, t: &mut T); // common
|
||||
|
|
@ -227,14 +242,6 @@ pub trait MutVisitor: Sized {
|
|||
walk_generic_args(self, p);
|
||||
}
|
||||
|
||||
fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) {
|
||||
walk_angle_bracketed_parameter_data(self, p);
|
||||
}
|
||||
|
||||
fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) {
|
||||
walk_parenthesized_parameter_data(self, p);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &mut Local) {
|
||||
walk_local(self, l);
|
||||
}
|
||||
|
|
@ -303,10 +310,6 @@ pub trait MutVisitor: Sized {
|
|||
walk_flat_map_expr_field(self, f)
|
||||
}
|
||||
|
||||
fn visit_where_clause(&mut self, where_clause: &mut WhereClause) {
|
||||
walk_where_clause(self, where_clause);
|
||||
}
|
||||
|
||||
fn flat_map_where_predicate(
|
||||
&mut self,
|
||||
where_predicate: WherePredicate,
|
||||
|
|
@ -385,19 +388,14 @@ generate_flat_map_visitor_fns! {
|
|||
visit_generic_params, GenericParam, flat_map_generic_param;
|
||||
visit_stmts, Stmt, flat_map_stmt;
|
||||
visit_exprs, P<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;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F)
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
for elem in elems {
|
||||
visit_elem(elem);
|
||||
}
|
||||
visit_where_predicates, WherePredicate, flat_map_where_predicate;
|
||||
visit_params, Param, flat_map_param;
|
||||
visit_field_defs, FieldDef, flat_map_field_def;
|
||||
visit_arms, Arm, flat_map_arm;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -410,40 +408,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F)
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
if let Some(elem) = opt {
|
||||
visit_elem(elem);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) {
|
||||
for attr in attrs.iter_mut() {
|
||||
vis.visit_attribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
|
||||
match args {
|
||||
AttrArgs::Empty => {}
|
||||
AttrArgs::Delimited(args) => visit_delim_args(vis, args),
|
||||
AttrArgs::Eq { eq_span, expr } => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_span(eq_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) {
|
||||
let DelimArgs { dspan, delim: _, tokens: _ } = args;
|
||||
let DelimSpan { open, close } = dspan;
|
||||
vis.visit_span(open);
|
||||
vis.visit_span(close);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_pat_field<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut fp: PatField,
|
||||
|
|
@ -461,40 +431,11 @@ fn visit_nested_use_tree<V: MutVisitor>(
|
|||
vis.visit_use_tree(nested_tree);
|
||||
}
|
||||
|
||||
pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) {
|
||||
let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_pat(pat);
|
||||
visit_opt(guard, |guard| vis.visit_expr(guard));
|
||||
visit_opt(body, |body| vis.visit_expr(body));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
|
||||
vis.visit_arm(&mut arm);
|
||||
smallvec![arm]
|
||||
}
|
||||
|
||||
fn walk_assoc_item_constraint<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint,
|
||||
) {
|
||||
vis.visit_id(id);
|
||||
vis.visit_ident(ident);
|
||||
if let Some(gen_args) = gen_args {
|
||||
vis.visit_generic_args(gen_args);
|
||||
}
|
||||
match kind {
|
||||
AssocItemConstraintKind::Equality { term } => match term {
|
||||
Term::Ty(ty) => vis.visit_ty(ty),
|
||||
Term::Const(c) => vis.visit_anon_const(c),
|
||||
},
|
||||
AssocItemConstraintKind::Bound { bounds } => visit_bounds(vis, bounds, BoundKind::Bound),
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_variant<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut variant: Variant,
|
||||
|
|
@ -503,64 +444,6 @@ pub fn walk_flat_map_variant<T: MutVisitor>(
|
|||
smallvec![variant]
|
||||
}
|
||||
|
||||
fn walk_generic_args<T: MutVisitor>(vis: &mut T, generic_args: &mut GenericArgs) {
|
||||
match generic_args {
|
||||
GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
|
||||
GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
|
||||
GenericArgs::ParenthesizedElided(span) => vis.visit_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_generic_arg<T: MutVisitor>(vis: &mut T, arg: &mut GenericArg) {
|
||||
match arg {
|
||||
GenericArg::Lifetime(lt) => vis.visit_lifetime(lt),
|
||||
GenericArg::Type(ty) => vis.visit_ty(ty),
|
||||
GenericArg::Const(ct) => vis.visit_anon_const(ct),
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut AngleBracketedArgs) {
|
||||
let AngleBracketedArgs { args, span } = data;
|
||||
visit_thin_vec(args, |arg| match arg {
|
||||
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
|
||||
AngleBracketedArg::Constraint(constraint) => vis.visit_assoc_item_constraint(constraint),
|
||||
});
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
|
||||
let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
|
||||
visit_thin_vec(inputs, |input| vis.visit_ty(input));
|
||||
vis.visit_fn_ret_ty(output);
|
||||
vis.visit_span(span);
|
||||
vis.visit_span(inputs_span);
|
||||
}
|
||||
|
||||
fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
|
||||
let Attribute { kind, id: _, style: _, span } = attr;
|
||||
match kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
let NormalAttr { item: AttrItem { unsafety: _, path, args, tokens: _ }, tokens: _ } =
|
||||
&mut **normal;
|
||||
vis.visit_path(path);
|
||||
visit_attr_args(vis, args);
|
||||
}
|
||||
AttrKind::DocComment(_kind, _sym) => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_mac<T: MutVisitor>(vis: &mut T, mac: &mut MacCall) {
|
||||
let MacCall { path, args } = mac;
|
||||
vis.visit_path(path);
|
||||
visit_delim_args(vis, args);
|
||||
}
|
||||
|
||||
fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) {
|
||||
let MacroDef { body, macro_rules: _ } = macro_def;
|
||||
visit_delim_args(vis, body);
|
||||
}
|
||||
|
||||
fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut MetaItemInner) {
|
||||
match li {
|
||||
MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi),
|
||||
|
|
@ -578,138 +461,11 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
|
|||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) {
|
||||
let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_ty(ty);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
|
||||
vis.visit_param(&mut param);
|
||||
smallvec![param]
|
||||
}
|
||||
|
||||
fn walk_closure_binder<T: MutVisitor>(vis: &mut T, binder: &mut ClosureBinder) {
|
||||
match binder {
|
||||
ClosureBinder::NotPresent => {}
|
||||
ClosureBinder::For { span: _, generic_params } => {
|
||||
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||
match kind {
|
||||
FnKind::Fn(
|
||||
_ctxt,
|
||||
_vis,
|
||||
Fn {
|
||||
defaultness,
|
||||
ident,
|
||||
generics,
|
||||
contract,
|
||||
body,
|
||||
sig: FnSig { header, decl, span },
|
||||
define_opaque,
|
||||
},
|
||||
) => {
|
||||
// Visibility is visited as a part of the item.
|
||||
visit_defaultness(vis, defaultness);
|
||||
vis.visit_ident(ident);
|
||||
vis.visit_fn_header(header);
|
||||
vis.visit_generics(generics);
|
||||
vis.visit_fn_decl(decl);
|
||||
if let Some(contract) = contract {
|
||||
vis.visit_contract(contract);
|
||||
}
|
||||
if let Some(body) = body {
|
||||
vis.visit_block(body);
|
||||
}
|
||||
vis.visit_span(span);
|
||||
|
||||
walk_define_opaques(vis, define_opaque);
|
||||
}
|
||||
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||
vis.visit_closure_binder(binder);
|
||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||
vis.visit_fn_decl(decl);
|
||||
vis.visit_expr(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut FnContract) {
|
||||
let FnContract { requires, ensures } = contract;
|
||||
if let Some(pred) = requires {
|
||||
vis.visit_expr(pred);
|
||||
}
|
||||
if let Some(pred) = ensures {
|
||||
vis.visit_expr(pred);
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut FnDecl) {
|
||||
let FnDecl { inputs, output } = decl;
|
||||
inputs.flat_map_in_place(|param| vis.flat_map_param(param));
|
||||
vis.visit_fn_ret_ty(output);
|
||||
}
|
||||
|
||||
fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
|
||||
match fn_ret_ty {
|
||||
FnRetTy::Default(span) => vis.visit_span(span),
|
||||
FnRetTy::Ty(ty) => vis.visit_ty(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_param_bound<T: MutVisitor>(vis: &mut T, pb: &mut GenericBound) {
|
||||
match pb {
|
||||
GenericBound::Trait(trait_ref) => vis.visit_poly_trait_ref(trait_ref),
|
||||
GenericBound::Outlives(lifetime) => walk_lifetime(vis, lifetime),
|
||||
GenericBound::Use(args, span) => {
|
||||
for arg in args {
|
||||
vis.visit_precise_capturing_arg(arg);
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCapturingArg) {
|
||||
match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => {
|
||||
vis.visit_lifetime(lt);
|
||||
}
|
||||
PreciseCapturingArg::Arg(path, id) => {
|
||||
vis.visit_id(id);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) {
|
||||
let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_ident(ident);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
match kind {
|
||||
GenericParamKind::Lifetime => {}
|
||||
GenericParamKind::Type { default } => {
|
||||
visit_opt(default, |default| vis.visit_ty(default));
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||
vis.visit_ty(ty);
|
||||
visit_opt(default, |default| vis.visit_anon_const(default));
|
||||
}
|
||||
}
|
||||
if let Some(colon_span) = colon_span {
|
||||
vis.visit_span(colon_span);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_generic_param<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut param: GenericParam,
|
||||
|
|
@ -718,13 +474,6 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>(
|
|||
smallvec![param]
|
||||
}
|
||||
|
||||
fn walk_generics<T: MutVisitor>(vis: &mut T, generics: &mut Generics) {
|
||||
let Generics { params, where_clause, span } = generics;
|
||||
params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_where_clause(where_clause);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) {
|
||||
let TyAliasWhereClauses { before, after, split: _ } = tawcs;
|
||||
let TyAliasWhereClause { has_where_token: _, span: span_before } = before;
|
||||
|
|
@ -733,70 +482,14 @@ fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWh
|
|||
vis.visit_span(span_after);
|
||||
}
|
||||
|
||||
fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) {
|
||||
let WhereClause { has_where_token: _, predicates, span } = wc;
|
||||
predicates.flat_map_in_place(|predicate| vis.flat_map_where_predicate(predicate));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_where_predicate<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut pred: WherePredicate,
|
||||
) -> SmallVec<[WherePredicate; 1]> {
|
||||
let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = &mut pred;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_where_predicate_kind(kind);
|
||||
vis.visit_span(span);
|
||||
walk_where_predicate(vis, &mut pred);
|
||||
smallvec![pred]
|
||||
}
|
||||
|
||||
pub fn walk_where_predicate_kind<T: MutVisitor>(vis: &mut T, kind: &mut WherePredicateKind) {
|
||||
match kind {
|
||||
WherePredicateKind::BoundPredicate(bp) => {
|
||||
let WhereBoundPredicate { bound_generic_params, bounded_ty, bounds } = bp;
|
||||
bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_ty(bounded_ty);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
}
|
||||
WherePredicateKind::RegionPredicate(rp) => {
|
||||
let WhereRegionPredicate { lifetime, bounds } = rp;
|
||||
vis.visit_lifetime(lifetime);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
}
|
||||
WherePredicateKind::EqPredicate(ep) => {
|
||||
let WhereEqPredicate { lhs_ty, rhs_ty } = ep;
|
||||
vis.visit_ty(lhs_ty);
|
||||
vis.visit_ty(rhs_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_variant_data<T: MutVisitor>(vis: &mut T, vdata: &mut VariantData) {
|
||||
match vdata {
|
||||
VariantData::Struct { fields, recovered: _ } => {
|
||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||
}
|
||||
VariantData::Tuple(fields, id) => {
|
||||
vis.visit_id(id);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||
}
|
||||
VariantData::Unit(id) => vis.visit_id(id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd;
|
||||
visitor.visit_id(id);
|
||||
visit_attrs(visitor, attrs);
|
||||
visitor.visit_vis(vis);
|
||||
visit_safety(visitor, safety);
|
||||
visit_opt(ident, |ident| visitor.visit_ident(ident));
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(default, |default| visitor.visit_anon_const(default));
|
||||
visitor.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_field_def<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut fd: FieldDef,
|
||||
|
|
@ -846,255 +539,6 @@ pub fn walk_flat_map_assoc_item(
|
|||
smallvec![item]
|
||||
}
|
||||
|
||||
fn walk_inline_asm<T: MutVisitor>(vis: &mut T, asm: &mut InlineAsm) {
|
||||
// FIXME: Visit spans inside all this currently ignored stuff.
|
||||
let InlineAsm {
|
||||
asm_macro: _,
|
||||
template: _,
|
||||
template_strs: _,
|
||||
operands,
|
||||
clobber_abis: _,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
} = asm;
|
||||
for (op, span) in operands {
|
||||
match op {
|
||||
InlineAsmOperand::In { expr, reg: _ }
|
||||
| InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
|
||||
| InlineAsmOperand::InOut { expr, reg: _, late: _ } => vis.visit_expr(expr),
|
||||
InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
|
||||
InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
|
||||
vis.visit_expr(in_expr);
|
||||
if let Some(out_expr) = out_expr {
|
||||
vis.visit_expr(out_expr);
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
|
||||
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
|
||||
InlineAsmOperand::Label { block } => vis.visit_block(block),
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_inline_asm_sym<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
InlineAsmSym { id, qself, path }: &mut InlineAsmSym,
|
||||
) {
|
||||
vis.visit_id(id);
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
|
||||
fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) {
|
||||
// FIXME: visit the template exhaustively.
|
||||
let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt;
|
||||
for FormatArgument { kind, expr } in arguments.all_args_mut() {
|
||||
match kind {
|
||||
FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
|
||||
vis.visit_ident(ident)
|
||||
}
|
||||
FormatArgumentKind::Normal => {}
|
||||
}
|
||||
vis.visit_expr(expr);
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, tokens: _ }: &mut Expr) {
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
match kind {
|
||||
ExprKind::Array(exprs) => visit_exprs(vis, exprs),
|
||||
ExprKind::ConstBlock(anon_const) => {
|
||||
vis.visit_anon_const(anon_const);
|
||||
}
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_anon_const(count);
|
||||
}
|
||||
ExprKind::Tup(exprs) => visit_exprs(vis, exprs),
|
||||
ExprKind::Call(f, args) => {
|
||||
vis.visit_expr(f);
|
||||
visit_exprs(vis, args);
|
||||
}
|
||||
ExprKind::MethodCall(box MethodCall {
|
||||
seg: PathSegment { ident, id, args: seg_args },
|
||||
receiver,
|
||||
args: call_args,
|
||||
span,
|
||||
}) => {
|
||||
vis.visit_method_receiver_expr(receiver);
|
||||
vis.visit_id(id);
|
||||
vis.visit_ident(ident);
|
||||
visit_opt(seg_args, |args| vis.visit_generic_args(args));
|
||||
visit_exprs(vis, call_args);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Binary(binop, lhs, rhs) => {
|
||||
vis.visit_expr(lhs);
|
||||
vis.visit_expr(rhs);
|
||||
vis.visit_span(&mut binop.span);
|
||||
}
|
||||
ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
ExprKind::Type(expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
ExprKind::AddrOf(_kind, _mut, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::Let(pat, scrutinee, span, _recovered) => {
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_expr(scrutinee);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::If(cond, tr, fl) => {
|
||||
vis.visit_expr(cond);
|
||||
vis.visit_block(tr);
|
||||
visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl)));
|
||||
}
|
||||
ExprKind::While(cond, body, label) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_expr(cond);
|
||||
vis.visit_block(body);
|
||||
}
|
||||
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_expr(iter);
|
||||
vis.visit_block(body);
|
||||
}
|
||||
ExprKind::Loop(body, label, span) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_block(body);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Match(expr, arms, _kind) => {
|
||||
vis.visit_expr(expr);
|
||||
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
|
||||
}
|
||||
ExprKind::Closure(box Closure {
|
||||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
coroutine_kind,
|
||||
movability: _,
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span,
|
||||
fn_arg_span,
|
||||
}) => {
|
||||
visit_constness(vis, constness);
|
||||
vis.visit_capture_by(capture_clause);
|
||||
vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
|
||||
vis.visit_span(fn_decl_span);
|
||||
vis.visit_span(fn_arg_span);
|
||||
}
|
||||
ExprKind::Block(blk, label) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_block(blk);
|
||||
}
|
||||
ExprKind::Gen(_capture_by, body, _kind, decl_span) => {
|
||||
vis.visit_block(body);
|
||||
vis.visit_span(decl_span);
|
||||
}
|
||||
ExprKind::Await(expr, await_kw_span) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_span(await_kw_span);
|
||||
}
|
||||
ExprKind::Use(expr, use_kw_span) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_span(use_kw_span);
|
||||
}
|
||||
ExprKind::Assign(el, er, span) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_expr(er);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::AssignOp(_op, el, er) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_expr(er);
|
||||
}
|
||||
ExprKind::Field(el, ident) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_ident(ident);
|
||||
}
|
||||
ExprKind::Index(el, er, brackets_span) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_expr(er);
|
||||
vis.visit_span(brackets_span);
|
||||
}
|
||||
ExprKind::Range(e1, e2, _lim) => {
|
||||
visit_opt(e1, |e1| vis.visit_expr(e1));
|
||||
visit_opt(e2, |e2| vis.visit_expr(e2));
|
||||
}
|
||||
ExprKind::Underscore => {}
|
||||
ExprKind::Path(qself, path) => {
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
ExprKind::Break(label, expr) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::Continue(label) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
}
|
||||
ExprKind::Ret(expr) => {
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::Yeet(expr) => {
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::Become(expr) => vis.visit_expr(expr),
|
||||
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
|
||||
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
|
||||
ExprKind::OffsetOf(container, fields) => {
|
||||
vis.visit_ty(container);
|
||||
for field in fields.iter_mut() {
|
||||
vis.visit_ident(field);
|
||||
}
|
||||
}
|
||||
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
ExprKind::Struct(se) => {
|
||||
let StructExpr { qself, path, fields, rest } = se.deref_mut();
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_expr_field(field));
|
||||
match rest {
|
||||
StructRest::Base(expr) => vis.visit_expr(expr),
|
||||
StructRest::Rest(_span) => {}
|
||||
StructRest::None => {}
|
||||
}
|
||||
}
|
||||
ExprKind::Paren(expr) => {
|
||||
vis.visit_expr(expr);
|
||||
}
|
||||
ExprKind::Yield(kind) => {
|
||||
let expr = kind.expr_mut();
|
||||
if let Some(expr) = expr {
|
||||
vis.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
ExprKind::Try(expr) => vis.visit_expr(expr),
|
||||
ExprKind::TryBlock(body) => vis.visit_block(body),
|
||||
ExprKind::Lit(_token) => {}
|
||||
ExprKind::IncludedBytes(_bytes) => {}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
if let Some(ty) = ty {
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
ExprKind::Err(_guar) => {}
|
||||
ExprKind::Dummy => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
|
||||
vis.visit_expr(&mut e);
|
||||
Some(e)
|
||||
|
|
@ -1139,18 +583,6 @@ fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallV
|
|||
}
|
||||
}
|
||||
|
||||
fn walk_vis<T: MutVisitor>(vis: &mut T, visibility: &mut Visibility) {
|
||||
let Visibility { kind, span, tokens: _ } = visibility;
|
||||
match kind {
|
||||
VisibilityKind::Public | VisibilityKind::Inherited => {}
|
||||
VisibilityKind::Restricted { path, id, shorthand: _ } => {
|
||||
vis.visit_id(id);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
|
||||
match capture_by {
|
||||
CaptureBy::Ref => {}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -73,16 +73,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
// Merge attributes into the inner expression.
|
||||
if !e.attrs.is_empty() {
|
||||
let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);
|
||||
let attrs = &*self.arena.alloc_from_iter(
|
||||
self.lower_attrs_vec(&e.attrs, e.span)
|
||||
.into_iter()
|
||||
.chain(old_attrs.iter().cloned()),
|
||||
);
|
||||
if attrs.is_empty() {
|
||||
let new_attrs = self
|
||||
.lower_attrs_vec(&e.attrs, e.span, ex.hir_id)
|
||||
.into_iter()
|
||||
.chain(old_attrs.iter().cloned());
|
||||
let new_attrs = &*self.arena.alloc_from_iter(new_attrs);
|
||||
if new_attrs.is_empty() {
|
||||
return ex;
|
||||
}
|
||||
|
||||
self.attrs.insert(ex.hir_id.local_id, attrs);
|
||||
self.attrs.insert(ex.hir_id.local_id, new_attrs);
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
|
@ -2035,7 +2034,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
let ret_expr = self.checked_return(Some(from_residual_expr));
|
||||
self.arena.alloc(self.expr(try_span, ret_expr))
|
||||
};
|
||||
self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span);
|
||||
self.lower_attrs(ret_expr.hir_id, &attrs, span);
|
||||
|
||||
let break_pat = self.pat_cf_break(try_span, residual_local);
|
||||
self.arm(break_pat, ret_expr)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
|
||||
for (def_id, info) in lctx.children {
|
||||
let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
|
||||
debug_assert!(
|
||||
assert!(
|
||||
matches!(owner, hir::MaybeOwner::Phantom),
|
||||
"duplicate copy of {def_id:?} in lctx.children"
|
||||
);
|
||||
|
|
@ -78,7 +78,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
|
|||
match node {
|
||||
AstOwner::NonOwner => {}
|
||||
AstOwner::Crate(c) => {
|
||||
debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
|
||||
assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
|
||||
self.with_lctx(CRATE_NODE_ID, |lctx| {
|
||||
let module = lctx.lower_mod(&c.items, &c.spans);
|
||||
// FIXME(jdonszelman): is dummy span ever a problem here?
|
||||
|
|
@ -1160,7 +1160,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
) -> hir::BodyId {
|
||||
let body = hir::Body { params, value: self.arena.alloc(value) };
|
||||
let id = body.id();
|
||||
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
||||
assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
|
||||
self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
|
||||
id
|
||||
}
|
||||
|
|
@ -1673,8 +1673,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
itctx: ImplTraitContext,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> (&'hir hir::Generics<'hir>, T) {
|
||||
debug_assert!(self.impl_trait_defs.is_empty());
|
||||
debug_assert!(self.impl_trait_bounds.is_empty());
|
||||
assert!(self.impl_trait_defs.is_empty());
|
||||
assert!(self.impl_trait_bounds.is_empty());
|
||||
|
||||
// Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
|
||||
// Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
|
|||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::{
|
||||
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
|
||||
LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
|
||||
|
|
@ -141,6 +142,8 @@ struct LoweringContext<'a, 'hir> {
|
|||
allow_for_await: Arc<[Symbol]>,
|
||||
allow_async_fn_traits: Arc<[Symbol]>,
|
||||
|
||||
delayed_lints: Vec<DelayedLint>,
|
||||
|
||||
attribute_parser: AttributeParser<'hir>,
|
||||
}
|
||||
|
||||
|
|
@ -190,6 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
|
||||
attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
|
||||
delayed_lints: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -198,6 +202,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SpanLowerer {
|
||||
is_incremental: bool,
|
||||
def_id: LocalDefId,
|
||||
}
|
||||
|
||||
impl SpanLowerer {
|
||||
fn lower(&self, span: Span) -> Span {
|
||||
if self.is_incremental {
|
||||
span.with_parent(Some(self.def_id))
|
||||
} else {
|
||||
// Do not make spans relative when not using incremental compilation.
|
||||
span
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[extension(trait ResolverAstLoweringExt)]
|
||||
impl ResolverAstLowering {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
|
||||
|
|
@ -503,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: Span,
|
||||
) -> LocalDefId {
|
||||
let parent = self.current_hir_id_owner.def_id;
|
||||
debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
|
||||
assert_ne!(node_id, ast::DUMMY_NODE_ID);
|
||||
assert!(
|
||||
self.opt_local_def_id(node_id).is_none(),
|
||||
"adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}",
|
||||
|
|
@ -573,6 +593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
|
||||
let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
|
||||
let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
|
||||
let current_delayed_lints = std::mem::take(&mut self.delayed_lints);
|
||||
|
||||
// Do not reset `next_node_id` and `node_id_to_def_id`:
|
||||
// we want `f` to be able to refer to the `LocalDefId`s that the caller created.
|
||||
|
|
@ -586,10 +607,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
let item = f(self);
|
||||
debug_assert_eq!(owner_id, item.def_id());
|
||||
assert_eq!(owner_id, item.def_id());
|
||||
// `f` should have consumed all the elements in these vectors when constructing `item`.
|
||||
debug_assert!(self.impl_trait_defs.is_empty());
|
||||
debug_assert!(self.impl_trait_bounds.is_empty());
|
||||
assert!(self.impl_trait_defs.is_empty());
|
||||
assert!(self.impl_trait_bounds.is_empty());
|
||||
let info = self.make_owner_info(item);
|
||||
|
||||
self.attrs = current_attrs;
|
||||
|
|
@ -606,6 +627,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.item_local_id_counter = current_local_counter;
|
||||
self.impl_trait_defs = current_impl_trait_defs;
|
||||
self.impl_trait_bounds = current_impl_trait_bounds;
|
||||
self.delayed_lints = current_delayed_lints;
|
||||
|
||||
debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id));
|
||||
self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info)));
|
||||
|
|
@ -616,6 +638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
let define_opaque = std::mem::take(&mut self.define_opaque);
|
||||
let trait_map = std::mem::take(&mut self.trait_map);
|
||||
let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (id, attrs) in attrs.iter() {
|
||||
|
|
@ -629,14 +652,16 @@ 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) =
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
|
||||
let (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);
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
|
||||
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
|
||||
let delayed_lints =
|
||||
hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash };
|
||||
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints })
|
||||
}
|
||||
|
||||
/// This method allocates a new `HirId` for the given `NodeId`.
|
||||
|
|
@ -759,15 +784,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
})
|
||||
}
|
||||
|
||||
fn span_lowerer(&self) -> SpanLowerer {
|
||||
SpanLowerer {
|
||||
is_incremental: self.tcx.sess.opts.incremental.is_some(),
|
||||
def_id: self.current_hir_id_owner.def_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Intercept all spans entering HIR.
|
||||
/// Mark a span as relative to the current owning item.
|
||||
fn lower_span(&self, span: Span) -> Span {
|
||||
if self.tcx.sess.opts.incremental.is_some() {
|
||||
span.with_parent(Some(self.current_hir_id_owner.def_id))
|
||||
} else {
|
||||
// Do not make spans relative when not using incremental compilation.
|
||||
span
|
||||
}
|
||||
self.span_lowerer().lower(span)
|
||||
}
|
||||
|
||||
fn lower_ident(&self, ident: Ident) -> Ident {
|
||||
|
|
@ -889,9 +916,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
if attrs.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
|
||||
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id);
|
||||
|
||||
debug_assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
let ret = self.arena.alloc_from_iter(lowered_attrs);
|
||||
|
||||
// this is possible if an item contained syntactical attribute,
|
||||
|
|
@ -909,16 +936,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> {
|
||||
self.attribute_parser
|
||||
.parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s))
|
||||
fn lower_attrs_vec(
|
||||
&mut self,
|
||||
attrs: &[Attribute],
|
||||
target_span: Span,
|
||||
target_hir_id: HirId,
|
||||
) -> Vec<hir::Attribute> {
|
||||
let l = self.span_lowerer();
|
||||
self.attribute_parser.parse_attribute_list(
|
||||
attrs,
|
||||
target_span,
|
||||
target_hir_id,
|
||||
OmitDoc::Lower,
|
||||
|s| l.lower(s),
|
||||
|l| {
|
||||
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
|
||||
debug_assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
|
||||
assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
assert_eq!(target_id.owner, self.current_hir_id_owner);
|
||||
if let Some(&a) = self.attrs.get(&target_id.local_id) {
|
||||
debug_assert!(!a.is_empty());
|
||||
assert!(!a.is_empty());
|
||||
self.attrs.insert(id.local_id, a);
|
||||
}
|
||||
}
|
||||
|
|
@ -1397,7 +1438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
|
||||
self.resolver.get_lifetime_res(t.id)
|
||||
{
|
||||
debug_assert_eq!(start.plus(1), end);
|
||||
assert_eq!(start.plus(1), end);
|
||||
start
|
||||
} else {
|
||||
self.next_node_id()
|
||||
|
|
@ -1805,16 +1846,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeKind::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
hir::LifetimeKind::Infer
|
||||
}
|
||||
LifetimeRes::Static { .. } => {
|
||||
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
hir::LifetimeKind::Static
|
||||
}
|
||||
LifetimeRes::Error => hir::LifetimeKind::Error,
|
||||
|
|
@ -2244,7 +2285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> hir::Stmt<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
if let Some(a) = attrs {
|
||||
debug_assert!(!a.is_empty());
|
||||
assert!(!a.is_empty());
|
||||
self.attrs.insert(hir_id.local_id, a);
|
||||
}
|
||||
let local = hir::LetStmt {
|
||||
|
|
|
|||
|
|
@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
feature: sym::cmse_nonsecure_entry,
|
||||
explain: GateReason::Experimental,
|
||||
}),
|
||||
ExternAbi::Custom => {
|
||||
Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
ast_passes_abi_custom_coroutine =
|
||||
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
|
||||
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
|
||||
|
||||
ast_passes_abi_custom_invalid_signature =
|
||||
invalid signature for `extern "custom"` function
|
||||
.note = functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
.suggestion = remove the parameters and return type
|
||||
|
||||
ast_passes_abi_custom_safe_foreign_function =
|
||||
foreign functions with the `"custom"` ABI cannot be safe
|
||||
.suggestion = remove the `safe` keyword from this definition
|
||||
|
||||
ast_passes_abi_custom_safe_function =
|
||||
functions with the `"custom"` ABI must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::ExternAbi;
|
||||
|
|
@ -81,6 +82,7 @@ struct AstValidator<'a> {
|
|||
|
||||
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
||||
extern_mod_safety: Option<Safety>,
|
||||
extern_mod_abi: Option<ExternAbi>,
|
||||
|
||||
lint_node_id: NodeId,
|
||||
|
||||
|
|
@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
|
|||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
fn with_in_extern_mod(
|
||||
&mut self,
|
||||
extern_mod_safety: Safety,
|
||||
abi: Option<ExternAbi>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
|
||||
f(self);
|
||||
self.extern_mod_safety = old;
|
||||
self.extern_mod_safety = old_safety;
|
||||
self.extern_mod_abi = old_abi;
|
||||
}
|
||||
|
||||
fn with_tilde_const(
|
||||
|
|
@ -370,6 +379,65 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An `extern "custom"` function must be unsafe, and must not have any parameters or return
|
||||
/// type.
|
||||
fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
|
||||
let dcx = self.dcx();
|
||||
|
||||
// An `extern "custom"` function must be unsafe.
|
||||
match sig.header.safety {
|
||||
Safety::Unsafe(_) => { /* all good */ }
|
||||
Safety::Safe(safe_span) => {
|
||||
let safe_span =
|
||||
self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span));
|
||||
dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
|
||||
}
|
||||
Safety::Default => match ctxt {
|
||||
FnCtxt::Foreign => { /* all good */ }
|
||||
FnCtxt::Free | FnCtxt::Assoc(_) => {
|
||||
self.dcx().emit_err(errors::AbiCustomSafeFunction {
|
||||
span: sig.span,
|
||||
unsafe_span: sig.span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// An `extern "custom"` function cannot be `async` and/or `gen`.
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
let coroutine_kind_span = self
|
||||
.sess
|
||||
.psess
|
||||
.source_map()
|
||||
.span_until_non_whitespace(coroutine_kind.span().to(sig.span));
|
||||
|
||||
self.dcx().emit_err(errors::AbiCustomCoroutine {
|
||||
span: sig.span,
|
||||
coroutine_kind_span,
|
||||
coroutine_kind_str: coroutine_kind.as_str(),
|
||||
});
|
||||
}
|
||||
|
||||
// An `extern "custom"` function must not have any parameters or return type.
|
||||
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
|
||||
spans.push(ret_ty.span);
|
||||
}
|
||||
|
||||
if !spans.is_empty() {
|
||||
let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
|
||||
let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
|
||||
let padding = if header_span.is_empty() { "" } else { " " };
|
||||
|
||||
self.dcx().emit_err(errors::AbiCustomInvalidSignature {
|
||||
spans,
|
||||
symbol: ident.name,
|
||||
suggestion_span,
|
||||
padding,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// This ensures that items can only be `unsafe` (or unmarked) outside of extern
|
||||
/// blocks.
|
||||
///
|
||||
|
|
@ -1005,7 +1073,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
if abi.is_none() {
|
||||
self.handle_missing_abi(*extern_span, item.id);
|
||||
}
|
||||
self.with_in_extern_mod(*safety, |this| {
|
||||
|
||||
let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok());
|
||||
self.with_in_extern_mod(*safety, extern_abi, |this| {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
self.extern_mod_span = old_item;
|
||||
|
|
@ -1145,6 +1215,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(sig.header);
|
||||
self.check_foreign_item_ascii_only(*ident);
|
||||
if self.extern_mod_abi == Some(ExternAbi::Custom) {
|
||||
self.check_custom_abi(FnCtxt::Foreign, ident, sig);
|
||||
}
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
|
|
@ -1352,6 +1425,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_item_safety(span, safety);
|
||||
}
|
||||
|
||||
if let FnKind::Fn(ctxt, _, fun) = fk
|
||||
&& let Extern::Explicit(str_lit, _) = fun.sig.header.ext
|
||||
&& let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str())
|
||||
{
|
||||
self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
|
||||
}
|
||||
|
||||
self.check_c_variadic_type(fk);
|
||||
|
||||
// Functions cannot both be `const async` or `const gen`
|
||||
|
|
@ -1703,6 +1783,7 @@ pub fn check_crate(
|
|||
outer_impl_trait_span: None,
|
||||
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||
extern_mod_safety: None,
|
||||
extern_mod_abi: None,
|
||||
lint_node_id: CRATE_NODE_ID,
|
||||
is_sdylib_interface,
|
||||
lint_buffer: lints,
|
||||
|
|
|
|||
|
|
@ -824,3 +824,67 @@ pub(crate) struct MissingAbi {
|
|||
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_safe_foreign_function)]
|
||||
pub(crate) struct AbiCustomSafeForeignFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub safe_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_safe_function)]
|
||||
pub(crate) struct AbiCustomSafeFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "unsafe ",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub unsafe_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_coroutine)]
|
||||
pub(crate) struct AbiCustomCoroutine {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub coroutine_kind_span: Span,
|
||||
pub coroutine_kind_str: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_invalid_signature)]
|
||||
#[note]
|
||||
pub(crate) struct AbiCustomInvalidSignature {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{padding}fn {symbol}()",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub suggestion_span: Span,
|
||||
pub symbol: Symbol,
|
||||
pub padding: &'static str,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,16 @@ macro_rules! gate_alt {
|
|||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
||||
for note in $notes {
|
||||
diag.note(*note);
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// The case involving a multispan.
|
||||
|
|
@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
// Check feature gates for built-in attributes.
|
||||
if let Some(BuiltinAttribute {
|
||||
gate: AttributeGate::Gated(_, name, descr, has_feature),
|
||||
gate: AttributeGate::Gated { feature, message, check, notes, .. },
|
||||
..
|
||||
}) = attr_info
|
||||
{
|
||||
gate_alt!(self, has_feature(self.features), *name, attr.span, *descr);
|
||||
gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
|
||||
}
|
||||
// Check unstable flavors of the `#[doc]` attribute.
|
||||
if attr.has_name(sym::doc) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String {
|
|||
State::new().item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn assoc_item_to_string(i: &ast::AssocItem) -> String {
|
||||
State::new().assoc_item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String {
|
||||
State::new().foreign_item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn stmt_to_string(s: &ast::Stmt) -> String {
|
||||
State::new().stmt_to_string(s)
|
||||
}
|
||||
|
||||
pub fn path_to_string(p: &ast::Path) -> String {
|
||||
State::new().path_to_string(p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1063,6 +1063,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
Self::to_string(|s| s.print_item(i))
|
||||
}
|
||||
|
||||
fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
|
||||
Self::to_string(|s| s.print_assoc_item(i))
|
||||
}
|
||||
|
||||
fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
|
||||
Self::to_string(|s| s.print_foreign_item(i))
|
||||
}
|
||||
|
||||
fn path_to_string(&self, p: &ast::Path) -> String {
|
||||
Self::to_string(|s| s.print_path(p, false, 0))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use rustc_ast::util::classify;
|
|||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
|
||||
use rustc_ast::{
|
||||
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
|
||||
FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
|
||||
self as ast, BinOpKind, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece,
|
||||
FormatCount, FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
|
||||
};
|
||||
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
|
|
@ -214,13 +214,6 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
|
||||
let needs_paren = match func.kind {
|
||||
// In order to call a named field, needs parens: `(self.fun)()`
|
||||
// But not for an unnamed field: `self.0()`
|
||||
ast::ExprKind::Field(_, name) => !name.is_numeric(),
|
||||
_ => func.precedence() < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
// 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
|
||||
|
|
@ -237,8 +230,16 @@ impl<'a> State<'a> {
|
|||
// because the latter is valid syntax but with the incorrect meaning.
|
||||
// It's a match-expression followed by tuple-expression, not a function
|
||||
// call.
|
||||
self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression());
|
||||
let func_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
|
||||
let needs_paren = match func.kind {
|
||||
// In order to call a named field, needs parens: `(self.fun)()`
|
||||
// But not for an unnamed field: `self.0()`
|
||||
ast::ExprKind::Field(_, name) => !name.is_numeric(),
|
||||
_ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
self.print_expr_cond_paren(func, needs_paren, func_fixup);
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
|
|
@ -281,9 +282,24 @@ impl<'a> State<'a> {
|
|||
rhs: &ast::Expr,
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
let operator_can_begin_expr = match op {
|
||||
| BinOpKind::Sub // -x
|
||||
| BinOpKind::Mul // *x
|
||||
| BinOpKind::And // &&x
|
||||
| BinOpKind::Or // || x
|
||||
| BinOpKind::BitAnd // &x
|
||||
| BinOpKind::BitOr // |x| x
|
||||
| BinOpKind::Shl // <<T as Trait>::Type as Trait>::CONST
|
||||
| BinOpKind::Lt // <T as Trait>::CONST
|
||||
=> true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let left_fixup = fixup.leftmost_subexpression_with_operator(operator_can_begin_expr);
|
||||
|
||||
let binop_prec = op.precedence();
|
||||
let left_prec = lhs.precedence();
|
||||
let right_prec = rhs.precedence();
|
||||
let left_prec = left_fixup.precedence(lhs);
|
||||
let right_prec = fixup.precedence(rhs);
|
||||
|
||||
let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
|
||||
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
|
||||
|
|
@ -312,18 +328,18 @@ impl<'a> State<'a> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, left_fixup);
|
||||
self.space();
|
||||
self.word_space(op.as_str());
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.rightmost_subexpression());
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(expr) < ExprPrecedence::Prefix,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -344,8 +360,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(expr) < ExprPrecedence::Prefix,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -590,8 +606,8 @@ impl<'a> State<'a> {
|
|||
self.word_space("=");
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(rhs) < ExprPrecedence::Assign,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
|
|
@ -604,8 +620,8 @@ impl<'a> State<'a> {
|
|||
self.word_space(op.node.as_str());
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(rhs) < ExprPrecedence::Assign,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
|
|
@ -618,10 +634,11 @@ impl<'a> State<'a> {
|
|||
self.print_ident(*ident);
|
||||
}
|
||||
ast::ExprKind::Index(expr, index, _) => {
|
||||
let expr_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup.leftmost_subexpression(),
|
||||
expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous,
|
||||
expr_fixup,
|
||||
);
|
||||
self.word("[");
|
||||
self.print_expr(index, FixupContext::default());
|
||||
|
|
@ -634,10 +651,11 @@ impl<'a> State<'a> {
|
|||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = ExprPrecedence::LOr;
|
||||
if let Some(e) = start {
|
||||
let start_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.leftmost_subexpression(),
|
||||
start_fixup.precedence(e) < fake_prec,
|
||||
start_fixup,
|
||||
);
|
||||
}
|
||||
match limits {
|
||||
|
|
@ -647,8 +665,8 @@ impl<'a> State<'a> {
|
|||
if let Some(e) = end {
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(e) < fake_prec,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -665,11 +683,10 @@ impl<'a> State<'a> {
|
|||
self.space();
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
// Parenthesize if required by precedence, or in the
|
||||
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
||||
expr.precedence() < ExprPrecedence::Jump
|
||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||
fixup.subsequent_subexpression(),
|
||||
// Parenthesize `break 'inner: loop { break 'inner 1 } + 1`
|
||||
// ^---------------------------------^
|
||||
opt_label.is_none() && classify::leading_labeled_expr(expr),
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -684,11 +701,7 @@ impl<'a> State<'a> {
|
|||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yeet(result) => {
|
||||
|
|
@ -697,21 +710,13 @@ impl<'a> State<'a> {
|
|||
self.word("yeet");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
result,
|
||||
result.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(result, fixup.rightmost_subexpression());
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`.
|
||||
|
|
@ -761,11 +766,7 @@ impl<'a> State<'a> {
|
|||
|
||||
if let Some(expr) = e {
|
||||
self.space();
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yield(YieldKind::Postfix(e)) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_ast::Expr;
|
||||
use rustc_ast::util::{classify, parser};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::parser::{self, ExprPrecedence};
|
||||
use rustc_ast::{Expr, ExprKind, YieldKind};
|
||||
|
||||
// The default amount of fixing is minimal fixing, so all fixups are set to `false` by `Default`.
|
||||
// Fixups should be turned on in a targeted fashion where needed.
|
||||
|
|
@ -93,6 +94,24 @@ pub(crate) struct FixupContext {
|
|||
/// }
|
||||
/// ```
|
||||
parenthesize_exterior_struct_lit: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let _ = (return) - 1; // without paren, this would return -1
|
||||
///
|
||||
/// let _ = return + 1; // no paren because '+' cannot begin expr
|
||||
/// ```
|
||||
next_operator_can_begin_expr: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let _ = 1 + return 1; // no parens if rightmost subexpression
|
||||
///
|
||||
/// let _ = 1 + (return 1) + 1; // needs parens
|
||||
/// ```
|
||||
next_operator_can_continue_expr: bool,
|
||||
}
|
||||
|
||||
impl FixupContext {
|
||||
|
|
@ -134,6 +153,8 @@ impl FixupContext {
|
|||
match_arm: false,
|
||||
leftmost_subexpression_in_match_arm: self.match_arm
|
||||
|| self.leftmost_subexpression_in_match_arm,
|
||||
next_operator_can_begin_expr: false,
|
||||
next_operator_can_continue_expr: true,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
|
@ -148,19 +169,34 @@ impl FixupContext {
|
|||
leftmost_subexpression_in_stmt: false,
|
||||
match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
|
||||
leftmost_subexpression_in_match_arm: false,
|
||||
next_operator_can_begin_expr: false,
|
||||
next_operator_can_continue_expr: true,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing any
|
||||
/// subexpression that is neither a leftmost subexpression nor surrounded in
|
||||
/// delimiters.
|
||||
/// Transform this fixup into the one that should apply when printing a
|
||||
/// leftmost subexpression followed by punctuation that is legal as the
|
||||
/// first token of an expression.
|
||||
pub(crate) fn leftmost_subexpression_with_operator(
|
||||
self,
|
||||
next_operator_can_begin_expr: bool,
|
||||
) -> Self {
|
||||
FixupContext { next_operator_can_begin_expr, ..self.leftmost_subexpression() }
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing the
|
||||
/// rightmost subexpression of the current expression.
|
||||
///
|
||||
/// This is for any subexpression that has a different first token than the
|
||||
/// current expression, and is not surrounded by a paren/bracket/brace. For
|
||||
/// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
|
||||
/// `$a.f($b)`.
|
||||
pub(crate) fn subsequent_subexpression(self) -> Self {
|
||||
/// The rightmost subexpression is any subexpression that has a different
|
||||
/// first token than the current expression, but has the same last token.
|
||||
///
|
||||
/// For example in `$a + $b` and `-$b`, the subexpression `$b` is a
|
||||
/// rightmost subexpression.
|
||||
///
|
||||
/// Not every expression has a rightmost subexpression. For example neither
|
||||
/// `[$b]` nor `$a.f($b)` have one.
|
||||
pub(crate) fn rightmost_subexpression(self) -> Self {
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
|
|
@ -193,6 +229,39 @@ impl FixupContext {
|
|||
/// "let chain".
|
||||
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
|
||||
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence())
|
||||
|| parser::needs_par_as_let_scrutinee(self.precedence(expr))
|
||||
}
|
||||
|
||||
/// Determines the effective precedence of a subexpression. Some expressions
|
||||
/// have higher or lower precedence when adjacent to particular operators.
|
||||
pub(crate) fn precedence(self, expr: &Expr) -> ExprPrecedence {
|
||||
if self.next_operator_can_begin_expr {
|
||||
// Decrease precedence of value-less jumps when followed by an
|
||||
// operator that would otherwise get interpreted as beginning a
|
||||
// value for the jump.
|
||||
if let ExprKind::Break(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Yield(YieldKind::Prefix(..)) = expr.kind
|
||||
{
|
||||
return ExprPrecedence::Jump;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.next_operator_can_continue_expr {
|
||||
// Increase precedence of expressions that extend to the end of
|
||||
// current statement or group.
|
||||
if let ExprKind::Break(..)
|
||||
| ExprKind::Closure(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Yield(YieldKind::Prefix(..))
|
||||
| ExprKind::Range(None, ..) = expr.kind
|
||||
{
|
||||
return ExprPrecedence::Prefix;
|
||||
}
|
||||
}
|
||||
|
||||
expr.precedence()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
|
||||
pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
|
||||
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
|
||||
self.ann.pre(self, AnnNode::SubItem(id));
|
||||
self.hardbreak_if_not_bol();
|
||||
|
|
@ -548,7 +548,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_assoc_item(&mut self, item: &ast::AssocItem) {
|
||||
pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
|
||||
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
|
||||
self.ann.pre(self, AnnNode::SubItem(id));
|
||||
self.hardbreak_if_not_bol();
|
||||
|
|
|
|||
|
|
@ -57,14 +57,6 @@ impl OptimizeAttr {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
|
||||
pub enum DiagnosticAttribute {
|
||||
// tidy-alphabetical-start
|
||||
DoNotRecommend,
|
||||
OnUnimplemented,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)]
|
||||
pub enum ReprAttr {
|
||||
ReprInt(IntType),
|
||||
|
|
@ -160,40 +152,52 @@ impl Deprecation {
|
|||
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub enum AttributeKind {
|
||||
// tidy-alphabetical-start
|
||||
/// Represents `#[rustc_allow_const_fn_unstable]`.
|
||||
AllowConstFnUnstable(ThinVec<Symbol>),
|
||||
|
||||
/// Represents `#[allow_internal_unstable]`.
|
||||
AllowInternalUnstable(ThinVec<(Symbol, Span)>),
|
||||
|
||||
/// Represents `#[rustc_default_body_unstable]`.
|
||||
BodyStability {
|
||||
stability: DefaultBodyStability,
|
||||
/// Span of the `#[rustc_default_body_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_confusables]`.
|
||||
Confusables {
|
||||
symbols: ThinVec<Symbol>,
|
||||
// FIXME(jdonszelmann): remove when target validation code is moved
|
||||
first_span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
|
||||
ConstStability {
|
||||
stability: PartialConstStability,
|
||||
/// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_const_stable_indirect]`.
|
||||
ConstStabilityIndirect,
|
||||
Deprecation {
|
||||
deprecation: Deprecation,
|
||||
span: Span,
|
||||
},
|
||||
Diagnostic(DiagnosticAttribute),
|
||||
DocComment {
|
||||
style: AttrStyle,
|
||||
kind: CommentKind,
|
||||
span: Span,
|
||||
comment: Symbol,
|
||||
},
|
||||
|
||||
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
|
||||
Deprecation { deprecation: Deprecation, span: Span },
|
||||
|
||||
/// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
|
||||
DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
|
||||
|
||||
/// Represents `#[rustc_macro_transparency]`.
|
||||
MacroTransparency(Transparency),
|
||||
|
||||
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
|
||||
Repr(ThinVec<(ReprAttr, Span)>),
|
||||
|
||||
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
|
||||
Stability {
|
||||
stability: Stability,
|
||||
/// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
|
||||
/// Span of the attribute.
|
||||
span: Span,
|
||||
},
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ mod attributes;
|
|||
mod stability;
|
||||
mod version;
|
||||
|
||||
pub mod lints;
|
||||
|
||||
use std::num::NonZero;
|
||||
|
||||
pub use attributes::*;
|
||||
|
|
|
|||
14
compiler/rustc_attr_data_structures/src/lints.rs
Normal file
14
compiler/rustc_attr_data_structures/src/lints.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
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 },
|
||||
}
|
||||
|
|
@ -132,6 +132,7 @@ pub enum StabilityLevel {
|
|||
/// fn foobar() {}
|
||||
/// ```
|
||||
implied_by: Option<Symbol>,
|
||||
old_name: Option<Symbol>,
|
||||
},
|
||||
/// `#[stable]`
|
||||
Stable {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,15 @@ attr_parsing_unsupported_literal_generic =
|
|||
attr_parsing_unsupported_literal_suggestion =
|
||||
consider removing the prefix
|
||||
|
||||
attr_parsing_unused_duplicate =
|
||||
unused attribute
|
||||
.suggestion = remove this attribute
|
||||
.note = attribute also specified here
|
||||
.warn = {-passes_previously_accepted}
|
||||
attr_parsing_unused_multiple =
|
||||
multiple `{$name}` attributes
|
||||
.suggestion = remove this attribute
|
||||
.note = attribute also specified here
|
||||
|
||||
-attr_parsing_perviously_accepted =
|
||||
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
|
|
|||
|
|
@ -4,41 +4,43 @@ use rustc_attr_data_structures::AttributeKind;
|
|||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::{CombineAttributeParser, ConvertFn};
|
||||
use crate::context::AcceptContext;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics;
|
||||
|
||||
pub(crate) struct AllowInternalUnstableParser;
|
||||
impl CombineAttributeParser for AllowInternalUnstableParser {
|
||||
const PATH: &'static [Symbol] = &[sym::allow_internal_unstable];
|
||||
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
||||
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
|
||||
type Item = (Symbol, Span);
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
|
||||
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a {
|
||||
parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span))
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
||||
.into_iter()
|
||||
.zip(iter::repeat(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AllowConstFnUnstableParser;
|
||||
impl CombineAttributeParser for AllowConstFnUnstableParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||
type Item = Symbol;
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
|
||||
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a {
|
||||
parse_unstable(cx, args, Self::PATH[0])
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_unstable<'a>(
|
||||
cx: &AcceptContext<'_>,
|
||||
args: &'a ArgParser<'a>,
|
||||
fn parse_unstable<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser<'_>,
|
||||
symbol: Symbol,
|
||||
) -> impl IntoIterator<Item = Symbol> {
|
||||
let mut res = Vec::new();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_span::{Span, Symbol, sym};
|
|||
use thin_vec::ThinVec;
|
||||
|
||||
use super::{AcceptMapping, AttributeParser};
|
||||
use crate::context::FinalizeContext;
|
||||
use crate::context::{FinalizeContext, Stage};
|
||||
use crate::session_diagnostics;
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser {
|
|||
first_span: Option<Span>,
|
||||
}
|
||||
|
||||
impl AttributeParser for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| {
|
||||
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
|
||||
let Some(list) = args.list() else {
|
||||
// FIXME(jdonszelmann): error when not a list? Bring validation code here.
|
||||
// NOTE: currently subsequent attributes are silently ignored using
|
||||
|
|
@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser {
|
|||
this.first_span.get_or_insert(cx.attr_span);
|
||||
})];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.confusables.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::SingleAttributeParser;
|
||||
use super::util::parse_version;
|
||||
use crate::context::AcceptContext;
|
||||
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics;
|
||||
use crate::session_diagnostics::UnsupportedLiteralReason;
|
||||
|
||||
pub(crate) struct DeprecationParser;
|
||||
|
||||
fn get(
|
||||
cx: &AcceptContext<'_>,
|
||||
fn get<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
name: Symbol,
|
||||
param_span: Span,
|
||||
arg: &ArgParser<'_>,
|
||||
|
|
@ -41,19 +41,12 @@ fn get(
|
|||
}
|
||||
}
|
||||
|
||||
impl SingleAttributeParser for DeprecationParser {
|
||||
const PATH: &'static [Symbol] = &[sym::deprecated];
|
||||
impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||
const PATH: &[Symbol] = &[sym::deprecated];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) {
|
||||
// FIXME(jdonszelmann): merge with errors from check_attrs.rs
|
||||
cx.emit_err(session_diagnostics::UnusedMultiple {
|
||||
this: cx.attr_span,
|
||||
other: first_span,
|
||||
name: sym::deprecated,
|
||||
});
|
||||
}
|
||||
|
||||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let features = cx.features();
|
||||
|
||||
let mut since = None;
|
||||
|
|
|
|||
97
compiler/rustc_attr_parsing/src/attributes/inline.rs
Normal file
97
compiler/rustc_attr_parsing/src/attributes/inline.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here.
|
||||
// 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_span::{Symbol, sym};
|
||||
|
||||
use super::{AcceptContext, AttributeOrder, OnDuplicate};
|
||||
use crate::attributes::SingleAttributeParser;
|
||||
use crate::context::Stage;
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct InlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args {
|
||||
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = list.single() else {
|
||||
cx.expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) {
|
||||
Some(sym::always) => {
|
||||
Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
|
||||
}
|
||||
Some(sym::never) => {
|
||||
Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
|
||||
}
|
||||
_ => {
|
||||
cx.expected_specific_argument(l.span(), vec!["always", "never"]);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let suggestions =
|
||||
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline");
|
||||
cx.emit_lint(
|
||||
AttributeLintKind::IllFormedAttributeInput { suggestions },
|
||||
cx.attr_span,
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcForceInlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
|
||||
|
||||
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let reason = match args {
|
||||
ArgParser::NoArgs => None,
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = list.single() else {
|
||||
cx.expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
|
||||
cx.expected_string_literal(l.span());
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(reason)
|
||||
}
|
||||
ArgParser::NameValue(v) => {
|
||||
let Some(reason) = v.value_as_str() else {
|
||||
cx.expected_string_literal(v.value_span);
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(reason)
|
||||
}
|
||||
};
|
||||
|
||||
Some(AttributeKind::Inline(
|
||||
InlineAttr::Force { attr_span: cx.attr_span, reason },
|
||||
cx.attr_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -12,16 +12,18 @@
|
|||
//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the
|
||||
//! contents of attributes, if an attribute appear multiple times in a list
|
||||
//!
|
||||
//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed.
|
||||
//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::lints::AttributeLintKind;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext};
|
||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics::UnusedMultiple;
|
||||
|
||||
pub(crate) mod allow_unstable;
|
||||
pub(crate) mod cfg;
|
||||
|
|
@ -32,8 +34,8 @@ pub(crate) mod stability;
|
|||
pub(crate) mod transparency;
|
||||
pub(crate) mod util;
|
||||
|
||||
type AcceptFn<T> = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>);
|
||||
type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)];
|
||||
type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
|
||||
type AcceptMapping<T, S> = &'static [(&'static [Symbol], AcceptFn<T, S>)];
|
||||
|
||||
/// An [`AttributeParser`] is a type which searches for syntactic attributes.
|
||||
///
|
||||
|
|
@ -51,15 +53,24 @@ type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)];
|
|||
/// whether it has seen the attribute it has been looking for.
|
||||
///
|
||||
/// The state machine is automatically reset to parse attributes on the next item.
|
||||
pub(crate) trait AttributeParser: Default + 'static {
|
||||
///
|
||||
/// For a simpler attribute parsing interface, consider using [`SingleAttributeParser`]
|
||||
/// or [`CombineAttributeParser`] instead.
|
||||
pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
|
||||
/// The symbols for the attributes that this parser is interested in.
|
||||
///
|
||||
/// If an attribute has this symbol, the `accept` function will be called on it.
|
||||
const ATTRIBUTES: AcceptMapping<Self>;
|
||||
const ATTRIBUTES: AcceptMapping<Self, S>;
|
||||
|
||||
/// The parser has gotten a chance to accept the attributes on an item,
|
||||
/// here it can produce an attribute.
|
||||
fn finalize(self, cx: &FinalizeContext<'_>) -> Option<AttributeKind>;
|
||||
///
|
||||
/// All finalize methods of all parsers are unconditionally called.
|
||||
/// This means you can't unconditionally return `Some` here,
|
||||
/// that'd be equivalent to unconditionally applying an attribute to
|
||||
/// every single syntax item that could have attributes applied to it.
|
||||
/// Your accept mappings should determine whether this returns something.
|
||||
fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;
|
||||
}
|
||||
|
||||
/// Alternative to [`AttributeParser`] that automatically handles state management.
|
||||
|
|
@ -71,44 +82,131 @@ pub(crate) trait AttributeParser: Default + 'static {
|
|||
///
|
||||
/// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple
|
||||
/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
|
||||
pub(crate) trait SingleAttributeParser: 'static {
|
||||
const PATH: &'static [Symbol];
|
||||
|
||||
/// Called when a duplicate attribute is found.
|
||||
///
|
||||
/// `first_span` is the span of the first occurrence of this attribute.
|
||||
// FIXME(jdonszelmann): default error
|
||||
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span);
|
||||
pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
|
||||
const PATH: &[Symbol];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder;
|
||||
const ON_DUPLICATE: OnDuplicate<S>;
|
||||
|
||||
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
|
||||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>;
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
|
||||
}
|
||||
|
||||
pub(crate) struct Single<T: SingleAttributeParser>(PhantomData<T>, Option<(AttributeKind, Span)>);
|
||||
pub(crate) struct Single<T: SingleAttributeParser<S>, S: Stage>(
|
||||
PhantomData<(S, T)>,
|
||||
Option<(AttributeKind, Span)>,
|
||||
);
|
||||
|
||||
impl<T: SingleAttributeParser> Default for Single<T> {
|
||||
impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SingleAttributeParser> AttributeParser for Single<T> {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| {
|
||||
if let Some((_, s)) = group.1 {
|
||||
T::on_duplicate(cx, s);
|
||||
return;
|
||||
}
|
||||
impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(T::PATH, |group: &mut Single<T, S>, cx, args| {
|
||||
if let Some(pa) = T::convert(cx, args) {
|
||||
match T::ATTRIBUTE_ORDER {
|
||||
// keep the first and report immediately. ignore this attribute
|
||||
AttributeOrder::KeepFirst => {
|
||||
if let Some((_, unused)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, cx.attr_span, unused);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// keep the new one and warn about the previous,
|
||||
// then replace
|
||||
AttributeOrder::KeepLast => {
|
||||
if let Some((_, used)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(pa) = T::convert(cx, args) {
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
}
|
||||
})];
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
}
|
||||
})];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
Some(self.1?.0)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing
|
||||
// them will be merged in another PR
|
||||
#[allow(unused)]
|
||||
pub(crate) enum OnDuplicate<S: Stage> {
|
||||
/// Give a default warning
|
||||
Warn,
|
||||
|
||||
/// Duplicates will be a warning, with a note that this will be an error in the future.
|
||||
WarnButFutureError,
|
||||
|
||||
/// Give a default error
|
||||
Error,
|
||||
|
||||
/// Ignore duplicates
|
||||
Ignore,
|
||||
|
||||
/// Custom function called when a duplicate attribute is found.
|
||||
///
|
||||
/// - `unused` is the span of the attribute that was unused or bad because of some
|
||||
/// duplicate reason (see [`AttributeOrder`])
|
||||
/// - `used` is the span of the attribute that was used in favor of the unused attribute
|
||||
Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)),
|
||||
}
|
||||
|
||||
impl<S: Stage> OnDuplicate<S> {
|
||||
fn exec<P: SingleAttributeParser<S>>(
|
||||
&self,
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
used: Span,
|
||||
unused: Span,
|
||||
) {
|
||||
match self {
|
||||
OnDuplicate::Warn => cx.emit_lint(
|
||||
AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: false },
|
||||
unused,
|
||||
),
|
||||
OnDuplicate::WarnButFutureError => cx.emit_lint(
|
||||
AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: true },
|
||||
unused,
|
||||
),
|
||||
OnDuplicate::Error => {
|
||||
cx.emit_err(UnusedMultiple {
|
||||
this: used,
|
||||
other: unused,
|
||||
name: Symbol::intern(
|
||||
&P::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."),
|
||||
),
|
||||
});
|
||||
}
|
||||
OnDuplicate::Ignore => {}
|
||||
OnDuplicate::Custom(f) => f(cx, used, unused),
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing
|
||||
// them will be merged in another PR
|
||||
#[allow(unused)]
|
||||
pub(crate) enum AttributeOrder {
|
||||
/// Duplicates after the first attribute will be an error.
|
||||
///
|
||||
/// This should be used where duplicates would be ignored, but carry extra
|
||||
/// meaning that could cause confusion. For example, `#[stable(since="1.0")]
|
||||
/// #[stable(since="2.0")]`, which version should be used for `stable`?
|
||||
KeepFirst,
|
||||
|
||||
/// Duplicates preceding the last instance of the attribute will be a
|
||||
/// warning, with a note that this will be an error in the future.
|
||||
///
|
||||
/// This is the same as `FutureWarnFollowing`, except the last attribute is
|
||||
/// the one that is "used". Ideally these can eventually migrate to
|
||||
/// `ErrorPreceding`.
|
||||
KeepLast,
|
||||
}
|
||||
|
||||
type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
|
||||
|
||||
/// Alternative to [`AttributeParser`] that automatically handles state management.
|
||||
|
|
@ -118,35 +216,35 @@ type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
|
|||
///
|
||||
/// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple
|
||||
/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
|
||||
pub(crate) trait CombineAttributeParser: 'static {
|
||||
const PATH: &'static [Symbol];
|
||||
pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
|
||||
const PATH: &[rustc_span::Symbol];
|
||||
|
||||
type Item;
|
||||
const CONVERT: ConvertFn<Self::Item>;
|
||||
|
||||
/// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a;
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c;
|
||||
}
|
||||
|
||||
pub(crate) struct Combine<T: CombineAttributeParser>(
|
||||
PhantomData<T>,
|
||||
ThinVec<<T as CombineAttributeParser>::Item>,
|
||||
pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
|
||||
PhantomData<(S, T)>,
|
||||
ThinVec<<T as CombineAttributeParser<S>>::Item>,
|
||||
);
|
||||
|
||||
impl<T: CombineAttributeParser> Default for Combine<T> {
|
||||
impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CombineAttributeParser> AttributeParser for Combine<T> {
|
||||
const ATTRIBUTES: AcceptMapping<Self> =
|
||||
&[(T::PATH, |group: &mut Combine<T>, cx, args| group.1.extend(T::extend(cx, args)))];
|
||||
impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use super::{CombineAttributeParser, ConvertFn};
|
||||
use crate::context::AcceptContext;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
|
||||
use crate::session_diagnostics;
|
||||
use crate::session_diagnostics::IncorrectReprFormatGenericCause;
|
||||
|
|
@ -19,15 +19,15 @@ use crate::session_diagnostics::IncorrectReprFormatGenericCause;
|
|||
// FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct?
|
||||
pub(crate) struct ReprParser;
|
||||
|
||||
impl CombineAttributeParser for ReprParser {
|
||||
impl<S: Stage> CombineAttributeParser<S> for ReprParser {
|
||||
type Item = (ReprAttr, Span);
|
||||
const PATH: &'static [Symbol] = &[sym::repr];
|
||||
const PATH: &[Symbol] = &[sym::repr];
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
|
||||
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a {
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
let mut reprs = Vec::new();
|
||||
|
||||
let Some(list) = args.list() else {
|
||||
|
|
@ -91,7 +91,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> {
|
||||
fn parse_repr<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
param: &MetaItemParser<'_>,
|
||||
) -> Option<ReprAttr> {
|
||||
use ReprAttr::*;
|
||||
|
||||
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
|
||||
|
|
@ -180,8 +183,8 @@ enum AlignKind {
|
|||
Align,
|
||||
}
|
||||
|
||||
fn parse_repr_align(
|
||||
cx: &AcceptContext<'_>,
|
||||
fn parse_repr_align<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
list: &MetaItemListParser<'_>,
|
||||
param_span: Span,
|
||||
align_kind: AlignKind,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ use rustc_errors::ErrorGuaranteed;
|
|||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::util::parse_version;
|
||||
use super::{AcceptMapping, AttributeParser, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, FinalizeContext};
|
||||
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemParser};
|
||||
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ pub(crate) struct StabilityParser {
|
|||
|
||||
impl StabilityParser {
|
||||
/// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
|
||||
fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
|
||||
fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
|
||||
if let Some((_, _)) = self.stability {
|
||||
cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
|
||||
true
|
||||
|
|
@ -41,8 +41,8 @@ impl StabilityParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl AttributeParser for StabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[
|
||||
impl<S: Stage> AttributeParser<S> for StabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[sym::stable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
|
|
@ -65,7 +65,7 @@ impl AttributeParser for StabilityParser {
|
|||
}),
|
||||
];
|
||||
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if let Some(atum) = self.allowed_through_unstable_modules {
|
||||
if let Some((
|
||||
Stability {
|
||||
|
|
@ -95,8 +95,8 @@ pub(crate) struct BodyStabilityParser {
|
|||
stability: Option<(DefaultBodyStability, Span)>,
|
||||
}
|
||||
|
||||
impl AttributeParser for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> =
|
||||
impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(&[sym::rustc_default_body_unstable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if this.stability.is_some() {
|
||||
|
|
@ -107,7 +107,7 @@ impl AttributeParser for BodyStabilityParser {
|
|||
}
|
||||
})];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
let (stability, span) = self.stability?;
|
||||
|
||||
Some(AttributeKind::BodyStability { stability, span })
|
||||
|
|
@ -116,13 +116,12 @@ impl AttributeParser for BodyStabilityParser {
|
|||
|
||||
pub(crate) struct ConstStabilityIndirectParser;
|
||||
// FIXME(jdonszelmann): single word attribute group when we have these
|
||||
impl SingleAttributeParser for ConstStabilityIndirectParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_const_stable_indirect];
|
||||
impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
|
||||
|
||||
// ignore
|
||||
fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {}
|
||||
|
||||
fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::ConstStabilityIndirect)
|
||||
}
|
||||
}
|
||||
|
|
@ -135,7 +134,7 @@ pub(crate) struct ConstStabilityParser {
|
|||
|
||||
impl ConstStabilityParser {
|
||||
/// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
|
||||
fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
|
||||
fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
|
||||
if let Some((_, _)) = self.stability {
|
||||
cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
|
||||
true
|
||||
|
|
@ -145,8 +144,8 @@ impl ConstStabilityParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl AttributeParser for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[
|
||||
impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[sym::rustc_const_stable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
|
||||
|
|
@ -176,7 +175,7 @@ impl AttributeParser for ConstStabilityParser {
|
|||
}),
|
||||
];
|
||||
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.promotable {
|
||||
if let Some((ref mut stab, _)) = self.stability {
|
||||
stab.promotable = true;
|
||||
|
|
@ -196,8 +195,8 @@ impl AttributeParser for ConstStabilityParser {
|
|||
///
|
||||
/// Emits an error when either the option was already Some, or the arguments weren't of form
|
||||
/// `name = value`
|
||||
fn insert_value_into_option_or_error(
|
||||
cx: &AcceptContext<'_>,
|
||||
fn insert_value_into_option_or_error<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
param: &MetaItemParser<'_>,
|
||||
item: &mut Option<Symbol>,
|
||||
) -> Option<()> {
|
||||
|
|
@ -223,8 +222,8 @@ fn insert_value_into_option_or_error(
|
|||
|
||||
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
|
||||
/// its stability information.
|
||||
pub(crate) fn parse_stability(
|
||||
cx: &AcceptContext<'_>,
|
||||
pub(crate) fn parse_stability<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser<'_>,
|
||||
) -> Option<(Symbol, StabilityLevel)> {
|
||||
let mut feature = None;
|
||||
|
|
@ -289,8 +288,8 @@ pub(crate) fn parse_stability(
|
|||
|
||||
// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
|
||||
/// attribute, and return the feature name and its stability information.
|
||||
pub(crate) fn parse_unstability(
|
||||
cx: &AcceptContext<'_>,
|
||||
pub(crate) fn parse_unstability<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser<'_>,
|
||||
) -> Option<(Symbol, StabilityLevel)> {
|
||||
let mut feature = None;
|
||||
|
|
@ -299,6 +298,7 @@ pub(crate) fn parse_unstability(
|
|||
let mut issue_num = None;
|
||||
let mut is_soft = false;
|
||||
let mut implied_by = None;
|
||||
let mut old_name = None;
|
||||
for param in args.list()?.mixed() {
|
||||
let Some(param) = param.meta_item() else {
|
||||
cx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
|
|
@ -346,11 +346,12 @@ pub(crate) fn parse_unstability(
|
|||
Some(sym::implied_by) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut implied_by)?
|
||||
}
|
||||
Some(sym::old_name) => insert_value_into_option_or_error(cx, ¶m, &mut old_name)?,
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param.span(),
|
||||
item: param.path().to_string(),
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by"],
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
|
@ -375,6 +376,7 @@ pub(crate) fn parse_unstability(
|
|||
issue: issue_num,
|
||||
is_soft,
|
||||
implied_by,
|
||||
old_name,
|
||||
};
|
||||
Some((feature, level))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use super::{AcceptContext, SingleAttributeParser};
|
||||
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct TransparencyParser;
|
||||
|
|
@ -10,14 +11,14 @@ pub(crate) struct TransparencyParser;
|
|||
// FIXME(jdonszelmann): make these proper diagnostics
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
impl SingleAttributeParser for TransparencyParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency];
|
||||
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
|
||||
cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
|
||||
});
|
||||
|
||||
fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) {
|
||||
cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes");
|
||||
}
|
||||
|
||||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args.name_value().and_then(|nv| nv.value_as_str()) {
|
||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::Deref;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use private::Sealed;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_errors::{DiagCtxtHandle, Diagnostic};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId};
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
|
|
@ -22,20 +26,40 @@ use crate::attributes::transparency::TransparencyParser;
|
|||
use crate::attributes::{AttributeParser as _, Combine, Single};
|
||||
use crate::parser::{ArgParser, MetaItemParser};
|
||||
|
||||
macro_rules! attribute_groups {
|
||||
macro_rules! group_type {
|
||||
($stage: ty) => {
|
||||
LazyLock<(
|
||||
BTreeMap<&'static [Symbol], 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>>>
|
||||
)>
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! attribute_parsers {
|
||||
(
|
||||
pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
type Accepts = BTreeMap<
|
||||
&'static [Symbol],
|
||||
Box<dyn Send + Sync + Fn(&AcceptContext<'_>, &ArgParser<'_>)>
|
||||
>;
|
||||
type Finalizes = Vec<
|
||||
Box<dyn Send + Sync + Fn(&FinalizeContext<'_>) -> Option<AttributeKind>>
|
||||
>;
|
||||
pub(crate) static $name: LazyLock<(Accepts, Finalizes)> = LazyLock::new(|| {
|
||||
let mut accepts = Accepts::new();
|
||||
let mut finalizes = Finalizes::new();
|
||||
mod early {
|
||||
use super::*;
|
||||
type Combine<T> = super::Combine<T, Early>;
|
||||
type Single<T> = super::Single<T, Early>;
|
||||
|
||||
attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
|
||||
}
|
||||
mod late {
|
||||
use super::*;
|
||||
type Combine<T> = super::Combine<T, Late>;
|
||||
type Single<T> = super::Single<T, Late>;
|
||||
|
||||
attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
|
||||
}
|
||||
};
|
||||
(
|
||||
@[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
|
||||
let mut accepts = BTreeMap::<_, 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();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
|
|
@ -62,9 +86,8 @@ macro_rules! attribute_groups {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
attribute_groups!(
|
||||
pub(crate) static ATTRIBUTE_MAPPING = [
|
||||
attribute_parsers!(
|
||||
pub(crate) static ATTRIBUTE_PARSERS = [
|
||||
// tidy-alphabetical-start
|
||||
BodyStabilityParser,
|
||||
ConfusablesParser,
|
||||
|
|
@ -86,30 +109,84 @@ attribute_groups!(
|
|||
];
|
||||
);
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for super::Early {}
|
||||
impl Sealed for super::Late {}
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
pub trait Stage: Sized + 'static + Sealed {
|
||||
type Id: Copy;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self);
|
||||
|
||||
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
impl Stage for Early {
|
||||
type Id = NodeId;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
&early::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
sess.dcx().create_err(diag).delay_as_bug()
|
||||
}
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
impl Stage for Late {
|
||||
type Id = HirId;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
&late::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
tcx.dcx().emit_err(diag)
|
||||
}
|
||||
}
|
||||
|
||||
/// used when parsing attributes for miscelaneous things *before* ast lowering
|
||||
pub struct Early;
|
||||
/// used when parsing attributes during ast lowering
|
||||
pub struct Late;
|
||||
|
||||
/// Context given to every attribute parser when accepting
|
||||
///
|
||||
/// Gives [`AttributeParser`]s enough information to create errors, for example.
|
||||
pub(crate) struct AcceptContext<'a> {
|
||||
pub(crate) group_cx: &'a FinalizeContext<'a>,
|
||||
pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
|
||||
pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>,
|
||||
/// The span of the attribute currently being parsed
|
||||
pub(crate) attr_span: Span,
|
||||
}
|
||||
|
||||
impl<'a> AcceptContext<'a> {
|
||||
pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed {
|
||||
if self.limit_diagnostics {
|
||||
self.dcx().create_err(diag).delay_as_bug()
|
||||
} else {
|
||||
self.dcx().emit_err(diag)
|
||||
}
|
||||
impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
S::emit_err(&self.sess, diag)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
|
||||
let id = self.target_id;
|
||||
(self.emit_lint)(AttributeLint { id, span, kind: lint });
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for AcceptContext<'a> {
|
||||
type Target = FinalizeContext<'a>;
|
||||
impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
|
||||
type Target = FinalizeContext<'f, 'sess, S>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.group_cx
|
||||
&self.finalize_cx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.finalize_cx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,19 +194,29 @@ impl<'a> Deref for AcceptContext<'a> {
|
|||
///
|
||||
/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
|
||||
/// errors, for example.
|
||||
pub(crate) struct FinalizeContext<'a> {
|
||||
pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
|
||||
/// The parse context, gives access to the session and the
|
||||
/// diagnostics context.
|
||||
pub(crate) cx: &'a AttributeParser<'a>,
|
||||
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
|
||||
/// The span of the syntactical component this attribute was applied to
|
||||
pub(crate) target_span: Span,
|
||||
/// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
|
||||
pub(crate) target_id: S::Id,
|
||||
|
||||
pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
|
||||
}
|
||||
|
||||
impl<'a> Deref for FinalizeContext<'a> {
|
||||
type Target = AttributeParser<'a>;
|
||||
impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
|
||||
type Target = AttributeParser<'sess, S>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cx
|
||||
self.cx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.cx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,23 +228,20 @@ pub enum OmitDoc {
|
|||
|
||||
/// Context created once, for example as part of the ast lowering
|
||||
/// context, through which all attributes can be lowered.
|
||||
pub struct AttributeParser<'sess> {
|
||||
pub struct AttributeParser<'sess, S: Stage = Late> {
|
||||
#[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes
|
||||
tools: Vec<Symbol>,
|
||||
sess: &'sess Session,
|
||||
features: Option<&'sess Features>,
|
||||
sess: &'sess Session,
|
||||
stage: PhantomData<S>,
|
||||
|
||||
/// *Only* parse attributes with this symbol.
|
||||
///
|
||||
/// Used in cases where we want the lowering infrastructure for parse just a single attribute.
|
||||
parse_only: Option<Symbol>,
|
||||
|
||||
/// Can be used to instruct parsers to reduce the number of diagnostics it emits.
|
||||
/// Useful when using `parse_limited` and you know the attr will be reparsed later.
|
||||
pub(crate) limit_diagnostics: bool,
|
||||
}
|
||||
|
||||
impl<'sess> AttributeParser<'sess> {
|
||||
impl<'sess> AttributeParser<'sess, Early> {
|
||||
/// This method allows you to parse attributes *before* you have access to features or tools.
|
||||
/// One example where this is necessary, is to parse `feature` attributes themselves for
|
||||
/// example.
|
||||
|
|
@ -168,33 +252,53 @@ impl<'sess> AttributeParser<'sess> {
|
|||
///
|
||||
/// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with
|
||||
/// that symbol are picked out of the list of instructions and parsed. Those are returned.
|
||||
///
|
||||
/// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
|
||||
/// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
|
||||
/// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
|
||||
pub fn parse_limited(
|
||||
sess: &'sess Session,
|
||||
attrs: &[ast::Attribute],
|
||||
sym: Symbol,
|
||||
target_span: Span,
|
||||
limit_diagnostics: bool,
|
||||
target_node_id: NodeId,
|
||||
) -> Option<Attribute> {
|
||||
let mut parsed = Self {
|
||||
sess,
|
||||
let mut p = Self {
|
||||
features: None,
|
||||
tools: Vec::new(),
|
||||
parse_only: Some(sym),
|
||||
limit_diagnostics,
|
||||
}
|
||||
.parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity);
|
||||
|
||||
sess,
|
||||
stage: PhantomData,
|
||||
};
|
||||
let mut parsed = p.parse_attribute_list(
|
||||
attrs,
|
||||
target_span,
|
||||
target_node_id,
|
||||
OmitDoc::Skip,
|
||||
std::convert::identity,
|
||||
|_lint| {
|
||||
panic!("can't emit lints here for now (nothing uses this atm)");
|
||||
},
|
||||
);
|
||||
assert!(parsed.len() <= 1);
|
||||
|
||||
parsed.pop()
|
||||
}
|
||||
|
||||
pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
|
||||
Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false }
|
||||
pub fn new_early(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
|
||||
Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'sess> AttributeParser<'sess, Late> {
|
||||
pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
|
||||
Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'sess, S: Stage> AttributeParser<'sess, S> {
|
||||
pub(crate) fn sess(&self) -> &'sess Session {
|
||||
self.sess
|
||||
&self.sess
|
||||
}
|
||||
|
||||
pub(crate) fn features(&self) -> &'sess Features {
|
||||
|
|
@ -202,25 +306,25 @@ impl<'sess> AttributeParser<'sess> {
|
|||
}
|
||||
|
||||
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
|
||||
self.sess.dcx()
|
||||
self.sess().dcx()
|
||||
}
|
||||
|
||||
/// Parse a list of attributes.
|
||||
///
|
||||
/// `target_span` is the span of the thing this list of attributes is applied to,
|
||||
/// and when `omit_doc` is set, doc attributes are filtered out.
|
||||
pub fn parse_attribute_list<'a>(
|
||||
&'a self,
|
||||
attrs: &'a [ast::Attribute],
|
||||
pub fn parse_attribute_list(
|
||||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
target_span: Span,
|
||||
target_id: S::Id,
|
||||
omit_doc: OmitDoc,
|
||||
|
||||
lower_span: impl Copy + Fn(Span) -> Span,
|
||||
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
|
||||
) -> Vec<Attribute> {
|
||||
let mut attributes = Vec::new();
|
||||
|
||||
let group_cx = FinalizeContext { cx: self, target_span };
|
||||
|
||||
for attr in attrs {
|
||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||
if let Some(expected) = self.parse_only {
|
||||
|
|
@ -268,11 +372,18 @@ impl<'sess> AttributeParser<'sess> {
|
|||
let args = parser.args();
|
||||
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accept) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) {
|
||||
let cx =
|
||||
AcceptContext { group_cx: &group_cx, attr_span: lower_span(attr.span) };
|
||||
if let Some(accept) = S::parsers().0.get(parts.as_slice()) {
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
finalize_cx: FinalizeContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target_id,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span: lower_span(attr.span),
|
||||
};
|
||||
|
||||
accept(&cx, &args)
|
||||
accept(&mut cx, args)
|
||||
} else {
|
||||
// If we're here, we must be compiling a tool attribute... Or someone
|
||||
// forgot to parse their fancy new attribute. Let's warn them in any case.
|
||||
|
|
@ -302,8 +413,13 @@ impl<'sess> AttributeParser<'sess> {
|
|||
}
|
||||
|
||||
let mut parsed_attributes = Vec::new();
|
||||
for f in &ATTRIBUTE_MAPPING.1 {
|
||||
if let Some(attr) = f(&group_cx) {
|
||||
for f in &S::parsers().1 {
|
||||
if let Some(attr) = f(&mut FinalizeContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target_id,
|
||||
emit_lint: &mut emit_lint,
|
||||
}) {
|
||||
parsed_attributes.push(Attribute::Parsed(attr));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@
|
|||
|
||||
#[macro_use]
|
||||
mod attributes;
|
||||
mod context;
|
||||
pub(crate) mod context;
|
||||
mod lints;
|
||||
pub mod parser;
|
||||
mod session_diagnostics;
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ pub use attributes::cfg::*;
|
|||
pub use attributes::util::{
|
||||
find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
|
||||
};
|
||||
pub use context::{AttributeParser, OmitDoc};
|
||||
pub use context::{AttributeParser, Early, Late, OmitDoc};
|
||||
pub use lints::emit_attribute_lint;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
|
|
|||
19
compiler/rustc_attr_parsing/src/lints.rs
Normal file
19
compiler/rustc_attr_parsing/src/lints.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_errors::LintEmitter;
|
||||
use rustc_hir::HirId;
|
||||
|
||||
use crate::session_diagnostics;
|
||||
|
||||
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
|
||||
let AttributeLint { id, span, kind } = lint;
|
||||
|
||||
match kind {
|
||||
&AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter
|
||||
.emit_node_span_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
*id,
|
||||
*span,
|
||||
session_diagnostics::UnusedDuplicate { this, other, warning },
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ impl<'a> ArgParser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self {
|
||||
pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
|
|
@ -235,7 +235,7 @@ impl<'a> Debug for MetaItemParser<'a> {
|
|||
impl<'a> MetaItemParser<'a> {
|
||||
/// Create a new parser from a [`NormalAttr`], which is stored inside of any
|
||||
/// [`ast::Attribute`](rustc_ast::Attribute)
|
||||
pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self {
|
||||
pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
Self {
|
||||
path: PathParser::Ast(&attr.item.path),
|
||||
args: ArgParser::from_attr_args(&attr.item.args, dcx),
|
||||
|
|
@ -320,13 +320,13 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit
|
|||
}
|
||||
}
|
||||
|
||||
struct MetaItemListParserContext<'a> {
|
||||
struct MetaItemListParserContext<'a, 'sess> {
|
||||
// the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside
|
||||
inside_delimiters: Peekable<TokenStreamIter<'a>>,
|
||||
dcx: DiagCtxtHandle<'a>,
|
||||
dcx: DiagCtxtHandle<'sess>,
|
||||
}
|
||||
|
||||
impl<'a> MetaItemListParserContext<'a> {
|
||||
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||
fn done(&mut self) -> bool {
|
||||
self.inside_delimiters.peek().is_none()
|
||||
}
|
||||
|
|
@ -507,11 +507,11 @@ pub struct MetaItemListParser<'a> {
|
|||
}
|
||||
|
||||
impl<'a> MetaItemListParser<'a> {
|
||||
fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> {
|
||||
fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx)
|
||||
}
|
||||
|
||||
fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self {
|
||||
fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::num::IntErrorKind;
|
|||
use rustc_ast as ast;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
|
@ -451,6 +451,17 @@ pub(crate) struct UnusedMultiple {
|
|||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(attr_parsing_unused_duplicate)]
|
||||
pub(crate) struct UnusedDuplicate {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub this: Span,
|
||||
#[note]
|
||||
pub other: Span,
|
||||
#[warning]
|
||||
pub warning: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_stability_outside_std, code = E0734)]
|
||||
pub(crate) struct StabilityOutsideStd {
|
||||
|
|
|
|||
|
|
@ -3229,8 +3229,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
|
|||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
let mutability = if matches!(borrow.kind(), BorrowKind::Mut { .. }) {
|
||||
"mut "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
if !is_format_arguments_item {
|
||||
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
|
||||
let addition = format!(
|
||||
"let {}binding = {};\n{}",
|
||||
mutability,
|
||||
s,
|
||||
" ".repeat(p)
|
||||
);
|
||||
err.multipart_suggestion_verbose(
|
||||
msg,
|
||||
vec![
|
||||
|
|
|
|||
|
|
@ -141,8 +141,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if !tcx.recursion_limit().value_within_limit(iteration) {
|
||||
// This may actually be reachable. If so, we should convert
|
||||
// this to a proper error/consider whether we should detect
|
||||
// this somewhere else.
|
||||
bug!(
|
||||
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
"unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> {
|
|||
match item {
|
||||
Annotatable::Item(item) => {
|
||||
let is_packed = matches!(
|
||||
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true),
|
||||
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id),
|
||||
Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -644,9 +644,9 @@ pub mod intrinsics {
|
|||
#[rustc_intrinsic]
|
||||
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
pub fn align_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||
#[rustc_intrinsic]
|
||||
|
|
|
|||
|
|
@ -204,11 +204,8 @@ fn main() {
|
|||
assert_eq!(intrinsics::size_of_val(a) as u8, 16);
|
||||
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
|
||||
|
||||
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
|
||||
assert_eq!(
|
||||
intrinsics::min_align_of_val(&a) as u8,
|
||||
intrinsics::min_align_of::<&str>() as u8
|
||||
);
|
||||
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
|
||||
|
||||
assert!(!intrinsics::needs_drop::<u8>());
|
||||
assert!(!intrinsics::needs_drop::<[u8]>());
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv(
|
|||
CanonAbi::Rust | CanonAbi::C => default_call_conv,
|
||||
CanonAbi::RustCold => CallConv::Cold,
|
||||
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => default_call_conv,
|
||||
|
||||
CanonAbi::X86(x86_call) => match x86_call {
|
||||
X86Call::SysV64 => CallConv::SystemV,
|
||||
X86Call::Win64 => CallConv::WindowsFastcall,
|
||||
|
|
|
|||
|
|
@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta);
|
||||
ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
|
||||
}
|
||||
sym::min_align_of_val => {
|
||||
sym::align_of_val => {
|
||||
intrinsic_args!(fx, args => (ptr); intrinsic);
|
||||
|
||||
let layout = fx.layout_of(generic_args.type_at(0));
|
||||
|
|
@ -613,7 +613,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
|
|||
intrinsic_args!(fx, args => (vtable); intrinsic);
|
||||
let vtable = vtable.load_scalar(fx);
|
||||
|
||||
let align = crate::vtable::min_align_of_obj(fx, vtable);
|
||||
let align = crate::vtable::align_of_obj(fx, vtable);
|
||||
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>(
|
|||
// load size/align from vtable
|
||||
(
|
||||
crate::vtable::size_of_obj(fx, info.unwrap()),
|
||||
crate::vtable::min_align_of_obj(fx, info.unwrap()),
|
||||
crate::vtable::align_of_obj(fx, info.unwrap()),
|
||||
)
|
||||
}
|
||||
ty::Slice(_) | ty::Str => {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
|
||||
pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
|
||||
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
|
||||
fx.bcx.ins().load(
|
||||
fx.pointer_type,
|
||||
|
|
|
|||
|
|
@ -655,9 +655,9 @@ pub mod intrinsics {
|
|||
#[rustc_intrinsic]
|
||||
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
pub fn align_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||
#[rustc_intrinsic]
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ fn main() {
|
|||
let slice = &[0, 1] as &[i32];
|
||||
let slice_ptr = slice as *const [i32] as *const i32;
|
||||
|
||||
let align = intrinsics::min_align_of::<*const i32>();
|
||||
let align = intrinsics::align_of::<*const i32>();
|
||||
assert_eq!(slice_ptr as usize % align, 0);
|
||||
|
||||
//return;
|
||||
|
|
@ -194,8 +194,8 @@ fn main() {
|
|||
assert_eq!(intrinsics::size_of_val(a) as u8, 8);
|
||||
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
|
||||
|
||||
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
|
||||
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
|
||||
|
||||
assert!(!intrinsics::needs_drop::<u8>());
|
||||
assert!(!intrinsics::needs_drop::<[u8]>());
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
|
|||
unknown feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = features must begin with a `+` to enable or `-` to disable it
|
||||
|
||||
codegen_gcc_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
|
||||
|
||||
codegen_gcc_unwinding_inline_asm =
|
||||
GCC backend does not support unwinding from inline asm
|
||||
|
||||
|
|
@ -26,10 +23,6 @@ codegen_gcc_unknown_ctarget_feature =
|
|||
.possible_feature = you might have meant: `{$rust_feature}`
|
||||
.consider_filing_feature_request = consider filing a feature request
|
||||
|
||||
codegen_gcc_unstable_ctarget_feature =
|
||||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
codegen_gcc_missing_features =
|
||||
add the missing features in a `target_feature` attribute
|
||||
|
||||
|
|
|
|||
|
|
@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
|
||||
let attribute = match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => return None,
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => return None,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
|
||||
ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
|
||||
ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
|
||||
},
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
CanonAbi::GpuKernel => {
|
||||
if arch == "amdgpu" {
|
||||
FnAttribute::GcnAmdGpuHsaKernel
|
||||
|
|
|
|||
|
|
@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
|
|||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_unstable_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_forbidden_ctarget_feature)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_gcc_possible_feature)]
|
||||
|
|
|
|||
|
|
@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::errors::{
|
||||
ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
|
||||
UnstableCTargetFeature,
|
||||
};
|
||||
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
|
||||
|
||||
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
|
||||
let mut features: Vec<&str> = Vec::new();
|
||||
retpoline_features_by_flags(sess, &mut features);
|
||||
features
|
||||
}
|
||||
|
||||
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
|
|
@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(feature))
|
||||
|
|
@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some(&(_, stability, _)) => {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. (It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above).
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
stability.verify_feature_enabled_by_flag(sess, enable, feature);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto =
|
|||
|
||||
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||
|
||||
codegen_llvm_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
|
||||
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
codegen_llvm_from_llvm_diag = {$message}
|
||||
|
||||
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
|
||||
|
|
@ -76,10 +71,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
|
|||
|
||||
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
|
||||
|
||||
codegen_llvm_unstable_ctarget_feature =
|
||||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
|
||||
|
||||
codegen_llvm_write_ir = failed to write LLVM IR to {$path}
|
||||
|
|
|
|||
|
|
@ -649,6 +649,10 @@ impl llvm::CallConv {
|
|||
match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
|
||||
CanonAbi::RustCold => llvm::PreserveMost,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => llvm::CCallConv,
|
||||
CanonAbi::GpuKernel => {
|
||||
if arch == "amdgpu" {
|
||||
llvm::AmdgpuKernel
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
@ -256,11 +257,11 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
|
|||
StackProbeType::Inline => "inline-asm",
|
||||
// Flag our internal `__rust_probestack` function as the stack probe symbol.
|
||||
// This is defined in the `compiler-builtins` crate for each architecture.
|
||||
StackProbeType::Call => "__rust_probestack",
|
||||
StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"),
|
||||
// Pick from the two above based on the LLVM version.
|
||||
StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
|
||||
if llvm_util::get_version() < min_llvm_version_for_inline {
|
||||
"__rust_probestack"
|
||||
&mangle_internal_symbol(cx.tcx, "__rust_probestack")
|
||||
} else {
|
||||
"inline-asm"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
|
|||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_unstable_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_forbidden_ctarget_feature)]
|
||||
#[note]
|
||||
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_llvm_possible_feature)]
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc_fs_util::path_to_c_string;
|
|||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{PrintKind, PrintRequest};
|
||||
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
|
||||
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
|
||||
|
|
@ -23,8 +24,7 @@ use smallvec::{SmallVec, smallvec};
|
|||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
|
||||
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
|
||||
};
|
||||
use crate::llvm;
|
||||
|
||||
|
|
@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
|
|||
handle_native(cpu_name)
|
||||
}
|
||||
|
||||
fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
|
||||
let mut features: Vec<&str> = Vec::new();
|
||||
retpoline_features_by_flags(sess, &mut features);
|
||||
features
|
||||
}
|
||||
|
||||
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
pub(crate) fn global_llvm_features(
|
||||
|
|
@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features(
|
|||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(feature))
|
||||
|
|
@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features(
|
|||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
stability.verify_feature_enabled_by_flag(sess, enable, feature);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1065,11 +1065,11 @@ fn link_natively(
|
|||
match strip {
|
||||
Strip::Debuginfo => {
|
||||
// FIXME: AIX's strip utility only offers option to strip line number information.
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"])
|
||||
strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-l"])
|
||||
}
|
||||
Strip::Symbols => {
|
||||
// Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata.
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"])
|
||||
strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-r"])
|
||||
}
|
||||
Strip::None => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
|
||||
llsize
|
||||
}
|
||||
sym::min_align_of_val => {
|
||||
sym::align_of_val => {
|
||||
let tp_ty = fn_args.type_at(0);
|
||||
let (_, meta) = args[0].val.pointer_parts();
|
||||
let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
{
|
||||
let from_backend_ty = bx.backend_type(operand.layout);
|
||||
let to_backend_ty = bx.backend_type(cast);
|
||||
Some(OperandValue::Immediate(self.transmute_immediate(
|
||||
Some(OperandValue::Immediate(transmute_immediate(
|
||||
bx,
|
||||
imm,
|
||||
from_scalar,
|
||||
|
|
@ -303,8 +303,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false);
|
||||
let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false);
|
||||
Some(OperandValue::Pair(
|
||||
self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
|
||||
self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
|
||||
transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
|
||||
transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -332,7 +332,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
// valid ranges. For example, `char`s are passed as just `i32`, with no
|
||||
// way for LLVM to know that they're 0x10FFFF at most. Thus we assume
|
||||
// the range of the input value too, not just the output range.
|
||||
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
|
||||
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
|
||||
(Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
|
||||
|
|
@ -365,98 +365,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
Some(imm)
|
||||
}
|
||||
|
||||
/// Transmutes one of the immediates from an [`OperandValue::Immediate`]
|
||||
/// or an [`OperandValue::Pair`] to an immediate of the target type.
|
||||
///
|
||||
/// `to_backend_ty` must be the *non*-immediate backend type (so it will be
|
||||
/// `i8`, not `i1`, for `bool`-like types.)
|
||||
fn transmute_immediate(
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
mut imm: Bx::Value,
|
||||
from_scalar: abi::Scalar,
|
||||
from_backend_ty: Bx::Type,
|
||||
to_scalar: abi::Scalar,
|
||||
to_backend_ty: Bx::Type,
|
||||
) -> Bx::Value {
|
||||
assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
|
||||
|
||||
// While optimizations will remove no-op transmutes, they might still be
|
||||
// there in debug or things that aren't no-op in MIR because they change
|
||||
// the Rust type but not the underlying layout/niche.
|
||||
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
|
||||
return imm;
|
||||
}
|
||||
|
||||
use abi::Primitive::*;
|
||||
imm = bx.from_immediate(imm);
|
||||
|
||||
// If we have a scalar, we must already know its range. Either
|
||||
//
|
||||
// 1) It's a parameter with `range` parameter metadata,
|
||||
// 2) It's something we `load`ed with `!range` metadata, or
|
||||
// 3) After a transmute we `assume`d the range (see below).
|
||||
//
|
||||
// That said, last time we tried removing this, it didn't actually help
|
||||
// the rustc-perf results, so might as well keep doing it
|
||||
// <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
|
||||
self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
|
||||
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
|
||||
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
|
||||
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
|
||||
(Pointer(..), Int(..)) => {
|
||||
// FIXME: this exposes the provenance, which shouldn't be necessary.
|
||||
bx.ptrtoint(imm, to_backend_ty)
|
||||
}
|
||||
(Float(_), Pointer(..)) => {
|
||||
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
|
||||
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
|
||||
}
|
||||
(Pointer(..), Float(_)) => {
|
||||
// FIXME: this exposes the provenance, which shouldn't be necessary.
|
||||
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
|
||||
bx.bitcast(int_imm, to_backend_ty)
|
||||
}
|
||||
};
|
||||
|
||||
// This `assume` remains important for cases like (a conceptual)
|
||||
// transmute::<u32, NonZeroU32>(x) == 0
|
||||
// since it's never passed to something with parameter metadata (especially
|
||||
// after MIR inlining) so the only way to tell the backend about the
|
||||
// constraint that the `transmute` introduced is to `assume` it.
|
||||
self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
|
||||
|
||||
imm = bx.to_immediate_scalar(imm, to_scalar);
|
||||
imm
|
||||
}
|
||||
|
||||
fn assume_scalar_range(
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
imm: Bx::Value,
|
||||
scalar: abi::Scalar,
|
||||
backend_ty: Bx::Type,
|
||||
) {
|
||||
if matches!(self.cx.sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(self.cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
match scalar.primitive() {
|
||||
abi::Primitive::Int(..) => {
|
||||
let range = scalar.valid_range(self.cx);
|
||||
bx.assume_integer_range(imm, backend_ty, range);
|
||||
}
|
||||
abi::Primitive::Pointer(abi::AddressSpace::DATA)
|
||||
if !scalar.valid_range(self.cx).contains(0) =>
|
||||
{
|
||||
bx.assume_nonnull(imm);
|
||||
}
|
||||
abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn codegen_rvalue_unsized(
|
||||
&mut self,
|
||||
bx: &mut Bx,
|
||||
|
|
@ -1231,3 +1139,93 @@ impl OperandValueKind {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Transmutes one of the immediates from an [`OperandValue::Immediate`]
|
||||
/// or an [`OperandValue::Pair`] to an immediate of the target type.
|
||||
///
|
||||
/// `to_backend_ty` must be the *non*-immediate backend type (so it will be
|
||||
/// `i8`, not `i1`, for `bool`-like types.)
|
||||
fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
mut imm: Bx::Value,
|
||||
from_scalar: abi::Scalar,
|
||||
from_backend_ty: Bx::Type,
|
||||
to_scalar: abi::Scalar,
|
||||
to_backend_ty: Bx::Type,
|
||||
) -> Bx::Value {
|
||||
assert_eq!(from_scalar.size(bx.cx()), to_scalar.size(bx.cx()));
|
||||
|
||||
// While optimizations will remove no-op transmutes, they might still be
|
||||
// there in debug or things that aren't no-op in MIR because they change
|
||||
// the Rust type but not the underlying layout/niche.
|
||||
if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
|
||||
return imm;
|
||||
}
|
||||
|
||||
use abi::Primitive::*;
|
||||
imm = bx.from_immediate(imm);
|
||||
|
||||
// If we have a scalar, we must already know its range. Either
|
||||
//
|
||||
// 1) It's a parameter with `range` parameter metadata,
|
||||
// 2) It's something we `load`ed with `!range` metadata, or
|
||||
// 3) After a transmute we `assume`d the range (see below).
|
||||
//
|
||||
// That said, last time we tried removing this, it didn't actually help
|
||||
// the rustc-perf results, so might as well keep doing it
|
||||
// <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
|
||||
assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
|
||||
|
||||
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
|
||||
(Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
|
||||
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
|
||||
(Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
|
||||
(Pointer(..), Int(..)) => {
|
||||
// FIXME: this exposes the provenance, which shouldn't be necessary.
|
||||
bx.ptrtoint(imm, to_backend_ty)
|
||||
}
|
||||
(Float(_), Pointer(..)) => {
|
||||
let int_imm = bx.bitcast(imm, bx.cx().type_isize());
|
||||
bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
|
||||
}
|
||||
(Pointer(..), Float(_)) => {
|
||||
// FIXME: this exposes the provenance, which shouldn't be necessary.
|
||||
let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
|
||||
bx.bitcast(int_imm, to_backend_ty)
|
||||
}
|
||||
};
|
||||
|
||||
// This `assume` remains important for cases like (a conceptual)
|
||||
// transmute::<u32, NonZeroU32>(x) == 0
|
||||
// since it's never passed to something with parameter metadata (especially
|
||||
// after MIR inlining) so the only way to tell the backend about the
|
||||
// constraint that the `transmute` introduced is to `assume` it.
|
||||
assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
|
||||
|
||||
imm = bx.to_immediate_scalar(imm, to_scalar);
|
||||
imm
|
||||
}
|
||||
|
||||
fn assume_scalar_range<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
imm: Bx::Value,
|
||||
scalar: abi::Scalar,
|
||||
backend_ty: Bx::Type,
|
||||
) {
|
||||
if matches!(bx.cx().sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(bx.cx()) {
|
||||
return;
|
||||
}
|
||||
|
||||
match scalar.primitive() {
|
||||
abi::Primitive::Int(..) => {
|
||||
let range = scalar.valid_range(bx.cx());
|
||||
bx.assume_integer_range(imm, backend_ty, range);
|
||||
}
|
||||
abi::Primitive::Pointer(abi::AddressSpace::DATA)
|
||||
if !scalar.valid_range(bx.cx()).contains(0) =>
|
||||
{
|
||||
bx.assume_nonnull(imm);
|
||||
}
|
||||
abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
|||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::features::StabilityExt;
|
||||
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
|
@ -66,7 +67,7 @@ pub(crate) fn from_target_feature_attr(
|
|||
|
||||
// Only allow target features whose feature gates have been enabled
|
||||
// and which are permitted to be toggled.
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
if let Err(reason) = stability.is_toggle_permitted(tcx.sess) {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature,
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ pub trait DerivedTypeCodegenMethods<'tcx>:
|
|||
BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
|
||||
{
|
||||
fn type_int(&self) -> Self::Type {
|
||||
match &self.sess().target.c_int_width[..] {
|
||||
"16" => self.type_i16(),
|
||||
"32" => self.type_i32(),
|
||||
"64" => self.type_i64(),
|
||||
match &self.sess().target.c_int_width {
|
||||
16 => self.type_i16(),
|
||||
32 => self.type_i32(),
|
||||
64 => self.type_i64(),
|
||||
width => bug!("Unsupported c_int_width: {}", width),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -356,10 +356,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
hir::ConstContext::ConstFn => true,
|
||||
_ => {
|
||||
// For indirect places, we are not creating a new permanent borrow, it's just as
|
||||
// transient as the already existing one. For reborrowing references this is handled
|
||||
// at the top of `visit_rvalue`, but for raw pointers we handle it here.
|
||||
// Pointers/references to `static mut` and cases where the `*` is not the first
|
||||
// projection also end up here.
|
||||
// transient as the already existing one.
|
||||
// Locals with StorageDead do not live beyond the evaluation and can
|
||||
// thus safely be borrowed without being able to be leaked to the final
|
||||
// value of the constant.
|
||||
|
|
|
|||
|
|
@ -227,12 +227,11 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
|
|||
|
||||
// Keep interning as long as there are things to intern.
|
||||
// We show errors if there are dangling pointers, or mutable pointers in immutable contexts
|
||||
// (i.e., everything except for `static mut`). When these errors affect references, it is
|
||||
// unfortunate that we show these errors here and not during validation, since validation can
|
||||
// show much nicer errors. However, we do need these checks to be run on all pointers, including
|
||||
// raw pointers, so we cannot rely on validation to catch them -- and since interning runs
|
||||
// before validation, and interning doesn't know the type of anything, this means we can't show
|
||||
// better errors. Maybe we should consider doing validation before interning in the future.
|
||||
// (i.e., everything except for `static mut`). We only return these errors as a `Result`
|
||||
// so that the caller can run validation, and subsequently only report interning errors
|
||||
// if validation fails. Validation has the better error messages so we prefer those, but
|
||||
// interning has better coverage since it "sees" *all* pointers, including raw pointers and
|
||||
// references stored in unions.
|
||||
while let Some(prov) = todo.pop() {
|
||||
trace!(?prov);
|
||||
let alloc_id = prov.alloc_id();
|
||||
|
|
@ -279,12 +278,12 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
|
|||
// when there is memory there that someone might expect to be mutable, but we make it immutable.
|
||||
let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id);
|
||||
if !dangling {
|
||||
// Found a mutable reference inside a const where inner allocations should be
|
||||
// Found a mutable pointer inside a const where inner allocations should be
|
||||
// immutable.
|
||||
if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
|
||||
span_bug!(
|
||||
ecx.tcx.span,
|
||||
"the static const safety checks accepted mutable references they should not have accepted"
|
||||
"the static const safety checks accepted a mutable pointer they should not have accepted"
|
||||
);
|
||||
}
|
||||
// Prefer dangling pointer errors over mutable pointer errors
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
self.copy_op(&val, dest)?;
|
||||
}
|
||||
|
||||
sym::min_align_of_val | sym::size_of_val => {
|
||||
sym::align_of_val | sym::size_of_val => {
|
||||
// Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be
|
||||
// dereferenceable!
|
||||
let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
|
||||
|
|
@ -129,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
.ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
|
||||
|
||||
let result = match intrinsic_name {
|
||||
sym::min_align_of_val => align.bytes(),
|
||||
sym::align_of_val => align.bytes(),
|
||||
sym::size_of_val => size.bytes(),
|
||||
_ => bug!(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ pub enum MaybeEnteredSpan {
|
|||
macro_rules! enter_trace_span {
|
||||
($machine:ident, $($tt:tt)*) => {
|
||||
if $machine::TRACING_ENABLED {
|
||||
$crate::interpret::tracing_utils::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered())
|
||||
$crate::interpret::util::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered())
|
||||
} else {
|
||||
$crate::interpret::tracing_utils::MaybeEnteredSpan::None
|
||||
$crate::interpret::util::MaybeEnteredSpan::None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,37 @@
|
|||
//! This is an extremely bare-bones alternative to the `thousands` crate on
|
||||
//! crates.io, for printing large numbers in a readable fashion.
|
||||
//! This is a bare-bones alternative to the `thousands` crate on crates.io, for
|
||||
//! printing large numbers in a readable fashion.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// Converts the number to a string, with underscores as the thousands separator.
|
||||
pub fn format_with_underscores(n: usize) -> String {
|
||||
let mut s = n.to_string();
|
||||
let mut i = s.len();
|
||||
while i > 3 {
|
||||
fn format_with_underscores(mut s: String) -> String {
|
||||
// Ignore a leading '-'.
|
||||
let start = if s.starts_with('-') { 1 } else { 0 };
|
||||
|
||||
// Stop after the first non-digit, e.g. '.' or 'e' for floats.
|
||||
let non_digit = s[start..].find(|c: char| !c.is_digit(10));
|
||||
let end = if let Some(non_digit) = non_digit { start + non_digit } else { s.len() };
|
||||
|
||||
// Insert underscores within `start..end`.
|
||||
let mut i = end;
|
||||
while i > start + 3 {
|
||||
i -= 3;
|
||||
s.insert(i, '_');
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Print a `usize` with underscore separators.
|
||||
pub fn usize_with_underscores(n: usize) -> String {
|
||||
format_with_underscores(format!("{n}"))
|
||||
}
|
||||
|
||||
/// Print an `isize` with underscore separators.
|
||||
pub fn isize_with_underscores(n: isize) -> String {
|
||||
format_with_underscores(format!("{n}"))
|
||||
}
|
||||
|
||||
/// Print an `f64` with precision 1 (one decimal place) and underscore separators.
|
||||
pub fn f64p1_with_underscores(n: f64) -> String {
|
||||
format_with_underscores(format!("{n:.1}"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,13 +2,51 @@ use super::*;
|
|||
|
||||
#[test]
|
||||
fn test_format_with_underscores() {
|
||||
assert_eq!("0", format_with_underscores(0));
|
||||
assert_eq!("1", format_with_underscores(1));
|
||||
assert_eq!("99", format_with_underscores(99));
|
||||
assert_eq!("345", format_with_underscores(345));
|
||||
assert_eq!("1_000", format_with_underscores(1_000));
|
||||
assert_eq!("12_001", format_with_underscores(12_001));
|
||||
assert_eq!("999_999", format_with_underscores(999_999));
|
||||
assert_eq!("1_000_000", format_with_underscores(1_000_000));
|
||||
assert_eq!("12_345_678", format_with_underscores(12_345_678));
|
||||
assert_eq!("", format_with_underscores("".to_string()));
|
||||
assert_eq!("0", format_with_underscores("0".to_string()));
|
||||
assert_eq!("12_345.67e14", format_with_underscores("12345.67e14".to_string()));
|
||||
assert_eq!("-1_234.5678e10", format_with_underscores("-1234.5678e10".to_string()));
|
||||
assert_eq!("------", format_with_underscores("------".to_string()));
|
||||
assert_eq!("abcdefgh", format_with_underscores("abcdefgh".to_string()));
|
||||
assert_eq!("-1b", format_with_underscores("-1b".to_string()));
|
||||
assert_eq!("-3_456xyz", format_with_underscores("-3456xyz".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_usize_with_underscores() {
|
||||
assert_eq!("0", usize_with_underscores(0));
|
||||
assert_eq!("1", usize_with_underscores(1));
|
||||
assert_eq!("99", usize_with_underscores(99));
|
||||
assert_eq!("345", usize_with_underscores(345));
|
||||
assert_eq!("1_000", usize_with_underscores(1_000));
|
||||
assert_eq!("12_001", usize_with_underscores(12_001));
|
||||
assert_eq!("999_999", usize_with_underscores(999_999));
|
||||
assert_eq!("1_000_000", usize_with_underscores(1_000_000));
|
||||
assert_eq!("12_345_678", usize_with_underscores(12_345_678));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_isize_with_underscores() {
|
||||
assert_eq!("0", isize_with_underscores(0));
|
||||
assert_eq!("-1", isize_with_underscores(-1));
|
||||
assert_eq!("99", isize_with_underscores(99));
|
||||
assert_eq!("345", isize_with_underscores(345));
|
||||
assert_eq!("-1_000", isize_with_underscores(-1_000));
|
||||
assert_eq!("12_001", isize_with_underscores(12_001));
|
||||
assert_eq!("-999_999", isize_with_underscores(-999_999));
|
||||
assert_eq!("1_000_000", isize_with_underscores(1_000_000));
|
||||
assert_eq!("-12_345_678", isize_with_underscores(-12_345_678));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_f64p1_with_underscores() {
|
||||
assert_eq!("0.0", f64p1_with_underscores(0f64));
|
||||
assert_eq!("0.0", f64p1_with_underscores(0.00000001));
|
||||
assert_eq!("-0.0", f64p1_with_underscores(-0.00000001));
|
||||
assert_eq!("1.0", f64p1_with_underscores(0.9999999));
|
||||
assert_eq!("-1.0", f64p1_with_underscores(-0.9999999));
|
||||
assert_eq!("345.5", f64p1_with_underscores(345.4999999));
|
||||
assert_eq!("-100_000.0", f64p1_with_underscores(-100_000f64));
|
||||
assert_eq!("123_456_789.1", f64p1_with_underscores(123456789.123456789));
|
||||
assert_eq!("-123_456_789.1", f64p1_with_underscores(-123456789.123456789));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,8 +60,9 @@ pub use rustc_error_messages::{
|
|||
SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
|
||||
};
|
||||
use rustc_hashes::Hash128;
|
||||
use rustc_lint_defs::LintExpectationId;
|
||||
use rustc_hir::HirId;
|
||||
pub use rustc_lint_defs::{Applicability, listify, pluralize};
|
||||
use rustc_lint_defs::{Lint, LintExpectationId};
|
||||
use rustc_macros::{Decodable, Encodable};
|
||||
pub use rustc_span::ErrorGuaranteed;
|
||||
pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
|
||||
|
|
@ -101,6 +102,19 @@ rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
|
|||
#[cfg(target_pointer_width = "64")]
|
||||
rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
|
||||
|
||||
/// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`.
|
||||
/// Always the `TyCtxt`.
|
||||
pub trait LintEmitter: Copy {
|
||||
#[track_caller]
|
||||
fn emit_node_span_lint(
|
||||
self,
|
||||
lint: &'static Lint,
|
||||
hir_id: HirId,
|
||||
span: impl Into<MultiSpan>,
|
||||
decorator: impl for<'a> LintDiagnostic<'a, ()>,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
|
||||
pub enum SuggestionStyle {
|
||||
/// Hide the suggested code when displaying this suggestion inline.
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ expand_feature_not_allowed =
|
|||
expand_feature_removed =
|
||||
feature has been removed
|
||||
.label = feature has been removed
|
||||
.note = removed in {$removed_rustc_version} (you are using {$current_rustc_version}){$pull_note}
|
||||
.reason = {$reason}
|
||||
|
||||
expand_glob_delegation_outside_impls =
|
||||
|
|
@ -112,7 +113,7 @@ expand_meta_var_expr_unrecognized_var =
|
|||
variable `{$key}` is not recognized in meta-variable expression
|
||||
|
||||
expand_missing_fragment_specifier = missing fragment specifier
|
||||
.note = fragment specifiers must be specified in the 2024 edition
|
||||
.note = fragment specifiers must be provided
|
||||
.suggestion_add_fragspec = try adding a specifier here
|
||||
.valid = {$valid}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use rustc_ast::tokenstream::TokenStream;
|
|||
use rustc_ast::visit::{AssocCtxt, Visitor};
|
||||
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
|
||||
use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr};
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
|
||||
use rustc_data_structures::sync;
|
||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
|
||||
use rustc_feature::Features;
|
||||
|
|
@ -727,6 +727,7 @@ pub enum SyntaxExtensionKind {
|
|||
/// A trivial attribute "macro" that does nothing,
|
||||
/// only keeps the attribute and marks it as inert,
|
||||
/// thus making it ineligible for further expansion.
|
||||
/// E.g. `#[default]`, `#[rustfmt::skip]`.
|
||||
NonMacroAttr,
|
||||
|
||||
/// A token-based derive macro.
|
||||
|
|
@ -1189,6 +1190,8 @@ pub struct ExtCtxt<'a> {
|
|||
/// in the AST, but insert it here so that we know
|
||||
/// not to expand it again.
|
||||
pub(super) expanded_inert_attrs: MarkedAttrs,
|
||||
/// `-Zmacro-stats` data.
|
||||
pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals
|
||||
}
|
||||
|
||||
impl<'a> ExtCtxt<'a> {
|
||||
|
|
@ -1218,6 +1221,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
expansions: FxIndexMap::default(),
|
||||
expanded_inert_attrs: MarkedAttrs::new(),
|
||||
buffered_early_lint: vec![],
|
||||
macro_stats: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,9 +80,20 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
|
|||
|
||||
// If the enabled feature has been removed, issue an error.
|
||||
if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) {
|
||||
let pull_note = if let Some(pull) = f.pull {
|
||||
format!(
|
||||
"; see <https://github.com/rust-lang/rust/pull/{}> for more information",
|
||||
pull
|
||||
)
|
||||
} else {
|
||||
"".to_owned()
|
||||
};
|
||||
sess.dcx().emit_err(FeatureRemoved {
|
||||
span: mi.span(),
|
||||
reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
|
||||
removed_rustc_version: f.feature.since,
|
||||
current_rustc_version: sess.cfg_version,
|
||||
pull_note,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,12 +154,16 @@ pub(crate) struct HelperAttributeNameInvalid {
|
|||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(expand_feature_removed, code = E0557)]
|
||||
#[note]
|
||||
pub(crate) struct FeatureRemoved<'a> {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[subdiagnostic]
|
||||
pub reason: Option<FeatureRemovedReason<'a>>,
|
||||
pub removed_rustc_version: &'a str,
|
||||
pub current_rustc_version: &'a str,
|
||||
pub pull_note: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
|
|||
|
|
@ -42,13 +42,22 @@ use crate::module::{
|
|||
DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod,
|
||||
};
|
||||
use crate::placeholders::{PlaceholderExpander, placeholder};
|
||||
use crate::stats::*;
|
||||
|
||||
macro_rules! ast_fragments {
|
||||
(
|
||||
$($Kind:ident($AstTy:ty) {
|
||||
$kind_name:expr;
|
||||
$(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
|
||||
$(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
|
||||
$(one
|
||||
fn $mut_visit_ast:ident;
|
||||
fn $visit_ast:ident;
|
||||
fn $ast_to_string:path;
|
||||
)?
|
||||
$(many
|
||||
fn $flat_map_ast_elt:ident;
|
||||
fn $visit_ast_elt:ident($($args:tt)*);
|
||||
fn $ast_to_string_elt:path;
|
||||
)?
|
||||
fn $make_ast:ident;
|
||||
})*
|
||||
) => {
|
||||
|
|
@ -61,7 +70,7 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
|
||||
/// "Discriminant" of an AST fragment.
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AstFragmentKind {
|
||||
OptExpr,
|
||||
MethodReceiverExpr,
|
||||
|
|
@ -151,6 +160,21 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
V::Result::output()
|
||||
}
|
||||
|
||||
pub(crate) fn to_string(&self) -> String {
|
||||
match self {
|
||||
AstFragment::OptExpr(Some(expr)) => pprust::expr_to_string(expr),
|
||||
AstFragment::OptExpr(None) => unreachable!(),
|
||||
AstFragment::MethodReceiverExpr(expr) => pprust::expr_to_string(expr),
|
||||
$($(AstFragment::$Kind(ast) => $ast_to_string(ast),)?)*
|
||||
$($(
|
||||
AstFragment::$Kind(ast) => {
|
||||
// The closure unwraps a `P` if present, or does nothing otherwise.
|
||||
elems_to_string(&*ast, |ast| $ast_to_string_elt(&*ast))
|
||||
}
|
||||
)?)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
|
||||
|
|
@ -163,76 +187,98 @@ macro_rules! ast_fragments {
|
|||
}
|
||||
|
||||
ast_fragments! {
|
||||
Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
|
||||
Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
|
||||
Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
|
||||
Expr(P<ast::Expr>) {
|
||||
"expression";
|
||||
one fn visit_expr; fn visit_expr; fn pprust::expr_to_string;
|
||||
fn make_expr;
|
||||
}
|
||||
Pat(P<ast::Pat>) {
|
||||
"pattern";
|
||||
one fn visit_pat; fn visit_pat; fn pprust::pat_to_string;
|
||||
fn make_pat;
|
||||
}
|
||||
Ty(P<ast::Ty>) {
|
||||
"type";
|
||||
one fn visit_ty; fn visit_ty; fn pprust::ty_to_string;
|
||||
fn make_ty;
|
||||
}
|
||||
Stmts(SmallVec<[ast::Stmt; 1]>) {
|
||||
"statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts;
|
||||
"statement";
|
||||
many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string;
|
||||
fn make_stmts;
|
||||
}
|
||||
Items(SmallVec<[P<ast::Item>; 1]>) {
|
||||
"item"; many fn flat_map_item; fn visit_item(); fn make_items;
|
||||
"item";
|
||||
many fn flat_map_item; fn visit_item(); fn pprust::item_to_string;
|
||||
fn make_items;
|
||||
}
|
||||
TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"trait item";
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Trait);
|
||||
many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait);
|
||||
fn pprust::assoc_item_to_string;
|
||||
fn make_trait_items;
|
||||
}
|
||||
ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"impl item";
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });
|
||||
many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });
|
||||
fn pprust::assoc_item_to_string;
|
||||
fn make_impl_items;
|
||||
}
|
||||
TraitImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
|
||||
"impl item";
|
||||
many fn flat_map_assoc_item;
|
||||
fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });
|
||||
many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });
|
||||
fn pprust::assoc_item_to_string;
|
||||
fn make_trait_impl_items;
|
||||
}
|
||||
ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) {
|
||||
"foreign item";
|
||||
many fn flat_map_foreign_item;
|
||||
fn visit_foreign_item();
|
||||
many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string;
|
||||
fn make_foreign_items;
|
||||
}
|
||||
Arms(SmallVec<[ast::Arm; 1]>) {
|
||||
"match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
|
||||
"match arm";
|
||||
many fn flat_map_arm; fn visit_arm(); fn unreachable_to_string;
|
||||
fn make_arms;
|
||||
}
|
||||
ExprFields(SmallVec<[ast::ExprField; 1]>) {
|
||||
"field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields;
|
||||
"field expression";
|
||||
many fn flat_map_expr_field; fn visit_expr_field(); fn unreachable_to_string;
|
||||
fn make_expr_fields;
|
||||
}
|
||||
PatFields(SmallVec<[ast::PatField; 1]>) {
|
||||
"field pattern";
|
||||
many fn flat_map_pat_field;
|
||||
fn visit_pat_field();
|
||||
many fn flat_map_pat_field; fn visit_pat_field(); fn unreachable_to_string;
|
||||
fn make_pat_fields;
|
||||
}
|
||||
GenericParams(SmallVec<[ast::GenericParam; 1]>) {
|
||||
"generic parameter";
|
||||
many fn flat_map_generic_param;
|
||||
fn visit_generic_param();
|
||||
many fn flat_map_generic_param; fn visit_generic_param(); fn unreachable_to_string;
|
||||
fn make_generic_params;
|
||||
}
|
||||
Params(SmallVec<[ast::Param; 1]>) {
|
||||
"function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
|
||||
"function parameter";
|
||||
many fn flat_map_param; fn visit_param(); fn unreachable_to_string;
|
||||
fn make_params;
|
||||
}
|
||||
FieldDefs(SmallVec<[ast::FieldDef; 1]>) {
|
||||
"field";
|
||||
many fn flat_map_field_def;
|
||||
fn visit_field_def();
|
||||
many fn flat_map_field_def; fn visit_field_def(); fn unreachable_to_string;
|
||||
fn make_field_defs;
|
||||
}
|
||||
Variants(SmallVec<[ast::Variant; 1]>) {
|
||||
"variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
|
||||
"variant"; many fn flat_map_variant; fn visit_variant(); fn unreachable_to_string;
|
||||
fn make_variants;
|
||||
}
|
||||
WherePredicates(SmallVec<[ast::WherePredicate; 1]>) {
|
||||
"where predicate";
|
||||
many fn flat_map_where_predicate;
|
||||
fn visit_where_predicate();
|
||||
many fn flat_map_where_predicate; fn visit_where_predicate(); fn unreachable_to_string;
|
||||
fn make_where_predicates;
|
||||
}
|
||||
Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
|
||||
}
|
||||
Crate(ast::Crate) {
|
||||
"crate";
|
||||
one fn visit_crate; fn visit_crate; fn unreachable_to_string;
|
||||
fn make_crate;
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SupportsMacroExpansion {
|
||||
|
|
@ -270,7 +316,7 @@ impl AstFragmentKind {
|
|||
}
|
||||
}
|
||||
|
||||
fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
|
||||
pub(crate) fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
|
||||
self,
|
||||
items: I,
|
||||
) -> AstFragment {
|
||||
|
|
@ -686,13 +732,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar));
|
||||
}
|
||||
|
||||
let macro_stats = self.cx.sess.opts.unstable_opts.macro_stats;
|
||||
|
||||
let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
|
||||
ExpandResult::Ready(match invoc.kind {
|
||||
InvocationKind::Bang { mac, span } => match ext {
|
||||
SyntaxExtensionKind::Bang(expander) => {
|
||||
match expander.expand(self.cx, span, mac.args.tokens.clone()) {
|
||||
Ok(tok_result) => {
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
|
||||
let fragment =
|
||||
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span);
|
||||
if macro_stats {
|
||||
update_bang_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
mac,
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
|
||||
}
|
||||
|
|
@ -708,13 +767,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
});
|
||||
}
|
||||
};
|
||||
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
|
||||
result
|
||||
if let Some(fragment) = fragment_kind.make_from(tok_result) {
|
||||
if macro_stats {
|
||||
update_bang_macro_stats(self.cx, fragment_kind, span, mac, &fragment);
|
||||
}
|
||||
fragment
|
||||
} else {
|
||||
let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
|
||||
fragment_kind.dummy(span, guar)
|
||||
};
|
||||
result
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
|
@ -746,24 +807,39 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
_ => item.to_tokens(),
|
||||
};
|
||||
let attr_item = attr.unwrap_normal_item();
|
||||
let attr_item = attr.get_normal_item();
|
||||
if let AttrArgs::Eq { .. } = attr_item.args {
|
||||
self.cx.dcx().emit_err(UnsupportedKeyValue { span });
|
||||
}
|
||||
let inner_tokens = attr_item.args.inner_tokens();
|
||||
match expander.expand(self.cx, span, inner_tokens, tokens) {
|
||||
Ok(tok_result) => self.parse_ast_fragment(
|
||||
tok_result,
|
||||
fragment_kind,
|
||||
&attr_item.path,
|
||||
span,
|
||||
),
|
||||
Ok(tok_result) => {
|
||||
let fragment = self.parse_ast_fragment(
|
||||
tok_result,
|
||||
fragment_kind,
|
||||
&attr_item.path,
|
||||
span,
|
||||
);
|
||||
if macro_stats {
|
||||
update_attr_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
&attr_item.path,
|
||||
&attr,
|
||||
item,
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
|
||||
}
|
||||
}
|
||||
SyntaxExtensionKind::LegacyAttr(expander) => {
|
||||
match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
|
||||
Ok(meta) => {
|
||||
let item_clone = macro_stats.then(|| item.clone());
|
||||
let items = match expander.expand(self.cx, span, &meta, item, false) {
|
||||
ExpandResult::Ready(items) => items,
|
||||
ExpandResult::Retry(item) => {
|
||||
|
|
@ -782,7 +858,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span });
|
||||
fragment_kind.dummy(span, guar)
|
||||
} else {
|
||||
fragment_kind.expect_from_annotatables(items)
|
||||
let fragment = fragment_kind.expect_from_annotatables(items);
|
||||
if macro_stats {
|
||||
update_attr_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
&meta.path,
|
||||
&attr,
|
||||
item_clone.unwrap(),
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
|
|
@ -792,6 +880,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
SyntaxExtensionKind::NonMacroAttr => {
|
||||
// `-Zmacro-stats` ignores these because they don't do any real expansion.
|
||||
self.cx.expanded_inert_attrs.mark(&attr);
|
||||
item.visit_attrs(|attrs| attrs.insert(pos, attr));
|
||||
fragment_kind.expect_from_annotatables(iter::once(item))
|
||||
|
|
@ -822,7 +911,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
});
|
||||
}
|
||||
};
|
||||
fragment_kind.expect_from_annotatables(items)
|
||||
let fragment = fragment_kind.expect_from_annotatables(items);
|
||||
if macro_stats {
|
||||
update_derive_macro_stats(
|
||||
self.cx,
|
||||
fragment_kind,
|
||||
span,
|
||||
&meta.path,
|
||||
&fragment,
|
||||
);
|
||||
}
|
||||
fragment
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
|
@ -852,6 +951,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
let single_delegations = build_single_delegations::<Node>(
|
||||
self.cx, deleg, &item, &suffixes, item.span, true,
|
||||
);
|
||||
// `-Zmacro-stats` ignores these because they don't seem important.
|
||||
fragment_kind.expect_from_annotatables(
|
||||
single_delegations
|
||||
.map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })),
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ mod errors;
|
|||
mod mbe;
|
||||
mod placeholders;
|
||||
mod proc_macro_server;
|
||||
mod stats;
|
||||
|
||||
pub use mbe::macro_rules::compile_declarative_macro;
|
||||
pub mod base;
|
||||
|
|
|
|||
|
|
@ -112,9 +112,8 @@ use rustc_ast::{DUMMY_NODE_ID, NodeId};
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_errors::MultiSpan;
|
||||
use rustc_lint_defs::BuiltinLintDiag;
|
||||
use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
|
||||
use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
@ -266,23 +265,11 @@ fn check_binders(
|
|||
// Similarly, this can only happen when checking a toplevel macro.
|
||||
TokenTree::MetaVarDecl(span, name, kind) => {
|
||||
if kind.is_none() && node_id != DUMMY_NODE_ID {
|
||||
// FIXME: Report this as a hard error eventually and remove equivalent errors from
|
||||
// `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once
|
||||
// as a hard error and then once as a buffered lint.
|
||||
if span.edition() >= Edition::Edition2024 {
|
||||
psess.dcx().emit_err(errors::MissingFragmentSpecifier {
|
||||
span,
|
||||
add_span: span.shrink_to_hi(),
|
||||
valid: VALID_FRAGMENT_NAMES_MSG,
|
||||
});
|
||||
} else {
|
||||
psess.buffer_lint(
|
||||
MISSING_FRAGMENT_SPECIFIER,
|
||||
span,
|
||||
node_id,
|
||||
BuiltinLintDiag::MissingFragmentSpecifier,
|
||||
);
|
||||
}
|
||||
psess.dcx().emit_err(errors::MissingFragmentSpecifier {
|
||||
span,
|
||||
add_span: span.shrink_to_hi(),
|
||||
valid: VALID_FRAGMENT_NAMES_MSG,
|
||||
});
|
||||
}
|
||||
if !macros.is_empty() {
|
||||
psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");
|
||||
|
|
|
|||
171
compiler/rustc_expand/src/stats.rs
Normal file
171
compiler/rustc_expand/src/stats.rs
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{self as ast, DUMMY_NODE_ID, Expr, ExprKind};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::{Span, Symbol, kw, sym};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::base::{Annotatable, ExtCtxt};
|
||||
use crate::expand::{AstFragment, AstFragmentKind};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MacroStat {
|
||||
/// Number of uses of the macro.
|
||||
pub uses: usize,
|
||||
|
||||
/// Net increase in number of lines of code (when pretty-printed), i.e.
|
||||
/// `lines(output) - lines(invocation)`. Can be negative because a macro
|
||||
/// output may be smaller than the invocation.
|
||||
pub lines: isize,
|
||||
|
||||
/// Net increase in number of lines of code (when pretty-printed), i.e.
|
||||
/// `bytes(output) - bytes(invocation)`. Can be negative because a macro
|
||||
/// output may be smaller than the invocation.
|
||||
pub bytes: isize,
|
||||
}
|
||||
|
||||
pub(crate) fn elems_to_string<T>(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> String) -> String {
|
||||
let mut s = String::new();
|
||||
for (i, elem) in elems.iter().enumerate() {
|
||||
if i > 0 {
|
||||
s.push('\n');
|
||||
}
|
||||
s.push_str(&f(elem));
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
pub(crate) fn unreachable_to_string<T>(_: &T) -> String {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn update_bang_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
mac: P<ast::MacCall>,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
// Does this path match any of the include macros, e.g. `include!`?
|
||||
// Ignore them. They would have large numbers but are entirely
|
||||
// unsurprising and uninteresting.
|
||||
let is_include_path = mac.path == sym::include
|
||||
|| mac.path == sym::include_bytes
|
||||
|| mac.path == sym::include_str
|
||||
|| mac.path == [sym::std, sym::include].as_slice() // std::include
|
||||
|| mac.path == [sym::std, sym::include_bytes].as_slice() // std::include_bytes
|
||||
|| mac.path == [sym::std, sym::include_str].as_slice(); // std::include_str
|
||||
if is_include_path {
|
||||
return;
|
||||
}
|
||||
|
||||
// The call itself (e.g. `println!("hi")`) is the input. Need to wrap
|
||||
// `mac` in something printable; `ast::Expr` is as good as anything
|
||||
// else.
|
||||
let expr = Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::MacCall(mac),
|
||||
span: Default::default(),
|
||||
attrs: Default::default(),
|
||||
tokens: None,
|
||||
};
|
||||
let input = pprust::expr_to_string(&expr);
|
||||
|
||||
// Get `mac` back out of `expr`.
|
||||
let ast::Expr { kind: ExprKind::MacCall(mac), .. } = expr else { unreachable!() };
|
||||
|
||||
update_macro_stats(ecx, MacroKind::Bang, fragment_kind, span, &mac.path, &input, fragment);
|
||||
}
|
||||
|
||||
pub(crate) fn update_attr_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
path: &ast::Path,
|
||||
attr: &ast::Attribute,
|
||||
item: Annotatable,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
// Does this path match `#[derive(...)]` in any of its forms? If so,
|
||||
// ignore it because the individual derives will go through the
|
||||
// `Invocation::Derive` handling separately.
|
||||
let is_derive_path = *path == sym::derive
|
||||
// ::core::prelude::v1::derive
|
||||
|| *path == [kw::PathRoot, sym::core, sym::prelude, sym::v1, sym::derive].as_slice();
|
||||
if is_derive_path {
|
||||
return;
|
||||
}
|
||||
|
||||
// The attribute plus the item itself constitute the input, which we
|
||||
// measure.
|
||||
let input = format!(
|
||||
"{}\n{}",
|
||||
pprust::attribute_to_string(attr),
|
||||
fragment_kind.expect_from_annotatables(iter::once(item)).to_string(),
|
||||
);
|
||||
update_macro_stats(ecx, MacroKind::Attr, fragment_kind, span, path, &input, fragment);
|
||||
}
|
||||
|
||||
pub(crate) fn update_derive_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
path: &ast::Path,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
// Use something like `#[derive(Clone)]` for the measured input, even
|
||||
// though it may have actually appeared in a multi-derive attribute
|
||||
// like `#[derive(Clone, Copy, Debug)]`.
|
||||
let input = format!("#[derive({})]", pprust::path_to_string(path));
|
||||
update_macro_stats(ecx, MacroKind::Derive, fragment_kind, span, path, &input, fragment);
|
||||
}
|
||||
|
||||
pub(crate) fn update_macro_stats(
|
||||
ecx: &mut ExtCtxt<'_>,
|
||||
macro_kind: MacroKind,
|
||||
fragment_kind: AstFragmentKind,
|
||||
span: Span,
|
||||
path: &ast::Path,
|
||||
input: &str,
|
||||
fragment: &AstFragment,
|
||||
) {
|
||||
fn lines_and_bytes(s: &str) -> (usize, usize) {
|
||||
(s.trim_end().split('\n').count(), s.len())
|
||||
}
|
||||
|
||||
// Measure the size of the output by pretty-printing it and counting
|
||||
// the lines and bytes.
|
||||
let name = Symbol::intern(&pprust::path_to_string(path));
|
||||
let output = fragment.to_string();
|
||||
let (in_l, in_b) = lines_and_bytes(input);
|
||||
let (out_l, out_b) = lines_and_bytes(&output);
|
||||
|
||||
// This code is useful for debugging `-Zmacro-stats`. For every
|
||||
// invocation it prints the full input and output.
|
||||
if false {
|
||||
let name = ExpnKind::Macro(macro_kind, name).descr();
|
||||
let crate_name = &ecx.ecfg.crate_name;
|
||||
let span = ecx
|
||||
.sess
|
||||
.source_map()
|
||||
.span_to_string(span, rustc_span::FileNameDisplayPreference::Local);
|
||||
eprint!(
|
||||
"\
|
||||
-------------------------------\n\
|
||||
{name}: [{crate_name}] ({fragment_kind:?}) {span}\n\
|
||||
-------------------------------\n\
|
||||
{input}\n\
|
||||
-- ({in_l} lines, {in_b} bytes) --> ({out_l} lines, {out_b} bytes) --\n\
|
||||
{output}\n\
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
// The recorded size is the difference between the input and the output.
|
||||
let entry = ecx.macro_stats.entry((name, macro_kind)).or_insert(MacroStat::default());
|
||||
entry.uses += 1;
|
||||
entry.lines += out_l as isize - in_l as isize;
|
||||
entry.bytes += out_b as isize - in_b as isize;
|
||||
}
|
||||
|
|
@ -259,6 +259,8 @@ declare_features! (
|
|||
/// Allows some increased flexibility in the name resolution rules,
|
||||
/// especially around globs and shadowing (RFC 1560).
|
||||
(accepted, item_like_imports, "1.15.0", Some(35120)),
|
||||
// Allows using the `kl` and `widekl` target features and the associated intrinsics
|
||||
(accepted, keylocker_x86, "CURRENT_RUSTC_VERSION", Some(134813)),
|
||||
/// Allows `'a: { break 'a; }`.
|
||||
(accepted, label_break_value, "1.65.0", Some(48594)),
|
||||
/// Allows `let...else` statements.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::{Features, Stability};
|
||||
use crate::Features;
|
||||
|
||||
type GateFn = fn(&Features) -> bool;
|
||||
|
||||
|
|
@ -94,34 +94,23 @@ pub enum AttributeSafety {
|
|||
Unsafe { unsafe_since: Option<Edition> },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub enum AttributeGate {
|
||||
/// Is gated by a given feature gate, reason
|
||||
/// and function to check if enabled
|
||||
Gated(Stability, Symbol, &'static str, fn(&Features) -> bool),
|
||||
|
||||
/// A gated attribute which requires a feature gate to be enabled.
|
||||
Gated {
|
||||
/// The feature gate, for example `#![feature(rustc_attrs)]` for rustc_* attributes.
|
||||
feature: Symbol,
|
||||
/// The error message displayed when an attempt is made to use the attribute without its feature gate.
|
||||
message: &'static str,
|
||||
/// Check function to be called during the `PostExpansionVisitor` pass.
|
||||
check: fn(&Features) -> bool,
|
||||
/// Notes to be displayed when an attempt is made to use the attribute without its feature gate.
|
||||
notes: &'static [&'static str],
|
||||
},
|
||||
/// Ungated attribute, can be used on all release channels
|
||||
Ungated,
|
||||
}
|
||||
|
||||
// fn() is not Debug
|
||||
impl std::fmt::Debug for AttributeGate {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
Self::Gated(ref stab, name, expl, _) => {
|
||||
write!(fmt, "Gated({stab:?}, {name}, {expl})")
|
||||
}
|
||||
Self::Ungated => write!(fmt, "Ungated"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AttributeGate {
|
||||
fn is_deprecated(&self) -> bool {
|
||||
matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..))
|
||||
}
|
||||
}
|
||||
|
||||
/// A template that the attribute input must match.
|
||||
/// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
|
||||
#[derive(Clone, Copy, Default)]
|
||||
|
|
@ -247,7 +236,7 @@ macro_rules! ungated {
|
|||
}
|
||||
|
||||
macro_rules! gated {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
|
|
@ -255,10 +244,15 @@ macro_rules! gated {
|
|||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
|
||||
gate: Gated {
|
||||
feature: sym::$gate,
|
||||
message: $message,
|
||||
check: Features::$gate,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
|
||||
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
|
|
@ -266,10 +260,15 @@ macro_rules! gated {
|
|||
safety: AttributeSafety::Unsafe { unsafe_since: None },
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
|
||||
gate: Gated {
|
||||
feature: sym::$attr,
|
||||
message: $message,
|
||||
check: Features::$attr,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
|
|
@ -277,10 +276,15 @@ macro_rules! gated {
|
|||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
|
||||
gate: Gated {
|
||||
feature: sym::$gate,
|
||||
message: $message,
|
||||
check: Features::$gate,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
|
|
@ -288,7 +292,12 @@ macro_rules! gated {
|
|||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
|
||||
gate: Gated {
|
||||
feature: sym::$attr,
|
||||
message: $message,
|
||||
check: Features::$attr,
|
||||
notes: &[],
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -304,12 +313,11 @@ macro_rules! rustc_attr {
|
|||
concat!(
|
||||
"the `#[",
|
||||
stringify!($attr),
|
||||
"]` attribute is just used for rustc unit tests \
|
||||
and will never be stable",
|
||||
"]` attribute is used for rustc unit tests"
|
||||
),
|
||||
)
|
||||
};
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
|
||||
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => {
|
||||
BuiltinAttribute {
|
||||
name: sym::$attr,
|
||||
encode_cross_crate: $encode_cross_crate,
|
||||
|
|
@ -317,7 +325,17 @@ macro_rules! rustc_attr {
|
|||
safety: AttributeSafety::Normal,
|
||||
template: $tpl,
|
||||
duplicates: $duplicates,
|
||||
gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs),
|
||||
gate: Gated {
|
||||
feature: sym::rustc_attrs,
|
||||
message: "use of an internal attribute",
|
||||
check: Features::rustc_attrs,
|
||||
notes: &[
|
||||
concat!("the `#[",
|
||||
stringify!($attr),
|
||||
"]` attribute is an internal implementation detail that will never be stable"),
|
||||
$($notes),*
|
||||
]
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -328,9 +346,6 @@ macro_rules! experimental {
|
|||
};
|
||||
}
|
||||
|
||||
const IMPL_DETAIL: &str = "internal implementation detail";
|
||||
const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum EncodeCrossCrate {
|
||||
Yes,
|
||||
|
|
@ -668,7 +683,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"rustc_deprecated_safe_2024 is supposed to be used in libstd only",
|
||||
"`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_pub_transparent, Normal, template!(Word),
|
||||
|
|
@ -695,7 +710,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
|
||||
never type stabilization, and will never be stable"
|
||||
never type stabilization"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
|
|
@ -704,23 +719,23 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
|
||||
rustc_attr!(
|
||||
rustc_allocator, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_nounwind, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_reallocator, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_deallocator, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
gated!(
|
||||
default_lib_allocator, Normal, template!(Word), WarnFollowing,
|
||||
|
|
@ -762,7 +777,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
rustc_attr!(
|
||||
rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
|
|
@ -772,11 +787,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_builtin_macro, Normal,
|
||||
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, IMPL_DETAIL
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::No,
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_macro_transparency, Normal,
|
||||
|
|
@ -786,7 +801,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_autodiff, Normal,
|
||||
template!(Word, List: r#""...""#), DuplicatesOk,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
|
||||
// The attributes are not gated, to avoid stability errors, but they cannot be used in stable
|
||||
|
|
@ -812,54 +827,53 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
NameValueStr: "message"
|
||||
),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
INTERNAL_UNSTABLE
|
||||
"see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_confusables, Normal,
|
||||
template!(List: r#""name1", "name2", ..."#),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
INTERNAL_UNSTABLE,
|
||||
),
|
||||
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
|
||||
rustc_attr!(
|
||||
rustc_conversion_suggestion, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Prevents field reads in the marked trait or method to be considered
|
||||
// during dead code analysis.
|
||||
rustc_attr!(
|
||||
rustc_trivial_field_reads, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::potential_query_instability` lint to warn methods which
|
||||
// might not be stable during incremental compilation.
|
||||
rustc_attr!(
|
||||
rustc_lint_query_instability, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::untracked_query_information` lint to warn methods which
|
||||
// might not be stable during incremental compilation.
|
||||
rustc_attr!(
|
||||
rustc_lint_untracked_query_information, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
|
||||
// APIs. Any function with this attribute will be checked by that lint.
|
||||
rustc_attr!(
|
||||
rustc_lint_diagnostics, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
|
||||
// types (as well as any others in future).
|
||||
rustc_attr!(
|
||||
rustc_lint_opt_ty, Normal, template!(Word),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Used by the `rustc::bad_opt_access` lint on fields
|
||||
// types (as well as any others in future).
|
||||
rustc_attr!(
|
||||
rustc_lint_opt_deny_field_access, Normal, template!(List: "message"),
|
||||
WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
WarnFollowing, EncodeCrossCrate::Yes,
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
|
|
@ -868,28 +882,30 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
|
||||
rustc_attr!(
|
||||
rustc_promotable, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::No, IMPL_DETAIL),
|
||||
EncodeCrossCrate::No, ),
|
||||
rustc_attr!(
|
||||
rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes,
|
||||
),
|
||||
// Do not const-check this function's body. It will always get replaced during CTFE.
|
||||
rustc_attr!(
|
||||
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
|
||||
),
|
||||
// Ensure the argument to this function is &&str during const-check.
|
||||
rustc_attr!(
|
||||
rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
|
||||
EncodeCrossCrate::Yes, "`#[rustc_const_panic_str]` ensures the argument to this function is &&str during const-check",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_const_stable_indirect, Normal,
|
||||
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
|
||||
template!(Word),
|
||||
WarnFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"this is an internal implementation detail",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_intrinsic_const_stable_indirect, Normal,
|
||||
template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
|
||||
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
|
||||
),
|
||||
gated!(
|
||||
rustc_allow_const_fn_unstable, Normal,
|
||||
|
|
@ -905,21 +921,21 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
|
||||
niche optimizations in libcore and libstd and will never be stable",
|
||||
niche optimizations in the standard library",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
|
||||
niche optimizations in libcore and libstd and will never be stable",
|
||||
niche optimizations in the standard library",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
|
||||
guaranteed niche optimizations in libcore and libstd and will never be stable\n\
|
||||
(note that the compiler does not even check whether the type indeed is being non-null-optimized; \
|
||||
it is your responsibility to ensure that the attribute is only used on types that are optimized)",
|
||||
guaranteed niche optimizations in the standard library",
|
||||
"the compiler does not even check whether the type indeed is being non-null-optimized; \
|
||||
it is your responsibility to ensure that the attribute is only used on types that are optimized",
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
|
|
@ -932,17 +948,17 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
|
||||
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
|
||||
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes,
|
||||
"#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
|
||||
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
|
|
@ -950,15 +966,15 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
rustc_attr!(
|
||||
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
|
||||
"#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
|
||||
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
|
||||
"#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver."
|
||||
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
|
||||
"#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
|
||||
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl."
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
|
||||
|
|
@ -970,7 +986,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
|
||||
"`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_do_not_implement_via_object,
|
||||
|
|
@ -978,14 +994,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
|
||||
"`#[rustc_do_not_implement_via_object]` opts out of the automatic trait impl for trait objects \
|
||||
(`impl Trait for dyn Trait`)"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
|
||||
the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
|
||||
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
|
||||
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`."
|
||||
),
|
||||
|
||||
BuiltinAttribute {
|
||||
|
|
@ -996,12 +1012,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
safety: AttributeSafety::Normal,
|
||||
template: template!(NameValueStr: "name"),
|
||||
duplicates: ErrorFollowing,
|
||||
gate: Gated(
|
||||
Stability::Unstable,
|
||||
sym::rustc_attrs,
|
||||
"diagnostic items compiler internal support for linting",
|
||||
Features::rustc_attrs,
|
||||
),
|
||||
gate: Gated{
|
||||
feature: sym::rustc_attrs,
|
||||
message: "use of an internal attribute",
|
||||
check: Features::rustc_attrs,
|
||||
notes: &["the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types \
|
||||
from the standard library for diagnostic purposes"],
|
||||
},
|
||||
},
|
||||
gated!(
|
||||
// Used in resolve:
|
||||
|
|
@ -1015,14 +1032,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
|
||||
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
|
||||
overflow checking behavior of several libcore functions that are inlined \
|
||||
across crates and will never be stable",
|
||||
overflow checking behavior of several functions in the standard library that are inlined \
|
||||
across crates",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_reservation_impl, Normal,
|
||||
template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
"the `#[rustc_reservation_impl]` attribute is internally used \
|
||||
for reserving for `for<T> From<!> for T` impl"
|
||||
for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
|
||||
|
|
@ -1053,12 +1070,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
|
||||
ErrorFollowing, EncodeCrossCrate::No,
|
||||
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
|
||||
definition of a trait, it's currently in experimental form and should be changed before \
|
||||
being exposed outside of the std"
|
||||
definition of a trait. Its syntax and semantics are highly experimental and will be \
|
||||
subject to change before stabilization",
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
|
||||
EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#,
|
||||
EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \
|
||||
to provide a way to generate documentation for primitive types",
|
||||
),
|
||||
gated!(
|
||||
rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
|
||||
|
|
@ -1066,11 +1084,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
rustc_attr!(
|
||||
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
|
||||
"#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
|
||||
"`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
|
||||
"#[rustc_force_inline] forces a free function to be inlined"
|
||||
"`#[rustc_force_inline]` forces a free function to be inlined"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
|
|
@ -1209,10 +1227,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
),
|
||||
];
|
||||
|
||||
pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
|
||||
BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
|
||||
}
|
||||
|
||||
pub fn is_builtin_attr_name(name: Symbol) -> bool {
|
||||
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,14 +40,6 @@ pub struct Feature {
|
|||
issue: Option<NonZero<u32>>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Stability {
|
||||
Unstable,
|
||||
// First argument is tracking issue link; second argument is an optional
|
||||
// help message, which defaults to "remove this attribute".
|
||||
Deprecated(&'static str, Option<&'static str>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Hash)]
|
||||
pub enum UnstableFeatures {
|
||||
/// Disallow use of unstable features, as on beta/stable channels.
|
||||
|
|
@ -144,9 +136,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
|
|||
pub use accepted::ACCEPTED_LANG_FEATURES;
|
||||
pub use builtin_attrs::{
|
||||
AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
|
||||
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes,
|
||||
encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
|
||||
is_valid_for_get_attr,
|
||||
BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate,
|
||||
find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr,
|
||||
};
|
||||
pub use removed::REMOVED_LANG_FEATURES;
|
||||
pub use unstable::{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
//! List of the removed feature gates.
|
||||
|
||||
use std::num::{NonZero, NonZeroU32};
|
||||
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{Feature, to_nonzero};
|
||||
|
|
@ -7,11 +9,21 @@ use super::{Feature, to_nonzero};
|
|||
pub struct RemovedFeature {
|
||||
pub feature: Feature,
|
||||
pub reason: Option<&'static str>,
|
||||
pub pull: Option<NonZero<u32>>,
|
||||
}
|
||||
|
||||
macro_rules! opt_nonzero_u32 {
|
||||
() => {
|
||||
None
|
||||
};
|
||||
($val:expr) => {
|
||||
Some(NonZeroU32::new($val).unwrap())
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! declare_features {
|
||||
($(
|
||||
$(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr),
|
||||
$(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr $(, $pull:expr)?),
|
||||
)+) => {
|
||||
/// Formerly unstable features that have now been removed.
|
||||
pub static REMOVED_LANG_FEATURES: &[RemovedFeature] = &[
|
||||
|
|
@ -21,7 +33,8 @@ macro_rules! declare_features {
|
|||
since: $ver,
|
||||
issue: to_nonzero($issue),
|
||||
},
|
||||
reason: $reason
|
||||
reason: $reason,
|
||||
pull: opt_nonzero_u32!($($pull)?),
|
||||
}),+
|
||||
];
|
||||
};
|
||||
|
|
@ -40,64 +53,64 @@ declare_features! (
|
|||
// version they got originally added in.)
|
||||
|
||||
/// Allows using the `amdgpu-kernel` ABI.
|
||||
(removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None),
|
||||
(removed, advanced_slice_patterns, "1.0.0", Some(62254),
|
||||
Some("merged into `#![feature(slice_patterns)]`")),
|
||||
(removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None, 120495),
|
||||
(removed, advanced_slice_patterns, "1.42.0", Some(62254),
|
||||
Some("merged into `#![feature(slice_patterns)]`"), 67712),
|
||||
(removed, allocator, "1.0.0", None, None),
|
||||
/// Allows a test to fail without failing the whole suite.
|
||||
(removed, allow_fail, "1.19.0", Some(46488), Some("removed due to no clear use cases")),
|
||||
(removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416),
|
||||
(removed, await_macro, "1.38.0", Some(50547),
|
||||
Some("subsumed by `.await` syntax")),
|
||||
Some("subsumed by `.await` syntax"), 62293),
|
||||
/// Allows using the `box $expr` syntax.
|
||||
(removed, box_syntax, "1.70.0", Some(49733), Some("replaced with `#[rustc_box]`")),
|
||||
(removed, box_syntax, "1.70.0", Some(49733), Some("replaced with `#[rustc_box]`"), 108471),
|
||||
/// Allows capturing disjoint fields in a closure/coroutine (RFC 2229).
|
||||
(removed, capture_disjoint_fields, "1.49.0", Some(53488), Some("stabilized in Rust 2021")),
|
||||
(removed, capture_disjoint_fields, "1.69.0", Some(53488), Some("stabilized in Rust 2021"), 108550),
|
||||
/// Allows comparing raw pointers during const eval.
|
||||
(removed, const_compare_raw_pointers, "1.46.0", Some(53020),
|
||||
Some("cannot be allowed in const eval in any meaningful way")),
|
||||
Some("cannot be allowed in const eval in any meaningful way"), 73398),
|
||||
/// Allows limiting the evaluation steps of const expressions
|
||||
(removed, const_eval_limit, "1.43.0", Some(67217), Some("removed the limit entirely")),
|
||||
(removed, const_eval_limit, "1.72.0", Some(67217), Some("removed the limit entirely"), 103877),
|
||||
/// Allows non-trivial generic constants which have to be manually propagated upwards.
|
||||
(removed, const_evaluatable_checked, "1.48.0", Some(76560), Some("renamed to `generic_const_exprs`")),
|
||||
(removed, const_evaluatable_checked, "1.56.0", Some(76560), Some("renamed to `generic_const_exprs`"), 88369),
|
||||
/// Allows the definition of `const` functions with some advanced features.
|
||||
(removed, const_fn, "1.54.0", Some(57563),
|
||||
Some("split into finer-grained feature gates")),
|
||||
Some("split into finer-grained feature gates"), 85109),
|
||||
/// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`).
|
||||
(removed, const_generics, "1.34.0", Some(44580),
|
||||
Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")),
|
||||
(removed, const_generics, "1.56.0", Some(44580),
|
||||
Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`"), 88369),
|
||||
/// Allows `[x; N]` where `x` is a constant (RFC 2203).
|
||||
(removed, const_in_array_repeat_expressions, "1.37.0", Some(49147),
|
||||
Some("removed due to causing promotable bugs")),
|
||||
(removed, const_in_array_repeat_expressions, "1.51.0", Some(49147),
|
||||
Some("removed due to causing promotable bugs"), 80404),
|
||||
/// Allows casting raw pointers to `usize` during const eval.
|
||||
(removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910),
|
||||
Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")),
|
||||
Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported"), 87020),
|
||||
/// Allows `T: ?const Trait` syntax in bounds.
|
||||
(removed, const_trait_bound_opt_out, "1.42.0", Some(67794),
|
||||
Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
|
||||
(removed, const_trait_bound_opt_out, "1.56.0", Some(67794),
|
||||
Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]"), 88328),
|
||||
/// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
|
||||
(removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`")),
|
||||
(removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`"), 97254),
|
||||
/// Allows using custom attributes (RFC 572).
|
||||
(removed, custom_attribute, "1.0.0", Some(29642),
|
||||
Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
|
||||
Some("removed in favor of `#![register_tool]` and `#![register_attr]`"), 66070),
|
||||
/// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
|
||||
(removed, custom_derive, "1.32.0", Some(29644),
|
||||
Some("subsumed by `#[proc_macro_derive]`")),
|
||||
/// Allows default type parameters to influence type inference.
|
||||
(removed, default_type_parameter_fallback, "1.82.0", Some(27336),
|
||||
Some("never properly implemented; requires significant design work")),
|
||||
Some("never properly implemented; requires significant design work"), 127655),
|
||||
/// Allows deriving traits as per `SmartPointer` specification
|
||||
(removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")),
|
||||
(removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284),
|
||||
/// Allows using `#[doc(keyword = "...")]`.
|
||||
(removed, doc_keyword, "1.28.0", Some(51315),
|
||||
Some("merged into `#![feature(rustdoc_internals)]`")),
|
||||
(removed, doc_keyword, "1.58.0", Some(51315),
|
||||
Some("merged into `#![feature(rustdoc_internals)]`"), 90420),
|
||||
/// Allows using `doc(primitive)` without a future-incompat warning.
|
||||
(removed, doc_primitive, "1.56.0", Some(88070),
|
||||
Some("merged into `#![feature(rustdoc_internals)]`")),
|
||||
(removed, doc_primitive, "1.58.0", Some(88070),
|
||||
Some("merged into `#![feature(rustdoc_internals)]`"), 90420),
|
||||
/// Allows `#[doc(spotlight)]`.
|
||||
/// The attribute was renamed to `#[doc(notable_trait)]`
|
||||
/// and the feature to `doc_notable_trait`.
|
||||
(removed, doc_spotlight, "1.22.0", Some(45040),
|
||||
Some("renamed to `doc_notable_trait`")),
|
||||
(removed, doc_spotlight, "1.53.0", Some(45040),
|
||||
Some("renamed to `doc_notable_trait`"), 80965),
|
||||
/// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
|
||||
(removed, dropck_parametricity, "1.38.0", Some(28498), None),
|
||||
/// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1].
|
||||
|
|
@ -107,161 +120,162 @@ declare_features! (
|
|||
/// Renamed from `object_safe_for_dispatch`.
|
||||
///
|
||||
/// [^1]: Formerly known as "object safe".
|
||||
(removed, dyn_compatible_for_dispatch, "1.83.0", Some(43561),
|
||||
Some("removed, not used heavily and represented additional complexity in dyn compatibility")),
|
||||
(removed, dyn_compatible_for_dispatch, "1.87.0", Some(43561),
|
||||
Some("removed, not used heavily and represented additional complexity in dyn compatibility"), 136522),
|
||||
/// Uses generic effect parameters for ~const bounds
|
||||
(removed, effects, "1.84.0", Some(102090),
|
||||
Some("removed, redundant with `#![feature(const_trait_impl)]`")),
|
||||
Some("removed, redundant with `#![feature(const_trait_impl)]`"), 132479),
|
||||
/// Allows defining `existential type`s.
|
||||
(removed, existential_type, "1.38.0", Some(63063),
|
||||
Some("removed in favor of `#![feature(type_alias_impl_trait)]`")),
|
||||
/// Paths of the form: `extern::foo::bar`
|
||||
(removed, extern_in_paths, "1.33.0", Some(55600),
|
||||
Some("subsumed by `::foo::bar` paths")),
|
||||
Some("subsumed by `::foo::bar` paths"), 57572),
|
||||
/// Allows `#[doc(include = "some-file")]`.
|
||||
(removed, external_doc, "1.54.0", Some(44732),
|
||||
Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
|
||||
Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations"), 85457),
|
||||
/// Allows using `#[ffi_returns_twice]` on foreign functions.
|
||||
(removed, ffi_returns_twice, "1.78.0", Some(58314),
|
||||
Some("being investigated by the ffi-unwind project group")),
|
||||
Some("being investigated by the ffi-unwind project group"), 120502),
|
||||
/// Allows generators to be cloned.
|
||||
(removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")),
|
||||
(removed, generator_clone, "1.75.0", Some(95360), Some("renamed to `coroutine_clone`"), 116958),
|
||||
/// Allows defining generators.
|
||||
(removed, generators, "1.21.0", Some(43122), Some("renamed to `coroutines`")),
|
||||
(removed, generators, "1.75.0", Some(43122), Some("renamed to `coroutines`"), 116958),
|
||||
/// An extension to the `generic_associated_types` feature, allowing incomplete features.
|
||||
(removed, generic_associated_types_extended, "1.85.0", Some(95451),
|
||||
Some(
|
||||
"feature needs overhaul and reimplementation pending \
|
||||
better implied higher-ranked implied bounds support"
|
||||
)
|
||||
),
|
||||
133768
|
||||
),
|
||||
(removed, import_shadowing, "1.0.0", None, None),
|
||||
/// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
|
||||
(removed, in_band_lifetimes, "1.23.0", Some(44524),
|
||||
Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity")),
|
||||
(removed, in_band_lifetimes, "1.61.0", Some(44524),
|
||||
Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity"), 93845),
|
||||
/// Allows inferring `'static` outlives requirements (RFC 2093).
|
||||
(removed, infer_static_outlives_requirements, "1.63.0", Some(54185),
|
||||
Some("removed as it caused some confusion and discussion was inactive for years")),
|
||||
Some("removed as it caused some confusion and discussion was inactive for years"), 97875),
|
||||
/// Allow anonymous constants from an inline `const` block in pattern position
|
||||
(removed, inline_const_pat, "1.88.0", Some(76001),
|
||||
Some("removed due to implementation concerns as it requires significant refactorings")),
|
||||
Some("removed due to implementation concerns as it requires significant refactorings"), 138492),
|
||||
/// Lazily evaluate constants. This allows constants to depend on type parameters.
|
||||
(removed, lazy_normalization_consts, "1.46.0", Some(72219), Some("superseded by `generic_const_exprs`")),
|
||||
(removed, lazy_normalization_consts, "1.56.0", Some(72219), Some("superseded by `generic_const_exprs`"), 88369),
|
||||
/// Changes `impl Trait` to capture all lifetimes in scope.
|
||||
(removed, lifetime_capture_rules_2024, "1.76.0", None, Some("unnecessary -- use edition 2024 instead")),
|
||||
(removed, lifetime_capture_rules_2024, "1.87.0", None, Some("unnecessary -- use edition 2024 instead"), 136787),
|
||||
/// Allows using the `#[link_args]` attribute.
|
||||
(removed, link_args, "1.53.0", Some(29596),
|
||||
Some("removed in favor of using `-C link-arg=ARG` on command line, \
|
||||
which is available from cargo build scripts with `cargo:rustc-link-arg` now")),
|
||||
which is available from cargo build scripts with `cargo:rustc-link-arg` now"), 83820),
|
||||
(removed, macro_reexport, "1.0.0", Some(29638),
|
||||
Some("subsumed by `pub use`")),
|
||||
Some("subsumed by `pub use`"), 49982),
|
||||
/// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls.
|
||||
(removed, main, "1.53.0", Some(29634), None),
|
||||
(removed, main, "1.53.0", Some(29634), None, 84217),
|
||||
(removed, managed_boxes, "1.0.0", None, None),
|
||||
/// Allows the use of type alias impl trait in function return positions
|
||||
(removed, min_type_alias_impl_trait, "1.56.0", Some(63063),
|
||||
Some("removed in favor of full type_alias_impl_trait")),
|
||||
Some("removed in favor of full type_alias_impl_trait"), 87564),
|
||||
/// Make `mut` not reset the binding mode on edition >= 2024.
|
||||
(removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")),
|
||||
(removed, mut_preserve_binding_mode_2024, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`"), 125168),
|
||||
(removed, needs_allocator, "1.4.0", Some(27389),
|
||||
Some("subsumed by `#![feature(allocator_internals)]`")),
|
||||
/// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
|
||||
(removed, negate_unsigned, "1.0.0", Some(29645), None),
|
||||
/// Allows `#[no_coverage]` on functions.
|
||||
/// The feature was renamed to `coverage_attribute` and the attribute to `#[coverage(on|off)]`
|
||||
(removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`")),
|
||||
(removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656),
|
||||
/// Allows `#[no_debug]`.
|
||||
(removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand")),
|
||||
(removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667),
|
||||
/// Note: this feature was previously recorded in a separate
|
||||
/// `STABLE_REMOVED` list because it, uniquely, was once stable but was
|
||||
/// then removed. But there was no utility storing it separately, so now
|
||||
/// it's in this list.
|
||||
(removed, no_stack_check, "1.0.0", None, None),
|
||||
(removed, no_stack_check, "1.0.0", None, None, 40110),
|
||||
/// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible (object safe).
|
||||
/// Renamed to `dyn_compatible_for_dispatch`.
|
||||
(removed, object_safe_for_dispatch, "1.83.0", Some(43561),
|
||||
Some("renamed to `dyn_compatible_for_dispatch`")),
|
||||
Some("renamed to `dyn_compatible_for_dispatch`"), 131511),
|
||||
/// Allows using `#[on_unimplemented(..)]` on traits.
|
||||
/// (Moved to `rustc_attrs`.)
|
||||
(removed, on_unimplemented, "1.40.0", None, None),
|
||||
(removed, on_unimplemented, "1.40.0", None, None, 65794),
|
||||
/// A way to temporarily opt out of opt-in copy. This will *never* be accepted.
|
||||
(removed, opt_out_copy, "1.0.0", None, None),
|
||||
(removed, opt_out_copy, "1.0.0", None, None, 20740),
|
||||
/// Allows features specific to OIBIT (now called auto traits).
|
||||
/// Renamed to `auto_traits`.
|
||||
(removed, optin_builtin_traits, "1.0.0", Some(13231),
|
||||
Some("renamed to `auto_traits`")),
|
||||
(removed, optin_builtin_traits, "1.50.0", Some(13231),
|
||||
Some("renamed to `auto_traits`"), 79336),
|
||||
/// Allows overlapping impls of marker traits.
|
||||
(removed, overlapping_marker_traits, "1.42.0", Some(29864),
|
||||
Some("removed in favor of `#![feature(marker_trait_attr)]`")),
|
||||
Some("removed in favor of `#![feature(marker_trait_attr)]`"), 68544),
|
||||
(removed, panic_implementation, "1.28.0", Some(44489),
|
||||
Some("subsumed by `#[panic_handler]`")),
|
||||
Some("subsumed by `#[panic_handler]`"), 53619),
|
||||
/// Allows `extern "platform-intrinsic" { ... }`.
|
||||
(removed, platform_intrinsics, "1.4.0", Some(27731),
|
||||
Some("SIMD intrinsics use the regular intrinsics ABI now")),
|
||||
(removed, platform_intrinsics, "1.78.0", Some(27731),
|
||||
Some("SIMD intrinsics use the regular intrinsics ABI now"), 121516),
|
||||
/// Allows using `#![plugin(myplugin)]`.
|
||||
(removed, plugin, "1.75.0", Some(29597),
|
||||
Some("plugins are no longer supported")),
|
||||
Some("plugins are no longer supported"), 116412),
|
||||
/// Allows using `#[plugin_registrar]` on functions.
|
||||
(removed, plugin_registrar, "1.54.0", Some(29597),
|
||||
Some("plugins are no longer supported")),
|
||||
(removed, plugin_registrar, "1.75.0", Some(29597),
|
||||
Some("plugins are no longer supported"), 116412),
|
||||
/// Allows exhaustive integer pattern matching with `usize::MAX`/`isize::MIN`/`isize::MAX`.
|
||||
(removed, precise_pointer_size_matching, "1.32.0", Some(56354),
|
||||
Some("removed in favor of half-open ranges")),
|
||||
(removed, precise_pointer_size_matching, "1.76.0", Some(56354),
|
||||
Some("removed in favor of half-open ranges"), 118598),
|
||||
(removed, pref_align_of, "CURRENT_RUSTC_VERSION", Some(91971),
|
||||
Some("removed due to marginal use and inducing compiler complications")),
|
||||
(removed, proc_macro_expr, "1.27.0", Some(54727),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
|
||||
(removed, proc_macro_gen, "1.27.0", Some(54727),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
|
||||
(removed, proc_macro_mod, "1.27.0", Some(54727),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
|
||||
(removed, proc_macro_non_items, "1.27.0", Some(54727),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
|
||||
Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
|
||||
(removed, pub_macro_rules, "1.53.0", Some(78855),
|
||||
Some("removed due to being incomplete, in particular it does not work across crates")),
|
||||
(removed, pushpop_unsafe, "1.2.0", None, None),
|
||||
(removed, quad_precision_float, "1.0.0", None, None),
|
||||
(removed, quote, "1.33.0", Some(29601), None),
|
||||
(removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")),
|
||||
(removed, ref_pat_everywhere, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024"), 125168),
|
||||
(removed, reflect, "1.0.0", Some(27749), None),
|
||||
/// Allows using the `#[register_attr]` attribute.
|
||||
(removed, register_attr, "1.65.0", Some(66080),
|
||||
Some("removed in favor of `#![register_tool]`")),
|
||||
Some("removed in favor of `#![register_tool]`"), 66070),
|
||||
(removed, rust_2018_preview, "1.76.0", None,
|
||||
Some("2018 Edition preview is no longer relevant")),
|
||||
/// Allows using the macros:
|
||||
/// + `__diagnostic_used`
|
||||
/// + `__register_diagnostic`
|
||||
/// +`__build_diagnostic_array`
|
||||
(removed, rustc_diagnostic_macros, "1.38.0", None, None),
|
||||
(removed, rustc_diagnostic_macros, "1.38.0", None, None, 64139),
|
||||
/// Allows identifying crates that contain sanitizer runtimes.
|
||||
(removed, sanitizer_runtime, "1.17.0", None, None),
|
||||
(removed, sanitizer_runtime, "1.17.0", None, None, 65241),
|
||||
(removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")),
|
||||
/// Allows using `#[start]` on a function indicating that it is the program entrypoint.
|
||||
(removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")),
|
||||
(removed, start, "1.86.0", Some(29633), Some("not portable enough and never RFC'd"), 134299),
|
||||
/// Allows `#[link(kind = "static-nobundle", ...)]`.
|
||||
(removed, static_nobundle, "1.16.0", Some(37403),
|
||||
Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)),
|
||||
(removed, static_nobundle, "1.63.0", Some(37403),
|
||||
Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818),
|
||||
(removed, struct_inherit, "1.0.0", None, None),
|
||||
(removed, test_removed_feature, "1.0.0", None, None),
|
||||
/// Allows using items which are missing stability attributes
|
||||
(removed, unmarked_api, "1.0.0", None, None),
|
||||
/// Allows unnamed fields of struct and union type
|
||||
(removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign")),
|
||||
(removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign"), 131045),
|
||||
(removed, unsafe_no_drop_flag, "1.0.0", None, None),
|
||||
(removed, unsized_tuple_coercion, "1.87.0", Some(42877),
|
||||
Some("The feature restricts possible layouts for tuples, and this restriction is not worth it.")),
|
||||
Some("The feature restricts possible layouts for tuples, and this restriction is not worth it."), 137728),
|
||||
/// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
|
||||
(removed, untagged_unions, "1.13.0", Some(55149),
|
||||
Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")),
|
||||
(removed, untagged_unions, "1.64.0", Some(55149),
|
||||
Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more"), 97995),
|
||||
/// Allows `#[unwind(..)]`.
|
||||
///
|
||||
/// Permits specifying whether a function should permit unwinding or abort on unwind.
|
||||
(removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead")),
|
||||
(removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead"), 86155),
|
||||
(removed, visible_private_types, "1.0.0", None, None),
|
||||
/// Allows `extern "wasm" fn`
|
||||
(removed, wasm_abi, "1.81.0", Some(83788),
|
||||
Some("non-standard wasm ABI is no longer supported")),
|
||||
Some("non-standard wasm ABI is no longer supported"), 127605),
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
// Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
|
||||
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
|
||||
|
|
|
|||
|
|
@ -353,6 +353,8 @@ declare_features! (
|
|||
(unstable, abi_avr_interrupt, "1.45.0", Some(69664)),
|
||||
/// Allows `extern "C-cmse-nonsecure-call" fn()`.
|
||||
(unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)),
|
||||
/// Allows `extern "custom" fn()`.
|
||||
(unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)),
|
||||
/// Allows `extern "gpu-kernel" fn()`.
|
||||
(unstable, abi_gpu_kernel, "1.86.0", Some(135467)),
|
||||
/// Allows `extern "msp430-interrupt" fn()`.
|
||||
|
|
@ -546,8 +548,6 @@ declare_features! (
|
|||
(incomplete, inherent_associated_types, "1.52.0", Some(8995)),
|
||||
/// Allows using `pointer` and `reference` in intra-doc links
|
||||
(unstable, intra_doc_pointers, "1.51.0", Some(80896)),
|
||||
// Allows using the `kl` and `widekl` target features and the associated intrinsics
|
||||
(unstable, keylocker_x86, "1.86.0", Some(134813)),
|
||||
// Allows setting the threshold for the `large_assignments` lint.
|
||||
(unstable, large_assignments, "1.52.0", Some(83518)),
|
||||
/// Allow to have type alias types for inter-crate use.
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use crate::def::{CtorKind, DefKind, PerNS, Res};
|
|||
use crate::def_id::{DefId, LocalDefIdMap};
|
||||
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
|
||||
use crate::intravisit::{FnKind, VisitorExt};
|
||||
use crate::lints::DelayedLints;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
|
||||
pub enum AngleBrackets {
|
||||
|
|
@ -1526,6 +1527,10 @@ pub struct OwnerInfo<'hir> {
|
|||
/// Map indicating what traits are in scope for places where this
|
||||
/// is relevant; generated by resolve.
|
||||
pub trait_map: ItemLocalMap<Box<[TraitCandidate]>>,
|
||||
|
||||
/// Lints delayed during ast lowering to be emitted
|
||||
/// after hir has completely built
|
||||
pub delayed_lints: DelayedLints,
|
||||
}
|
||||
|
||||
impl<'tcx> OwnerInfo<'tcx> {
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ mod hir;
|
|||
pub mod hir_id;
|
||||
pub mod intravisit;
|
||||
pub mod lang_items;
|
||||
pub mod lints;
|
||||
pub mod pat_util;
|
||||
mod stable_hash_impls;
|
||||
mod target;
|
||||
|
|
|
|||
23
compiler/rustc_hir/src/lints.rs
Normal file
23
compiler/rustc_hir/src/lints.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
use rustc_attr_data_structures::lints::AttributeLint;
|
||||
use rustc_data_structures::fingerprint::Fingerprint;
|
||||
use rustc_macros::HashStable_Generic;
|
||||
|
||||
use crate::HirId;
|
||||
|
||||
/// During ast lowering, no lints can be emitted.
|
||||
/// That is because lints attach to nodes either in the AST, or on the built HIR.
|
||||
/// When attached to AST nodes, they're emitted just before building HIR,
|
||||
/// and then there's a gap where no lints can be emitted until HIR is done.
|
||||
/// The variants in this enum represent lints that are temporarily stashed during
|
||||
/// AST lowering to be emitted once HIR is built.
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub enum DelayedLint {
|
||||
AttributeParsing(AttributeLint<HirId>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DelayedLints {
|
||||
pub lints: Box<[DelayedLint]>,
|
||||
// Only present when the crate hash is needed.
|
||||
pub opt_hash: Option<Fingerprint>,
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ use crate::hir::{
|
|||
AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
|
||||
};
|
||||
use crate::hir_id::{HirId, ItemLocalId};
|
||||
use crate::lints::DelayedLints;
|
||||
|
||||
/// Requirements for a `StableHashingContext` to be used in this crate.
|
||||
/// This is a hack to allow using the `HashStable_Generic` derive macro
|
||||
|
|
@ -102,6 +103,13 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
|
|||
}
|
||||
}
|
||||
|
||||
impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for DelayedLints {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
let DelayedLints { opt_hash, .. } = *self;
|
||||
opt_hash.unwrap().hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
|
||||
fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
|
||||
// We ignore the `map` since it refers to information included in `opt_hash` which is
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ rustc_abi = { path = "../rustc_abi" }
|
|||
rustc_arena = { path = "../rustc_arena" }
|
||||
rustc_ast = { path = "../rustc_ast" }
|
||||
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" }
|
||||
rustc_feature = { path = "../rustc_feature" }
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
hir_analysis_abi_custom_clothed_function =
|
||||
items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
.suggestion = convert this to an `#[unsafe(naked)]` function
|
||||
|
||||
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`
|
||||
.label = ambiguous associated {$assoc_kind} `{$assoc_ident}`
|
||||
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
self.param_env,
|
||||
ty::Binder::dummy(trait_ref),
|
||||
);
|
||||
if !self.infcx.predicate_may_hold(&obligation) {
|
||||
if !self.infcx.next_trait_solver() && !self.infcx.predicate_may_hold(&obligation) {
|
||||
debug!("overloaded_deref_ty: cannot match obligation");
|
||||
return None;
|
||||
}
|
||||
|
|
@ -184,17 +184,17 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
|
|||
self.param_env,
|
||||
ty,
|
||||
) else {
|
||||
// We shouldn't have errors here, except for evaluate/fulfill mismatches,
|
||||
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
|
||||
// by design).
|
||||
// FIXME(-Znext-solver): This *actually* shouldn't happen then.
|
||||
// We shouldn't have errors here in the old solver, except for
|
||||
// evaluate/fulfill mismatches, but that's not a reason for an ICE.
|
||||
return None;
|
||||
};
|
||||
let errors = ocx.select_where_possible();
|
||||
if !errors.is_empty() {
|
||||
// This shouldn't happen, except for evaluate/fulfill mismatches,
|
||||
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
|
||||
// by design).
|
||||
if self.infcx.next_trait_solver() {
|
||||
unreachable!();
|
||||
}
|
||||
// We shouldn't have errors here in the old solver, except for
|
||||
// evaluate/fulfill mismatches, but that's not a reason for an ICE.
|
||||
debug!(?errors, "encountered errors while fulfilling");
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
|
|||
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
||||
use rustc_middle::ty::util::Discr;
|
||||
use rustc_middle::ty::{
|
||||
AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
|
||||
AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, fold_regions,
|
||||
};
|
||||
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
||||
|
|
@ -37,22 +37,23 @@ use {rustc_attr_data_structures as attrs, rustc_hir as hir};
|
|||
use super::compare_impl_item::check_type_bounds;
|
||||
use super::*;
|
||||
|
||||
fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {
|
||||
if let ExternAbi::Cdecl { unwind } = abi {
|
||||
let c_abi = ExternAbi::C { unwind };
|
||||
diag.help(format!("use `extern {c_abi}` instead",));
|
||||
} else if let ExternAbi::Stdcall { unwind } = abi {
|
||||
let c_abi = ExternAbi::C { unwind };
|
||||
let system_abi = ExternAbi::System { unwind };
|
||||
diag.help(format!(
|
||||
"if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \
|
||||
use `extern {system_abi}`"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
|
||||
// FIXME: this should be checked earlier, e.g. in `rustc_ast_lowering`, to fix
|
||||
// things like #86232.
|
||||
fn add_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {
|
||||
if let ExternAbi::Cdecl { unwind } = abi {
|
||||
let c_abi = ExternAbi::C { unwind };
|
||||
diag.help(format!("use `extern {c_abi}` instead",));
|
||||
} else if let ExternAbi::Stdcall { unwind } = abi {
|
||||
let c_abi = ExternAbi::C { unwind };
|
||||
let system_abi = ExternAbi::System { unwind };
|
||||
diag.help(format!(
|
||||
"if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \
|
||||
use `extern {system_abi}`"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
|
||||
AbiMapping::Direct(..) => (),
|
||||
|
|
@ -63,13 +64,13 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi
|
|||
E0570,
|
||||
"`{abi}` is not a supported ABI for the current target",
|
||||
);
|
||||
add_help(abi, &mut err);
|
||||
add_abi_diag_help(abi, &mut err);
|
||||
err.emit();
|
||||
}
|
||||
AbiMapping::Deprecated(..) => {
|
||||
tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
|
||||
lint.primary_message("use of calling convention not supported on this target");
|
||||
add_help(abi, lint);
|
||||
add_abi_diag_help(abi, lint);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -80,7 +81,16 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex
|
|||
// in `check_abi` above.
|
||||
match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
|
||||
AbiMapping::Direct(..) => (),
|
||||
AbiMapping::Deprecated(..) | AbiMapping::Invalid => {
|
||||
// This is not a redundant match arm: these ABIs started linting after introducing
|
||||
// UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS already existed and we want to
|
||||
// avoid expanding the scope of that lint so it can move to a hard error sooner.
|
||||
AbiMapping::Deprecated(..) => {
|
||||
tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
|
||||
lint.primary_message("use of calling convention not supported on this target");
|
||||
add_abi_diag_help(abi, lint);
|
||||
});
|
||||
}
|
||||
AbiMapping::Invalid => {
|
||||
tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
|
||||
lint.primary_message(format!(
|
||||
"the calling convention {abi} is not supported on this target"
|
||||
|
|
@ -90,6 +100,18 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) {
|
||||
if fn_sig.abi == ExternAbi::Custom {
|
||||
// Function definitions that use `extern "custom"` must be naked functions.
|
||||
if !tcx.has_attr(def_id, sym::naked) {
|
||||
tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction {
|
||||
span: fn_sig_span,
|
||||
naked_span: tcx.def_span(def_id).shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
|
|||
| sym::box_new
|
||||
| sym::breakpoint
|
||||
| sym::size_of
|
||||
| sym::min_align_of
|
||||
| sym::align_of
|
||||
| sym::needs_drop
|
||||
| sym::caller_location
|
||||
| sym::add_with_overflow
|
||||
|
|
@ -200,10 +200,8 @@ pub(crate) fn check_intrinsic_type(
|
|||
sym::abort => (0, 0, vec![], tcx.types.never),
|
||||
sym::unreachable => (0, 0, vec![], tcx.types.never),
|
||||
sym::breakpoint => (0, 0, vec![], tcx.types.unit),
|
||||
sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => {
|
||||
(1, 0, vec![], tcx.types.usize)
|
||||
}
|
||||
sym::size_of_val | sym::min_align_of_val => {
|
||||
sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
|
||||
sym::size_of_val | sym::align_of_val => {
|
||||
(1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
|
||||
}
|
||||
sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ pub mod wfcheck;
|
|||
|
||||
use std::num::NonZero;
|
||||
|
||||
pub use check::{check_abi, check_abi_fn_ptr};
|
||||
pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
|
||||
use rustc_abi::{ExternAbi, VariantIdx};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
|
|||
|
||||
// Only visit the type looking for `_` if we didn't fix the type above
|
||||
visitor.visit_ty_unambig(a);
|
||||
self.lowerer().lower_arg_ty(a, None)
|
||||
self.lowerer().lower_ty(a)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
|
|||
|
|
@ -1698,3 +1698,17 @@ pub(crate) struct SelfInTypeAlias {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_abi_custom_clothed_function)]
|
||||
pub(crate) struct AbiCustomClothedFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "#[unsafe(naked)]\n",
|
||||
style = "short"
|
||||
)]
|
||||
pub naked_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -805,7 +805,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
|
||||
});
|
||||
let bound = (bound.upcast(tcx), span);
|
||||
// FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
|
||||
// FIXME(-Znext-solver): We can likely remove this hack once the
|
||||
// new trait solver lands. This fixed an overflow in the old solver.
|
||||
// This may have performance implications, so please check perf when
|
||||
// removing it.
|
||||
// This was added in <https://github.com/rust-lang/rust/pull/123302>.
|
||||
if tcx.is_lang_item(trait_def_id, rustc_hir::LangItem::Sized) {
|
||||
bounds.insert(0, bound);
|
||||
} else {
|
||||
|
|
@ -2704,16 +2708,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
|
||||
match ty.kind {
|
||||
hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => {
|
||||
self.record_ty(ty.hir_id, expected_ty, ty.span);
|
||||
expected_ty
|
||||
}
|
||||
_ => self.lower_ty(ty),
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower a function type from the HIR to our internal notion of a function signature.
|
||||
#[instrument(level = "debug", skip(self, hir_id, safety, abi, decl, generics, hir_ty), ret)]
|
||||
pub fn lower_fn_ty(
|
||||
|
|
|
|||
|
|
@ -92,8 +92,9 @@ mod variance;
|
|||
|
||||
pub use errors::NoVariantNamed;
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::{self as hir};
|
||||
use rustc_middle::middle;
|
||||
use rustc_middle::mir::interpret::GlobalId;
|
||||
use rustc_middle::query::Providers;
|
||||
|
|
@ -174,6 +175,14 @@ pub fn provide(providers: &mut Providers) {
|
|||
};
|
||||
}
|
||||
|
||||
fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) {
|
||||
match lint {
|
||||
DelayedLint::AttributeParsing(attribute_lint) => {
|
||||
rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_crate(tcx: TyCtxt<'_>) {
|
||||
let _prof_timer = tcx.sess.timer("type_check_crate");
|
||||
|
||||
|
|
@ -192,6 +201,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
|
|||
let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
|
||||
});
|
||||
|
||||
for owner_id in tcx.hir_crate_items(()).owners() {
|
||||
if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
|
||||
for lint in &delayed_lints.lints {
|
||||
emit_delayed_lint(lint, tcx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tcx.par_hir_body_owners(|item_def_id| {
|
||||
let def_kind = tcx.def_kind(item_def_id);
|
||||
// Make sure we evaluate all static and (non-associated) const items, even if unused.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
hir_typeck_abi_custom_call =
|
||||
functions with the `"custom"` ABI cannot be called
|
||||
.note = an `extern "custom"` function can only be called from within inline assembly
|
||||
|
||||
hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
|
||||
|
||||
hir_typeck_add_return_type_add = try adding a return type
|
||||
|
|
@ -17,6 +21,24 @@ hir_typeck_base_expression_double_dot_enable_default_field_values =
|
|||
add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
|
||||
hir_typeck_base_expression_double_dot_remove = remove the `..` as all the fields are already present
|
||||
|
||||
hir_typeck_break_inside_closure =
|
||||
`{$name}` inside of a closure
|
||||
.label = cannot `{$name}` inside of a closure
|
||||
.closure_label = enclosing closure
|
||||
|
||||
hir_typeck_break_inside_coroutine =
|
||||
`{$name}` inside `{$kind}` {$source}
|
||||
.label = cannot `{$name}` inside `{$kind}` {$source}
|
||||
.coroutine_label = enclosing `{$kind}` {$source}
|
||||
|
||||
hir_typeck_break_non_loop =
|
||||
`break` with value from a `{$kind}` loop
|
||||
.label = can only break with a value inside `loop` or breakable block
|
||||
.label2 = you can't `break` with a value in a `{$kind}` loop
|
||||
.suggestion = use `break` on its own without a value inside this `{$kind}` loop
|
||||
.break_expr_suggestion = alternatively, you might have meant to use the available loop label
|
||||
|
||||
|
||||
hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty ->
|
||||
[NONE] {""}
|
||||
[implement] , perhaps you need to implement it
|
||||
|
|
@ -64,6 +86,12 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
|
|||
.note = expected a function item, found {$ty}
|
||||
.help = consult the documentation on `const_eval_select` for more information
|
||||
|
||||
hir_typeck_continue_labeled_block =
|
||||
`continue` pointing to a labeled block
|
||||
.label = labeled blocks cannot be `continue`'d
|
||||
.block_label = labeled block the `continue` points to
|
||||
|
||||
|
||||
hir_typeck_convert_to_str = try converting the passed type into a `&str`
|
||||
|
||||
hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}`
|
||||
|
|
@ -182,6 +210,19 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
|
|||
hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
|
||||
hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
|
||||
|
||||
hir_typeck_outside_loop =
|
||||
`{$name}` outside of a loop{$is_break ->
|
||||
[true] {" or labeled block"}
|
||||
*[false] {""}
|
||||
}
|
||||
.label = cannot `{$name}` outside of a loop{$is_break ->
|
||||
[true] {" or labeled block"}
|
||||
*[false] {""}
|
||||
}
|
||||
|
||||
hir_typeck_outside_loop_suggestion = consider labeling this block to be able to break within it
|
||||
|
||||
|
||||
hir_typeck_params_not_allowed =
|
||||
referencing function parameters is not allowed in naked functions
|
||||
.help = follow the calling convention in asm block to use parameters
|
||||
|
|
@ -254,6 +295,13 @@ hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
|
|||
|
||||
hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
|
||||
|
||||
hir_typeck_unlabeled_cf_in_while_condition =
|
||||
`break` or `continue` with no label in the condition of a `while` loop
|
||||
.label = unlabeled `{$cf_type}` in the condition of a `while` loop
|
||||
|
||||
hir_typeck_unlabeled_in_labeled_block =
|
||||
unlabeled `{$cf_type}` inside of a labeled block
|
||||
.label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
|
||||
hir_typeck_use_is_empty =
|
||||
consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything
|
||||
|
||||
|
|
|
|||
|
|
@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
let (def_id, args) = match *expected_ty.kind() {
|
||||
// FIXME: Could also check that the RPIT is not defined
|
||||
ty::Alias(ty::Opaque, alias_ty) => (alias_ty.def_id.as_local()?, alias_ty.args),
|
||||
// FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone.
|
||||
// FIXME(-Znext-solver=no): Remove this branch once `replace_opaque_types_with_infer` is gone.
|
||||
ty::Infer(ty::TyVar(_)) => self
|
||||
.inner
|
||||
.borrow_mut()
|
||||
|
|
|
|||
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