Merge pull request #4398 from rust-lang/rustup-2025-06-14

Automatic Rustup
This commit is contained in:
Ralf Jung 2025-06-14 05:29:34 +00:00 committed by GitHub
commit 974779746f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
962 changed files with 16886 additions and 8809 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,6 +8,8 @@ mod attributes;
mod stability;
mod version;
pub mod lints;
use std::num::NonZero;
pub use attributes::*;

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

View file

@ -132,6 +132,7 @@ pub enum StabilityLevel {
/// fn foobar() {}
/// ```
implied_by: Option<Symbol>,
old_name: Option<Symbol>,
},
/// `#[stable]`
Stable {

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

@ -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, &param, &mut implied_by)?
}
Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &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))
}

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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