commit
6ad42bf4e7
2447 changed files with 45642 additions and 28557 deletions
7
.mailmap
7
.mailmap
|
|
@ -34,10 +34,13 @@ Alona Enraght-Moony <code@alona.page> <nixon@caminus.local>
|
|||
Alona Enraght-Moony <code@alona.page> <contact@alona.page>
|
||||
Amanda Stjerna <mail@amandastjerna.se> <albin.stjerna@gmail.com>
|
||||
Amanda Stjerna <mail@amandastjerna.se> <amanda.stjerna@it.uu.se>
|
||||
Amanieu d'Antras <amanieu@gmail.com> <amanieu.dantras@huawei.com>
|
||||
Amos Onn <amosonn@gmail.com>
|
||||
Ana-Maria Mihalache <mihalacheana.maria@yahoo.com>
|
||||
Anatoly Ikorsky <aikorsky@gmail.com>
|
||||
Andre Bogus <bogusandre@gmail.com>
|
||||
Andre Bogus <bogusandre@gmail.com> <andre.bogus@aleph-alpha.de>
|
||||
Andre Bogus <bogusandre@gmail.com> <andre.bogus@ankordata.de>
|
||||
Andrea Ciliberti <meziu210@icloud.com>
|
||||
Andreas Gal <gal@mozilla.com> <andreas.gal@gmail.com>
|
||||
Andreas Jonson <andjo403@users.noreply.github.com>
|
||||
|
|
@ -116,6 +119,7 @@ Carol Willing <carolcode@willingconsulting.com>
|
|||
Chandler Deng <chandde@microsoft.com>
|
||||
Charles Lew <crlf0710@gmail.com> CrLF0710 <crlf0710@gmail.com>
|
||||
Chris C Cerami <chrisccerami@users.noreply.github.com> Chris C Cerami <chrisccerami@gmail.com>
|
||||
Chris Denton <chris@chrisdenton.dev> <christophersdenton@gmail.com>
|
||||
Chris Denton <chris@chrisdenton.dev> Chris Denton <ChrisDenton@users.noreply.github.com>
|
||||
Chris Gregory <czipperz@gmail.com>
|
||||
Chris Pardy <chrispardy36@gmail.com>
|
||||
|
|
@ -403,6 +407,8 @@ Urgau <urgau@numericable.fr> <3616612+Urgau@users.noreply.github.com>
|
|||
Lucy <luxx4x@protonmail.com>
|
||||
Lukas H. <lukaramu@users.noreply.github.com>
|
||||
Lukas Lueg <lukas.lueg@gmail.com>
|
||||
Lukas Wirth <lukastw97@gmail.com> <lukas.wirth@ferrous-systems.com>
|
||||
Lukas Wirth <lukastw97@gmail.com> <me@lukaswirth.dev>
|
||||
Luke Metz <luke.metz@students.olin.edu>
|
||||
Luqman Aden <me@luqman.ca> <laden@csclub.uwaterloo.ca>
|
||||
Luqman Aden <me@luqman.ca> <laden@mozilla.com>
|
||||
|
|
@ -493,6 +499,7 @@ Nicolas Abram <abramlujan@gmail.com>
|
|||
Nicole Mazzuca <npmazzuca@gmail.com>
|
||||
Niko Matsakis <rust@nikomatsakis.com>
|
||||
Niko Matsakis <rust@nikomatsakis.com> <niko@alum.mit.edu>
|
||||
Niko Matsakis <rust@nikomatsakis.com> <nikomat@amazon.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <48135649+Nilstrieb@users.noreply.github.com>
|
||||
Noratrieb <48135649+Noratrieb@users.noreply.github.com> <nilstrieb@gmail.com>
|
||||
|
|
|
|||
283
Cargo.lock
283
Cargo.lock
|
|
@ -80,9 +80,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
version = "0.6.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
|
|
@ -95,58 +95,58 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-lossy"
|
||||
version = "1.1.3"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "934ff8719effd2023a48cf63e69536c1c3ced9d3895068f6f5cc9a4ff845e59b"
|
||||
checksum = "04d3a5dc826f84d0ea11882bb8054ff7f3d482602e11bb181101303a279ea01f"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-svg"
|
||||
version = "0.1.7"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3607949e9f6de49ea4bafe12f5e4fd73613ebf24795e48587302a8cc0e4bb35"
|
||||
checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"anstyle-lossy",
|
||||
"anstyle-parse",
|
||||
"html-escape",
|
||||
"unicode-width 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
version = "3.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
|
|
@ -266,9 +266,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.0"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
|
|
@ -341,15 +341,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.17.0"
|
||||
version = "3.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
||||
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
|
||||
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
|
|
@ -359,9 +359,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
|||
|
||||
[[package]]
|
||||
name = "camino"
|
||||
version = "1.1.9"
|
||||
version = "1.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
|
||||
checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -487,9 +487,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.38"
|
||||
version = "4.5.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
|
@ -507,9 +507,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.38"
|
||||
version = "4.5.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
|
@ -642,16 +642,16 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "color-eyre"
|
||||
version = "0.6.4"
|
||||
version = "0.6.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec"
|
||||
checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"color-spantrace",
|
||||
"eyre",
|
||||
"indenter",
|
||||
"once_cell",
|
||||
"owo-colors 4.2.0",
|
||||
"owo-colors 4.2.1",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
|
|
@ -678,21 +678,21 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "color-spantrace"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5"
|
||||
checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"owo-colors 4.2.0",
|
||||
"owo-colors 4.2.1",
|
||||
"tracing-core",
|
||||
"tracing-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
|
|
@ -851,9 +851,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "curl"
|
||||
version = "0.4.47"
|
||||
version = "0.4.48"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265"
|
||||
checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b"
|
||||
dependencies = [
|
||||
"curl-sys",
|
||||
"libc",
|
||||
|
|
@ -861,14 +861,14 @@ dependencies = [
|
|||
"openssl-sys",
|
||||
"schannel",
|
||||
"socket2",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "curl-sys"
|
||||
version = "0.4.80+curl-8.12.1"
|
||||
version = "0.4.82+curl-8.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734"
|
||||
checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -876,7 +876,7 @@ dependencies = [
|
|||
"openssl-sys",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1142,9 +1142,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.11"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
|
|
@ -1207,9 +1207,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.1"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
|
|
@ -1487,9 +1487,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
version = "0.15.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"equivalent",
|
||||
|
|
@ -1511,9 +1511,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
|
|
@ -1700,9 +1700,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
|
|||
|
||||
[[package]]
|
||||
name = "icu_properties"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
|
||||
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
|
||||
dependencies = [
|
||||
"displaydoc",
|
||||
"icu_collections",
|
||||
|
|
@ -1716,9 +1716,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "icu_properties_data"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
|
||||
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
|
||||
|
||||
[[package]]
|
||||
name = "icu_provider"
|
||||
|
|
@ -1933,9 +1933,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
|||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
|
||||
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
|
|
@ -1946,9 +1946,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
|
||||
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -2002,9 +2002,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "jsonpath-rust"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9"
|
||||
checksum = "5b37465feaf9d41f74df7da98c6c1c31ca8ea06d11b5bf7869c8f1ccc51a793f"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_derive",
|
||||
|
|
@ -2080,9 +2080,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.7"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
|
||||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.53.0",
|
||||
|
|
@ -2170,9 +2170,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
|
||||
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
|
|
@ -2463,9 +2463,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
|
|
@ -2538,6 +2538,12 @@ version = "1.21.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
|
||||
|
||||
[[package]]
|
||||
name = "opener"
|
||||
version = "0.7.2"
|
||||
|
|
@ -2558,9 +2564,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
|||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.108"
|
||||
version = "0.9.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
|
@ -2611,9 +2617,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
|||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "4.2.0"
|
||||
version = "4.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
|
||||
checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec"
|
||||
|
||||
[[package]]
|
||||
name = "pad"
|
||||
|
|
@ -2637,9 +2643,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.3"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
|
||||
checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
|
|
@ -2647,9 +2653,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.10"
|
||||
version = "0.9.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
|
||||
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
|
|
@ -2802,9 +2808,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
|
|
@ -3228,9 +3234,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc_apfloat"
|
||||
version = "0.2.2+llvm-462a31f5a5ab"
|
||||
version = "0.2.3+llvm-462a31f5a5ab"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f"
|
||||
checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"smallvec",
|
||||
|
|
@ -3468,11 +3474,9 @@ name = "rustc_codegen_ssa"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"ar_archive_writer",
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"bstr",
|
||||
"cc",
|
||||
"either",
|
||||
"itertools",
|
||||
"libc",
|
||||
"object 0.37.0",
|
||||
|
|
@ -3787,6 +3791,7 @@ dependencies = [
|
|||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
|
|
@ -4611,7 +4616,7 @@ dependencies = [
|
|||
"derive-where",
|
||||
"ena",
|
||||
"indexmap",
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.1.1",
|
||||
"rustc_ast_ir",
|
||||
"rustc_data_structures",
|
||||
"rustc_index",
|
||||
|
|
@ -4768,9 +4773,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 +4871,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 +4938,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 +5116,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 +5359,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 +5391,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 +5425,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 +5509,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 +5734,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 +5899,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 +5942,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 +5952,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 +6040,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 +6060,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 +6073,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 +6122,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 +6212,15 @@ dependencies = [
|
|||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
|
|
|
|||
|
|
@ -381,6 +381,15 @@
|
|||
# "miri", "cargo-miri" # for dev/nightly channels
|
||||
#]
|
||||
|
||||
# Specify build configuration specific for some tool, such as enabled features.
|
||||
# This option has no effect on which tools are enabled: refer to the `tools` option for that.
|
||||
#
|
||||
# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]`
|
||||
#
|
||||
# The default value for the `features` array is `[]`. However, please note that other flags in
|
||||
# `bootstrap.toml` might influence the features enabled for some tools.
|
||||
#tool.TOOL_NAME.features = [FEATURE1, FEATURE2]
|
||||
|
||||
# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
|
||||
#verbose = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ pub enum CanonAbi {
|
|||
Rust,
|
||||
RustCold,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
||||
/// ABIs relevant to 32-bit Arm targets
|
||||
Arm(ArmCall),
|
||||
/// ABI relevant to GPUs: the entry point for a GPU kernel
|
||||
|
|
@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ pub enum ExternAbi {
|
|||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define. Functions with this ABI can
|
||||
/// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
|
||||
/// be called from inline assembly.
|
||||
Custom,
|
||||
|
||||
/// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
|
||||
/// and only valid on platforms that have a UEFI standard
|
||||
EfiApi,
|
||||
|
|
@ -141,6 +146,7 @@ abi_impls! {
|
|||
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
|
||||
Cdecl { unwind: false } =><= "cdecl",
|
||||
Cdecl { unwind: true } =><= "cdecl-unwind",
|
||||
Custom =><= "custom",
|
||||
EfiApi =><= "efiapi",
|
||||
Fastcall { unwind: false } =><= "fastcall",
|
||||
Fastcall { unwind: true } =><= "fastcall-unwind",
|
||||
|
|
|
|||
|
|
@ -97,12 +97,12 @@ pub struct Path {
|
|||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
// Succeeds if the path has a single segment that is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
if let [segment] = self.segments.as_ref()
|
||||
&& segment.args.is_none()
|
||||
&& segment.ident.name == *name
|
||||
&& segment == name
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
|
@ -111,6 +111,15 @@ impl PartialEq<Symbol> for Path {
|
|||
}
|
||||
}
|
||||
|
||||
// Succeeds if the path has segments that are arg-free and match the given symbols.
|
||||
impl PartialEq<&[Symbol]> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, names: &&[Symbol]) -> bool {
|
||||
self.segments.len() == names.len()
|
||||
&& self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.segments.len().hash_stable(hcx, hasher);
|
||||
|
|
@ -166,6 +175,14 @@ pub struct PathSegment {
|
|||
pub args: Option<P<GenericArgs>>,
|
||||
}
|
||||
|
||||
// Succeeds if the path segment is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for PathSegment {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
self.args.is_none() && self.ident.name == *name
|
||||
}
|
||||
}
|
||||
|
||||
impl PathSegment {
|
||||
pub fn from_ident(ident: Ident) -> Self {
|
||||
PathSegment { ident, id: DUMMY_NODE_ID, args: None }
|
||||
|
|
@ -693,6 +710,12 @@ impl Pat {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<P<Pat>> for Pat {
|
||||
fn from(value: P<Pat>) -> Self {
|
||||
*value
|
||||
}
|
||||
}
|
||||
|
||||
/// A single field in a struct pattern.
|
||||
///
|
||||
/// Patterns like the fields of `Foo { x, ref y, ref mut z }`
|
||||
|
|
@ -1433,19 +1456,32 @@ impl Expr {
|
|||
}
|
||||
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
fn prefix_attrs_precedence(attrs: &AttrVec) -> ExprPrecedence {
|
||||
for attr in attrs {
|
||||
if let AttrStyle::Outer = attr.style {
|
||||
return ExprPrecedence::Prefix;
|
||||
}
|
||||
}
|
||||
ExprPrecedence::Unambiguous
|
||||
}
|
||||
|
||||
match &self.kind {
|
||||
ExprKind::Closure(closure) => {
|
||||
match closure.fn_decl.output {
|
||||
FnRetTy::Default(_) => ExprPrecedence::Jump,
|
||||
FnRetTy::Ty(_) => ExprPrecedence::Unambiguous,
|
||||
FnRetTy::Ty(_) => prefix_attrs_precedence(&self.attrs),
|
||||
}
|
||||
}
|
||||
|
||||
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 => prefix_attrs_precedence(&self.attrs),
|
||||
},
|
||||
|
||||
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
|
||||
|
|
@ -1469,7 +1505,7 @@ impl Expr {
|
|||
| ExprKind::Let(..)
|
||||
| ExprKind::Unary(..) => ExprPrecedence::Prefix,
|
||||
|
||||
// Never need parens
|
||||
// Need parens if and only if there are prefix attributes.
|
||||
ExprKind::Array(_)
|
||||
| ExprKind::Await(..)
|
||||
| ExprKind::Use(..)
|
||||
|
|
@ -1502,8 +1538,9 @@ impl Expr {
|
|||
| ExprKind::Underscore
|
||||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::While(..)
|
||||
| ExprKind::Yield(YieldKind::Postfix(..))
|
||||
| ExprKind::Err(_)
|
||||
| ExprKind::Dummy => ExprPrecedence::Unambiguous,
|
||||
| ExprKind::Dummy => prefix_attrs_precedence(&self.attrs),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1522,17 +1559,23 @@ impl Expr {
|
|||
)
|
||||
}
|
||||
|
||||
/// Creates a dummy `P<Expr>`.
|
||||
/// Creates a dummy `Expr`.
|
||||
///
|
||||
/// Should only be used when it will be replaced afterwards or as a return value when an error was encountered.
|
||||
pub fn dummy() -> P<Expr> {
|
||||
P(Expr {
|
||||
pub fn dummy() -> Expr {
|
||||
Expr {
|
||||
id: DUMMY_NODE_ID,
|
||||
kind: ExprKind::Dummy,
|
||||
span: DUMMY_SP,
|
||||
attrs: ThinVec::new(),
|
||||
tokens: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<P<Expr>> for Expr {
|
||||
fn from(value: P<Expr>) -> Self {
|
||||
*value
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2343,6 +2386,12 @@ impl Clone for Ty {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<P<Ty>> for Ty {
|
||||
fn from(value: P<Ty>) -> Self {
|
||||
*value
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
pub fn peel_refs(&self) -> &Self {
|
||||
let mut final_ty = self;
|
||||
|
|
@ -3520,6 +3569,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 {
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'st
|
|||
}
|
||||
}
|
||||
|
||||
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable";
|
||||
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2";
|
||||
|
||||
pub enum AllocatorTy {
|
||||
Layout,
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
|
|||
walk_flat_map_arm(self, arm)
|
||||
}
|
||||
|
||||
fn visit_pat(&mut self, p: &mut P<Pat>) {
|
||||
fn visit_pat(&mut self, p: &mut Pat) {
|
||||
walk_pat(self, p);
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
|
|||
walk_anon_const(self, c);
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &mut P<Expr>) {
|
||||
fn visit_expr(&mut self, e: &mut Expr) {
|
||||
walk_expr(self, e);
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
|
|||
walk_generic_arg(self, arg);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, t: &mut P<Ty>) {
|
||||
fn visit_ty(&mut self, t: &mut Ty) {
|
||||
walk_ty(self, t);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -884,7 +884,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
TyKind::BareFn(function_declaration) => {
|
||||
let BareFnTy { safety, ext: _, generic_params, decl, decl_span } =
|
||||
&$($mut)? **function_declaration;
|
||||
visit_safety(vis, safety);
|
||||
try_visit!(visit_safety(vis, safety));
|
||||
try_visit!(visit_generic_params(vis, generic_params));
|
||||
try_visit!(vis.visit_fn_decl(decl));
|
||||
try_visit!(visit_span(vis, decl_span));
|
||||
|
|
@ -1235,7 +1235,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
bounds,
|
||||
bound_generic_params,
|
||||
}) => {
|
||||
visit_generic_params(vis, bound_generic_params);
|
||||
try_visit!(visit_generic_params(vis, bound_generic_params));
|
||||
try_visit!(vis.visit_ty(bounded_ty));
|
||||
walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound);
|
||||
}
|
||||
|
|
@ -1420,7 +1420,7 @@ macro_rules! common_visitor_and_walkers {
|
|||
let StructExpr { qself, path, fields, rest } = &$($mut)?**se;
|
||||
try_visit!(vis.visit_qself(qself));
|
||||
try_visit!(vis.visit_path(path));
|
||||
visit_expr_fields(vis, fields);
|
||||
try_visit!(visit_expr_fields(vis, fields));
|
||||
match rest {
|
||||
StructRest::Base(expr) => try_visit!(vis.visit_expr(expr)),
|
||||
StructRest::Rest(_span) => {}
|
||||
|
|
@ -1700,7 +1700,8 @@ fn visit_nested_use_tree<'a, V: Visitor<'a>>(
|
|||
}
|
||||
|
||||
pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result {
|
||||
let Stmt { id: _, kind, span: _ } = statement;
|
||||
let Stmt { id, kind, span: _ } = statement;
|
||||
try_visit!(visit_id(visitor, id));
|
||||
match kind {
|
||||
StmtKind::Let(local) => try_visit!(visitor.visit_local(local)),
|
||||
StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
|
||||
|
|
|
|||
|
|
@ -172,13 +172,12 @@ ast_lowering_template_modifier = template modifier
|
|||
|
||||
ast_lowering_this_not_async = this is not `async`
|
||||
|
||||
ast_lowering_underscore_array_length_unstable =
|
||||
using `_` for array lengths is unstable
|
||||
|
||||
ast_lowering_underscore_expr_lhs_assign =
|
||||
in expressions, `_` can only be used on the left-hand side of an assignment
|
||||
.label = `_` not allowed here
|
||||
|
||||
ast_lowering_union_default_field_values = unions cannot have default field values
|
||||
|
||||
ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
|
||||
ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
|
||||
using both label and output operands for inline assembly is unstable
|
||||
|
|
|
|||
|
|
@ -475,3 +475,10 @@ pub(crate) struct UseConstGenericArg {
|
|||
#[suggestion_part(code = "{other_args}")]
|
||||
pub call_args: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_lowering_union_default_field_values)]
|
||||
pub(crate) struct UnionWithDefault {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use tracing::instrument;
|
|||
|
||||
use super::errors::{
|
||||
InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
|
||||
UnionWithDefault,
|
||||
};
|
||||
use super::stability::{enabled_names, gate_unstable_abi};
|
||||
use super::{
|
||||
|
|
@ -63,7 +64,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 +79,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?
|
||||
|
|
@ -145,6 +146,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
vis_span,
|
||||
span: self.lower_span(i.span),
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -315,7 +317,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
this.arena.alloc_from_iter(
|
||||
enum_definition.variants.iter().map(|x| this.lower_variant(x)),
|
||||
enum_definition.variants.iter().map(|x| this.lower_variant(i, x)),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
|
@ -327,7 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, struct_def),
|
||||
|this| this.lower_variant_data(hir_id, i, struct_def),
|
||||
);
|
||||
hir::ItemKind::Struct(ident, generics, struct_def)
|
||||
}
|
||||
|
|
@ -337,7 +339,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
generics,
|
||||
id,
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_variant_data(hir_id, vdata),
|
||||
|this| this.lower_variant_data(hir_id, i, vdata),
|
||||
);
|
||||
hir::ItemKind::Union(ident, generics, vdata)
|
||||
}
|
||||
|
|
@ -599,6 +601,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
vis_span,
|
||||
span: this.lower_span(use_tree.span),
|
||||
has_delayed_lints: !this.delayed_lints.is_empty(),
|
||||
};
|
||||
hir::OwnerNode::Item(this.arena.alloc(item))
|
||||
});
|
||||
|
|
@ -697,6 +700,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
vis_span: self.lower_span(i.vis.span),
|
||||
span: self.lower_span(i.span),
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -711,13 +715,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> {
|
||||
fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> {
|
||||
let hir_id = self.lower_node_id(v.id);
|
||||
self.lower_attrs(hir_id, &v.attrs, v.span);
|
||||
hir::Variant {
|
||||
hir_id,
|
||||
def_id: self.local_def_id(v.id),
|
||||
data: self.lower_variant_data(hir_id, &v.data),
|
||||
data: self.lower_variant_data(hir_id, item_kind, &v.data),
|
||||
disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
|
||||
ident: self.lower_ident(v.ident),
|
||||
span: self.lower_span(v.span),
|
||||
|
|
@ -727,15 +731,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
fn lower_variant_data(
|
||||
&mut self,
|
||||
parent_id: hir::HirId,
|
||||
item_kind: &ItemKind,
|
||||
vdata: &VariantData,
|
||||
) -> hir::VariantData<'hir> {
|
||||
match vdata {
|
||||
VariantData::Struct { fields, recovered } => hir::VariantData::Struct {
|
||||
fields: self
|
||||
VariantData::Struct { fields, recovered } => {
|
||||
let fields = self
|
||||
.arena
|
||||
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
|
||||
recovered: *recovered,
|
||||
},
|
||||
.alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
|
||||
|
||||
if let ItemKind::Union(..) = item_kind {
|
||||
for field in &fields[..] {
|
||||
if let Some(default) = field.default {
|
||||
// Unions cannot derive `Default`, and it's not clear how to use default
|
||||
// field values of unions if that was supported. Therefore, blanket reject
|
||||
// trying to use field values with unions.
|
||||
if self.tcx.features().default_field_values() {
|
||||
self.dcx().emit_err(UnionWithDefault { span: default.span });
|
||||
} else {
|
||||
let _ = self.dcx().span_delayed_bug(
|
||||
default.span,
|
||||
"expected union default field values feature gate error but none \
|
||||
was produced",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hir::VariantData::Struct { fields, recovered: *recovered }
|
||||
}
|
||||
VariantData::Tuple(fields, id) => {
|
||||
let ctor_id = self.lower_node_id(*id);
|
||||
self.alias_attrs(ctor_id, parent_id);
|
||||
|
|
@ -941,6 +966,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
kind,
|
||||
span: self.lower_span(i.span),
|
||||
defaultness: hir::Defaultness::Default { has_value: has_default },
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -1100,6 +1126,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
vis_span: self.lower_span(i.vis.span),
|
||||
span: self.lower_span(i.span),
|
||||
defaultness,
|
||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||
};
|
||||
self.arena.alloc(item)
|
||||
}
|
||||
|
|
@ -1160,7 +1187,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 +1700,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
|
||||
|
|
|
|||
|
|
@ -48,9 +48,10 @@ use rustc_data_structures::sorted_map::SortedMap;
|
|||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::spawn;
|
||||
use rustc_data_structures::tagged_ptr::TaggedRef;
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
|
||||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
|
||||
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,
|
||||
|
|
@ -59,7 +60,7 @@ use rustc_index::{Idx, IndexSlice, IndexVec};
|
|||
use rustc_macros::extension;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
|
||||
use rustc_session::parse::{add_feature_diagnostics, feature_err};
|
||||
use rustc_session::parse::add_feature_diagnostics;
|
||||
use rustc_span::symbol::{Ident, Symbol, kw, sym};
|
||||
use rustc_span::{DUMMY_SP, DesugaringKind, Span};
|
||||
use smallvec::SmallVec;
|
||||
|
|
@ -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,
|
||||
|
|
@ -2068,15 +2109,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
|
||||
match c.value.peel_parens().kind {
|
||||
ExprKind::Underscore => {
|
||||
if !self.tcx.features().generic_arg_infer() {
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::generic_arg_infer,
|
||||
c.value.span,
|
||||
fluent_generated::ast_lowering_underscore_array_length_unstable,
|
||||
)
|
||||
.stash(c.value.span, StashKey::UnderscoreForArrayLengths);
|
||||
}
|
||||
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
|
||||
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
|
||||
}
|
||||
|
|
@ -2106,7 +2138,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
ty_id,
|
||||
&None,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ParamMode::Explicit,
|
||||
AllowReturnTypeNotation::No,
|
||||
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
|
|
@ -2178,7 +2210,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
expr.id,
|
||||
qself,
|
||||
path,
|
||||
ParamMode::Optional,
|
||||
ParamMode::Explicit,
|
||||
AllowReturnTypeNotation::No,
|
||||
// FIXME(mgca): update for `fn foo() -> Bar<FOO<impl Trait>>` support
|
||||
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
|
||||
|
|
@ -2244,7 +2276,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> hir::Stmt<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
if let Some(a) = attrs {
|
||||
debug_assert!(!a.is_empty());
|
||||
assert!(!a.is_empty());
|
||||
self.attrs.insert(hir_id.local_id, a);
|
||||
}
|
||||
let local = hir::LetStmt {
|
||||
|
|
|
|||
|
|
@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
feature: sym::cmse_nonsecure_entry,
|
||||
explain: GateReason::Experimental,
|
||||
}),
|
||||
ExternAbi::Custom => {
|
||||
Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
ast_passes_abi_custom_coroutine =
|
||||
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
|
||||
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
|
||||
|
||||
ast_passes_abi_custom_invalid_signature =
|
||||
invalid signature for `extern "custom"` function
|
||||
.note = functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
.suggestion = remove the parameters and return type
|
||||
|
||||
ast_passes_abi_custom_safe_foreign_function =
|
||||
foreign functions with the `"custom"` ABI cannot be safe
|
||||
.suggestion = remove the `safe` keyword from this definition
|
||||
|
||||
ast_passes_abi_custom_safe_function =
|
||||
functions with the `"custom"` ABI must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::ExternAbi;
|
||||
|
|
@ -81,6 +82,7 @@ struct AstValidator<'a> {
|
|||
|
||||
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
||||
extern_mod_safety: Option<Safety>,
|
||||
extern_mod_abi: Option<ExternAbi>,
|
||||
|
||||
lint_node_id: NodeId,
|
||||
|
||||
|
|
@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
|
|||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
fn with_in_extern_mod(
|
||||
&mut self,
|
||||
extern_mod_safety: Safety,
|
||||
abi: Option<ExternAbi>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
|
||||
f(self);
|
||||
self.extern_mod_safety = old;
|
||||
self.extern_mod_safety = old_safety;
|
||||
self.extern_mod_abi = old_abi;
|
||||
}
|
||||
|
||||
fn with_tilde_const(
|
||||
|
|
@ -215,20 +224,6 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
|
||||
if let Some(ref ident) = field.ident
|
||||
&& ident.name == kw::Underscore
|
||||
{
|
||||
self.visit_vis(&field.vis);
|
||||
self.visit_ident(ident);
|
||||
self.visit_ty_common(&field.ty);
|
||||
self.walk_ty(&field.ty);
|
||||
walk_list!(self, visit_attribute, &field.attrs);
|
||||
} else {
|
||||
self.visit_field_def(field);
|
||||
}
|
||||
}
|
||||
|
||||
fn dcx(&self) -> DiagCtxtHandle<'a> {
|
||||
self.sess.dcx()
|
||||
}
|
||||
|
|
@ -370,6 +365,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 +1059,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;
|
||||
|
|
@ -1065,8 +1121,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
VariantData::Struct { fields, .. } => {
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
self.visit_generics(generics);
|
||||
// Permit `Anon{Struct,Union}` as field type.
|
||||
walk_list!(self, visit_struct_field_def, fields);
|
||||
walk_list!(self, visit_field_def, fields);
|
||||
}
|
||||
_ => visit::walk_item(self, item),
|
||||
},
|
||||
|
|
@ -1078,8 +1133,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
VariantData::Struct { fields, .. } => {
|
||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||
self.visit_generics(generics);
|
||||
// Permit `Anon{Struct,Union}` as field type.
|
||||
walk_list!(self, visit_struct_field_def, fields);
|
||||
walk_list!(self, visit_field_def, fields);
|
||||
}
|
||||
_ => visit::walk_item(self, item),
|
||||
}
|
||||
|
|
@ -1145,6 +1199,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 +1409,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 +1767,7 @@ pub fn check_crate(
|
|||
outer_impl_trait_span: None,
|
||||
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||
extern_mod_safety: None,
|
||||
extern_mod_abi: None,
|
||||
lint_node_id: CRATE_NODE_ID,
|
||||
is_sdylib_interface,
|
||||
lint_buffer: lints,
|
||||
|
|
|
|||
|
|
@ -824,3 +824,67 @@ pub(crate) struct MissingAbi {
|
|||
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_safe_foreign_function)]
|
||||
pub(crate) struct AbiCustomSafeForeignFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub safe_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_safe_function)]
|
||||
pub(crate) struct AbiCustomSafeFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "unsafe ",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub unsafe_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_coroutine)]
|
||||
pub(crate) struct AbiCustomCoroutine {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub coroutine_kind_span: Span,
|
||||
pub coroutine_kind_str: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_invalid_signature)]
|
||||
#[note]
|
||||
pub(crate) struct AbiCustomInvalidSignature {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{padding}fn {symbol}()",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub suggestion_span: Span,
|
||||
pub symbol: Symbol,
|
||||
pub padding: &'static str,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,16 @@ macro_rules! gate_alt {
|
|||
feature_err(&$visitor.sess, $name, $span, $explain).emit();
|
||||
}
|
||||
}};
|
||||
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
|
||||
if !$has_feature && !$span.allows_unstable($name) {
|
||||
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
|
||||
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
|
||||
for note in $notes {
|
||||
diag.note(*note);
|
||||
}
|
||||
diag.emit();
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
/// The case involving a multispan.
|
||||
|
|
@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
|
||||
// Check feature gates for built-in attributes.
|
||||
if let Some(BuiltinAttribute {
|
||||
gate: AttributeGate::Gated(_, name, descr, has_feature),
|
||||
gate: AttributeGate::Gated { feature, message, check, notes, .. },
|
||||
..
|
||||
}) = attr_info
|
||||
{
|
||||
gate_alt!(self, has_feature(self.features), *name, attr.span, *descr);
|
||||
gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
|
||||
}
|
||||
// Check unstable flavors of the `#[doc]` attribute.
|
||||
if attr.has_name(sym::doc) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String {
|
|||
State::new().item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn assoc_item_to_string(i: &ast::AssocItem) -> String {
|
||||
State::new().assoc_item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String {
|
||||
State::new().foreign_item_to_string(i)
|
||||
}
|
||||
|
||||
pub fn stmt_to_string(s: &ast::Stmt) -> String {
|
||||
State::new().stmt_to_string(s)
|
||||
}
|
||||
|
||||
pub fn path_to_string(p: &ast::Path) -> String {
|
||||
State::new().path_to_string(p)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1063,6 +1063,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
|
|||
Self::to_string(|s| s.print_item(i))
|
||||
}
|
||||
|
||||
fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
|
||||
Self::to_string(|s| s.print_assoc_item(i))
|
||||
}
|
||||
|
||||
fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
|
||||
Self::to_string(|s| s.print_foreign_item(i))
|
||||
}
|
||||
|
||||
fn path_to_string(&self, p: &ast::Path) -> String {
|
||||
Self::to_string(|s| s.print_path(p, false, 0))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ use rustc_ast::util::classify;
|
|||
use rustc_ast::util::literal::escape_byte_str_symbol;
|
||||
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
|
||||
use rustc_ast::{
|
||||
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
|
||||
FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
|
||||
self as ast, BinOpKind, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece,
|
||||
FormatCount, FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
|
||||
};
|
||||
|
||||
use crate::pp::Breaks::Inconsistent;
|
||||
|
|
@ -214,13 +214,6 @@ impl<'a> State<'a> {
|
|||
}
|
||||
|
||||
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
|
||||
let needs_paren = match func.kind {
|
||||
// In order to call a named field, needs parens: `(self.fun)()`
|
||||
// But not for an unnamed field: `self.0()`
|
||||
ast::ExprKind::Field(_, name) => !name.is_numeric(),
|
||||
_ => func.precedence() < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
// Independent of parenthesization related to precedence, we must
|
||||
// parenthesize `func` if this is a statement context in which without
|
||||
// parentheses, a statement boundary would occur inside `func` or
|
||||
|
|
@ -237,8 +230,16 @@ impl<'a> State<'a> {
|
|||
// because the latter is valid syntax but with the incorrect meaning.
|
||||
// It's a match-expression followed by tuple-expression, not a function
|
||||
// call.
|
||||
self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression());
|
||||
let func_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
|
||||
let needs_paren = match func.kind {
|
||||
// In order to call a named field, needs parens: `(self.fun)()`
|
||||
// But not for an unnamed field: `self.0()`
|
||||
ast::ExprKind::Field(_, name) => !name.is_numeric(),
|
||||
_ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous,
|
||||
};
|
||||
|
||||
self.print_expr_cond_paren(func, needs_paren, func_fixup);
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
|
|
@ -281,9 +282,24 @@ impl<'a> State<'a> {
|
|||
rhs: &ast::Expr,
|
||||
fixup: FixupContext,
|
||||
) {
|
||||
let operator_can_begin_expr = match op {
|
||||
| BinOpKind::Sub // -x
|
||||
| BinOpKind::Mul // *x
|
||||
| BinOpKind::And // &&x
|
||||
| BinOpKind::Or // || x
|
||||
| BinOpKind::BitAnd // &x
|
||||
| BinOpKind::BitOr // |x| x
|
||||
| BinOpKind::Shl // <<T as Trait>::Type as Trait>::CONST
|
||||
| BinOpKind::Lt // <T as Trait>::CONST
|
||||
=> true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let left_fixup = fixup.leftmost_subexpression_with_operator(operator_can_begin_expr);
|
||||
|
||||
let binop_prec = op.precedence();
|
||||
let left_prec = lhs.precedence();
|
||||
let right_prec = rhs.precedence();
|
||||
let left_prec = left_fixup.precedence(lhs);
|
||||
let right_prec = fixup.precedence(rhs);
|
||||
|
||||
let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
|
||||
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
|
||||
|
|
@ -312,18 +328,18 @@ impl<'a> State<'a> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
|
||||
self.print_expr_cond_paren(lhs, left_needs_paren, left_fixup);
|
||||
self.space();
|
||||
self.word_space(op.as_str());
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
|
||||
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.rightmost_subexpression());
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
|
||||
self.word(op.as_str());
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(expr) < ExprPrecedence::Prefix,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -344,8 +360,8 @@ impl<'a> State<'a> {
|
|||
}
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Prefix,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(expr) < ExprPrecedence::Prefix,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -590,8 +606,8 @@ impl<'a> State<'a> {
|
|||
self.word_space("=");
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(rhs) < ExprPrecedence::Assign,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::AssignOp(op, lhs, rhs) => {
|
||||
|
|
@ -604,8 +620,8 @@ impl<'a> State<'a> {
|
|||
self.word_space(op.node.as_str());
|
||||
self.print_expr_cond_paren(
|
||||
rhs,
|
||||
rhs.precedence() < ExprPrecedence::Assign,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(rhs) < ExprPrecedence::Assign,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
ast::ExprKind::Field(expr, ident) => {
|
||||
|
|
@ -618,10 +634,11 @@ impl<'a> State<'a> {
|
|||
self.print_ident(*ident);
|
||||
}
|
||||
ast::ExprKind::Index(expr, index, _) => {
|
||||
let expr_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Unambiguous,
|
||||
fixup.leftmost_subexpression(),
|
||||
expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous,
|
||||
expr_fixup,
|
||||
);
|
||||
self.word("[");
|
||||
self.print_expr(index, FixupContext::default());
|
||||
|
|
@ -634,10 +651,11 @@ impl<'a> State<'a> {
|
|||
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
|
||||
let fake_prec = ExprPrecedence::LOr;
|
||||
if let Some(e) = start {
|
||||
let start_fixup = fixup.leftmost_subexpression_with_operator(true);
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.leftmost_subexpression(),
|
||||
start_fixup.precedence(e) < fake_prec,
|
||||
start_fixup,
|
||||
);
|
||||
}
|
||||
match limits {
|
||||
|
|
@ -647,8 +665,8 @@ impl<'a> State<'a> {
|
|||
if let Some(e) = end {
|
||||
self.print_expr_cond_paren(
|
||||
e,
|
||||
e.precedence() < fake_prec,
|
||||
fixup.subsequent_subexpression(),
|
||||
fixup.precedence(e) < fake_prec,
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -665,11 +683,10 @@ impl<'a> State<'a> {
|
|||
self.space();
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
// Parenthesize if required by precedence, or in the
|
||||
// case of `break 'inner: loop { break 'inner 1 } + 1`
|
||||
expr.precedence() < ExprPrecedence::Jump
|
||||
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
|
||||
fixup.subsequent_subexpression(),
|
||||
// Parenthesize `break 'inner: loop { break 'inner 1 } + 1`
|
||||
// ^---------------------------------^
|
||||
opt_label.is_none() && classify::leading_labeled_expr(expr),
|
||||
fixup.rightmost_subexpression(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -684,11 +701,7 @@ impl<'a> State<'a> {
|
|||
self.word("return");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yeet(result) => {
|
||||
|
|
@ -697,21 +710,13 @@ impl<'a> State<'a> {
|
|||
self.word("yeet");
|
||||
if let Some(expr) = result {
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Become(result) => {
|
||||
self.word("become");
|
||||
self.word(" ");
|
||||
self.print_expr_cond_paren(
|
||||
result,
|
||||
result.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(result, fixup.rightmost_subexpression());
|
||||
}
|
||||
ast::ExprKind::InlineAsm(a) => {
|
||||
// FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`.
|
||||
|
|
@ -761,11 +766,7 @@ impl<'a> State<'a> {
|
|||
|
||||
if let Some(expr) = e {
|
||||
self.space();
|
||||
self.print_expr_cond_paren(
|
||||
expr,
|
||||
expr.precedence() < ExprPrecedence::Jump,
|
||||
fixup.subsequent_subexpression(),
|
||||
);
|
||||
self.print_expr(expr, fixup.rightmost_subexpression());
|
||||
}
|
||||
}
|
||||
ast::ExprKind::Yield(YieldKind::Postfix(e)) => {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_ast::Expr;
|
||||
use rustc_ast::util::{classify, parser};
|
||||
use rustc_ast::util::classify;
|
||||
use rustc_ast::util::parser::{self, ExprPrecedence};
|
||||
use rustc_ast::{Expr, ExprKind, YieldKind};
|
||||
|
||||
// The default amount of fixing is minimal fixing, so all fixups are set to `false` by `Default`.
|
||||
// Fixups should be turned on in a targeted fashion where needed.
|
||||
|
|
@ -93,6 +94,24 @@ pub(crate) struct FixupContext {
|
|||
/// }
|
||||
/// ```
|
||||
parenthesize_exterior_struct_lit: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let _ = (return) - 1; // without paren, this would return -1
|
||||
///
|
||||
/// let _ = return + 1; // no paren because '+' cannot begin expr
|
||||
/// ```
|
||||
next_operator_can_begin_expr: bool,
|
||||
|
||||
/// This is the difference between:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let _ = 1 + return 1; // no parens if rightmost subexpression
|
||||
///
|
||||
/// let _ = 1 + (return 1) + 1; // needs parens
|
||||
/// ```
|
||||
next_operator_can_continue_expr: bool,
|
||||
}
|
||||
|
||||
impl FixupContext {
|
||||
|
|
@ -134,6 +153,8 @@ impl FixupContext {
|
|||
match_arm: false,
|
||||
leftmost_subexpression_in_match_arm: self.match_arm
|
||||
|| self.leftmost_subexpression_in_match_arm,
|
||||
next_operator_can_begin_expr: false,
|
||||
next_operator_can_continue_expr: true,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
|
@ -148,19 +169,34 @@ impl FixupContext {
|
|||
leftmost_subexpression_in_stmt: false,
|
||||
match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
|
||||
leftmost_subexpression_in_match_arm: false,
|
||||
next_operator_can_begin_expr: false,
|
||||
next_operator_can_continue_expr: true,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing any
|
||||
/// subexpression that is neither a leftmost subexpression nor surrounded in
|
||||
/// delimiters.
|
||||
/// Transform this fixup into the one that should apply when printing a
|
||||
/// leftmost subexpression followed by punctuation that is legal as the
|
||||
/// first token of an expression.
|
||||
pub(crate) fn leftmost_subexpression_with_operator(
|
||||
self,
|
||||
next_operator_can_begin_expr: bool,
|
||||
) -> Self {
|
||||
FixupContext { next_operator_can_begin_expr, ..self.leftmost_subexpression() }
|
||||
}
|
||||
|
||||
/// Transform this fixup into the one that should apply when printing the
|
||||
/// rightmost subexpression of the current expression.
|
||||
///
|
||||
/// This is for any subexpression that has a different first token than the
|
||||
/// current expression, and is not surrounded by a paren/bracket/brace. For
|
||||
/// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
|
||||
/// `$a.f($b)`.
|
||||
pub(crate) fn subsequent_subexpression(self) -> Self {
|
||||
/// The rightmost subexpression is any subexpression that has a different
|
||||
/// first token than the current expression, but has the same last token.
|
||||
///
|
||||
/// For example in `$a + $b` and `-$b`, the subexpression `$b` is a
|
||||
/// rightmost subexpression.
|
||||
///
|
||||
/// Not every expression has a rightmost subexpression. For example neither
|
||||
/// `[$b]` nor `$a.f($b)` have one.
|
||||
pub(crate) fn rightmost_subexpression(self) -> Self {
|
||||
FixupContext {
|
||||
stmt: false,
|
||||
leftmost_subexpression_in_stmt: false,
|
||||
|
|
@ -193,6 +229,39 @@ impl FixupContext {
|
|||
/// "let chain".
|
||||
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
|
||||
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|
||||
|| parser::needs_par_as_let_scrutinee(expr.precedence())
|
||||
|| parser::needs_par_as_let_scrutinee(self.precedence(expr))
|
||||
}
|
||||
|
||||
/// Determines the effective precedence of a subexpression. Some expressions
|
||||
/// have higher or lower precedence when adjacent to particular operators.
|
||||
pub(crate) fn precedence(self, expr: &Expr) -> ExprPrecedence {
|
||||
if self.next_operator_can_begin_expr {
|
||||
// Decrease precedence of value-less jumps when followed by an
|
||||
// operator that would otherwise get interpreted as beginning a
|
||||
// value for the jump.
|
||||
if let ExprKind::Break(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Yield(YieldKind::Prefix(..)) = expr.kind
|
||||
{
|
||||
return ExprPrecedence::Jump;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.next_operator_can_continue_expr {
|
||||
// Increase precedence of expressions that extend to the end of
|
||||
// current statement or group.
|
||||
if let ExprKind::Break(..)
|
||||
| ExprKind::Closure(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yeet(..)
|
||||
| ExprKind::Yield(YieldKind::Prefix(..))
|
||||
| ExprKind::Range(None, ..) = expr.kind
|
||||
{
|
||||
return ExprPrecedence::Prefix;
|
||||
}
|
||||
}
|
||||
|
||||
expr.precedence()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
|
||||
pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
|
||||
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
|
||||
self.ann.pre(self, AnnNode::SubItem(id));
|
||||
self.hardbreak_if_not_bol();
|
||||
|
|
@ -548,7 +548,7 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_assoc_item(&mut self, item: &ast::AssocItem) {
|
||||
pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
|
||||
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
|
||||
self.ann.pre(self, AnnNode::SubItem(id));
|
||||
self.hardbreak_if_not_bol();
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use thin_vec::ThinVec;
|
|||
|
||||
use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability};
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
|
||||
pub enum InlineAttr {
|
||||
None,
|
||||
Hint,
|
||||
|
|
@ -130,24 +130,54 @@ impl Deprecation {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represent parsed, *built in*, inert attributes.
|
||||
/// Represents parsed *built-in* inert attributes.
|
||||
///
|
||||
/// That means attributes that are not actually ever expanded.
|
||||
/// For more information on this, see the module docs on the [`rustc_attr_parsing`] crate.
|
||||
/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler.
|
||||
/// These are kept around after the AST, into the HIR and further on.
|
||||
/// ## Overview
|
||||
/// These attributes are markers that guide the compilation process and are never expanded into other code.
|
||||
/// They persist throughout the compilation phases, from AST to HIR and beyond.
|
||||
///
|
||||
/// The word "parsed" could be a little misleading here, because the parser already parses
|
||||
/// attributes early on. However, the result, an [`ast::Attribute`]
|
||||
/// is only parsed at a high level, still containing a token stream in many cases. That is
|
||||
/// because the structure of the contents varies from attribute to attribute.
|
||||
/// With a parsed attribute I mean that each attribute is processed individually into a
|
||||
/// final structure, which on-site (the place where the attribute is useful for, think the
|
||||
/// the place where `must_use` is checked) little to no extra parsing or validating needs to
|
||||
/// happen.
|
||||
/// ## Attribute Processing
|
||||
/// While attributes are initially parsed by [`rustc_parse`] into [`ast::Attribute`], they still contain raw token streams
|
||||
/// because different attributes have different internal structures. This enum represents the final,
|
||||
/// fully parsed form of these attributes, where each variant contains contains all the information and
|
||||
/// structure relevant for the specific attribute.
|
||||
///
|
||||
/// For more docs, look in [`rustc_attr_parsing`].
|
||||
/// Some attributes can be applied multiple times to the same item, and they are "collapsed" into a single
|
||||
/// semantic attribute. For example:
|
||||
/// ```rust
|
||||
/// #[repr(C)]
|
||||
/// #[repr(packed)]
|
||||
/// struct S { }
|
||||
/// ```
|
||||
/// This is equivalent to `#[repr(C, packed)]` and results in a single [`AttributeKind::Repr`] containing
|
||||
/// both `C` and `packed` annotations. This collapsing happens during parsing and is reflected in the
|
||||
/// data structures defined in this enum.
|
||||
///
|
||||
/// ## Usage
|
||||
/// These parsed attributes are used throughout the compiler to:
|
||||
/// - Control code generation (e.g., `#[repr]`)
|
||||
/// - Mark API stability (`#[stable]`, `#[unstable]`)
|
||||
/// - Provide documentation (`#[doc]`)
|
||||
/// - Guide compiler behavior (e.g., `#[allow_internal_unstable]`)
|
||||
///
|
||||
/// ## Note on Attribute Organization
|
||||
/// Some attributes like `InlineAttr`, `OptimizeAttr`, and `InstructionSetAttr` are defined separately
|
||||
/// from this enum because they are used in specific compiler phases (like code generation) and don't
|
||||
/// need to persist throughout the entire compilation process. They are typically processed and
|
||||
/// converted into their final form earlier in the compilation pipeline.
|
||||
///
|
||||
/// For example:
|
||||
/// - `InlineAttr` is used during code generation to control function inlining
|
||||
/// - `OptimizeAttr` is used to control optimization levels
|
||||
/// - `InstructionSetAttr` is used for target-specific code generation
|
||||
///
|
||||
/// These attributes are handled by their respective compiler passes in the [`rustc_codegen_ssa`] crate
|
||||
/// and don't need to be preserved in the same way as the attributes in this enum.
|
||||
///
|
||||
/// For more details on attribute parsing, see the [`rustc_attr_parsing`] crate.
|
||||
///
|
||||
/// [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html
|
||||
/// [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html
|
||||
/// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html
|
||||
#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
|
||||
pub enum AttributeKind {
|
||||
|
|
@ -158,6 +188,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[allow_internal_unstable]`.
|
||||
AllowInternalUnstable(ThinVec<(Symbol, Span)>),
|
||||
|
||||
/// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
|
||||
AsPtr(Span),
|
||||
|
||||
/// Represents `#[rustc_default_body_unstable]`.
|
||||
BodyStability {
|
||||
stability: DefaultBodyStability,
|
||||
|
|
@ -188,6 +221,9 @@ pub enum AttributeKind {
|
|||
/// 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 `#[inline]` and `#[rustc_force_inline]`.
|
||||
Inline(InlineAttr, Span),
|
||||
|
||||
/// Represents `#[rustc_macro_transparency]`.
|
||||
MacroTransparency(Transparency),
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
//! Data structures for representing parsed attributes in the Rust compiler.
|
||||
//! For detailed documentation about attribute processing,
|
||||
//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html).
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(internal_features)]
|
||||
#![doc(rust_logo)]
|
||||
|
|
@ -8,6 +12,8 @@ mod attributes;
|
|||
mod stability;
|
||||
mod version;
|
||||
|
||||
pub mod lints;
|
||||
|
||||
use std::num::NonZero;
|
||||
|
||||
pub use attributes::*;
|
||||
|
|
|
|||
15
compiler/rustc_attr_data_structures/src/lints.rs
Normal file
15
compiler/rustc_attr_data_structures/src/lints.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub struct AttributeLint<Id> {
|
||||
pub id: Id,
|
||||
pub span: Span,
|
||||
pub kind: AttributeLintKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub enum AttributeLintKind {
|
||||
UnusedDuplicate { this: Span, other: Span, warning: bool },
|
||||
IllFormedAttributeInput { suggestions: Vec<String> },
|
||||
}
|
||||
|
|
@ -132,6 +132,7 @@ pub enum StabilityLevel {
|
|||
/// fn foobar() {}
|
||||
/// ```
|
||||
implied_by: Option<Symbol>,
|
||||
old_name: Option<Symbol>,
|
||||
},
|
||||
/// `#[stable]`
|
||||
Stable {
|
||||
|
|
|
|||
|
|
@ -23,8 +23,10 @@ attr_parsing_expects_feature_list =
|
|||
attr_parsing_expects_features =
|
||||
`{$name}` expects feature names
|
||||
|
||||
attr_parsing_incorrect_meta_item = expected a quoted string literal
|
||||
attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes
|
||||
attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
|
||||
[1] attribute must be of the form {$suggestions}
|
||||
*[other] valid forms for the attribute are {$suggestions}
|
||||
}
|
||||
|
||||
attr_parsing_incorrect_repr_format_align_one_arg =
|
||||
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
|
||||
|
|
@ -81,9 +83,6 @@ attr_parsing_missing_note =
|
|||
attr_parsing_missing_since =
|
||||
missing 'since'
|
||||
|
||||
attr_parsing_multiple_item =
|
||||
multiple '{$item}' items
|
||||
|
||||
attr_parsing_multiple_stability_levels =
|
||||
multiple stability levels
|
||||
|
||||
|
|
@ -122,16 +121,21 @@ attr_parsing_unsupported_literal_cfg_boolean =
|
|||
literal in `cfg` predicate value must be a boolean
|
||||
attr_parsing_unsupported_literal_cfg_string =
|
||||
literal in `cfg` predicate value must be a string
|
||||
attr_parsing_unsupported_literal_deprecated_kv_pair =
|
||||
item in `deprecated` must be a key/value pair
|
||||
attr_parsing_unsupported_literal_deprecated_string =
|
||||
literal in `deprecated` value must be a string
|
||||
attr_parsing_unsupported_literal_generic =
|
||||
unsupported literal
|
||||
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!
|
||||
|
|
|
|||
|
|
@ -1,44 +1,49 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
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;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
|
||||
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;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
|
||||
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::template;
|
||||
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,40 +13,36 @@ pub(crate) struct ConfusablesParser {
|
|||
first_span: Option<Span>,
|
||||
}
|
||||
|
||||
impl AttributeParser for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[(&[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
|
||||
// tcx.get_attr().
|
||||
return;
|
||||
};
|
||||
|
||||
if list.is_empty() {
|
||||
cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
|
||||
}
|
||||
|
||||
for param in list.mixed() {
|
||||
let span = param.span();
|
||||
|
||||
let Some(lit) = param.lit() else {
|
||||
cx.emit_err(session_diagnostics::IncorrectMetaItem {
|
||||
span,
|
||||
suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion {
|
||||
lo: span.shrink_to_lo(),
|
||||
hi: span.shrink_to_hi(),
|
||||
}),
|
||||
});
|
||||
continue;
|
||||
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::rustc_confusables],
|
||||
template!(List: r#""name1", "name2", ..."#),
|
||||
|this, cx, args| {
|
||||
let Some(list) = args.list() else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
return;
|
||||
};
|
||||
|
||||
this.confusables.push(lit.symbol);
|
||||
}
|
||||
if list.is_empty() {
|
||||
cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
|
||||
}
|
||||
|
||||
this.first_span.get_or_insert(cx.attr_span);
|
||||
})];
|
||||
for param in list.mixed() {
|
||||
let span = param.span();
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
let Some(lit) = param.lit().and_then(|i| i.value_str()) else {
|
||||
cx.expected_string_literal(span, param.lit());
|
||||
continue;
|
||||
};
|
||||
|
||||
this.confusables.push(lit);
|
||||
}
|
||||
|
||||
this.first_span.get_or_insert(cx.attr_span);
|
||||
},
|
||||
)];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.confusables.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,59 +1,50 @@
|
|||
use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
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<'_>,
|
||||
item: &Option<Symbol>,
|
||||
) -> Option<Symbol> {
|
||||
if item.is_some() {
|
||||
cx.emit_err(session_diagnostics::MultipleItem { span: param_span, item: name.to_string() });
|
||||
cx.duplicate_key(param_span, name);
|
||||
return None;
|
||||
}
|
||||
if let Some(v) = arg.name_value() {
|
||||
if let Some(value_str) = v.value_as_str() {
|
||||
Some(value_str)
|
||||
} else {
|
||||
let lit = v.value_as_lit();
|
||||
cx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: v.value_span,
|
||||
reason: UnsupportedLiteralReason::DeprecatedString,
|
||||
is_bytestr: lit.kind.is_bytestr(),
|
||||
start_point_span: cx.sess().source_map().start_point(lit.span),
|
||||
});
|
||||
cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
|
||||
None
|
||||
}
|
||||
} else {
|
||||
// FIXME(jdonszelmann): suggestion?
|
||||
cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None });
|
||||
cx.expected_name_value(param_span, Some(name));
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
const TEMPLATE: AttributeTemplate = template!(
|
||||
Word,
|
||||
List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
|
||||
NameValueStr: "reason"
|
||||
);
|
||||
|
||||
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;
|
||||
|
|
@ -62,57 +53,60 @@ impl SingleAttributeParser for DeprecationParser {
|
|||
|
||||
let is_rustc = features.staged_api();
|
||||
|
||||
if let Some(value) = args.name_value()
|
||||
&& let Some(value_str) = value.value_as_str()
|
||||
{
|
||||
note = Some(value_str)
|
||||
} else if let Some(list) = args.list() {
|
||||
for param in list.mixed() {
|
||||
let param_span = param.span();
|
||||
let Some(param) = param.meta_item() else {
|
||||
cx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
span: param_span,
|
||||
reason: UnsupportedLiteralReason::DeprecatedKvPair,
|
||||
is_bytestr: false,
|
||||
start_point_span: cx.sess().source_map().start_point(param_span),
|
||||
});
|
||||
return None;
|
||||
};
|
||||
|
||||
let ident_name = param.path().word_sym();
|
||||
|
||||
match ident_name {
|
||||
Some(name @ sym::since) => {
|
||||
since = Some(get(cx, name, param_span, param.args(), &since)?);
|
||||
}
|
||||
Some(name @ sym::note) => {
|
||||
note = Some(get(cx, name, param_span, param.args(), ¬e)?);
|
||||
}
|
||||
Some(name @ sym::suggestion) => {
|
||||
if !features.deprecated_suggestion() {
|
||||
cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
|
||||
span: param_span,
|
||||
is_nightly: cx.sess().is_nightly_build(),
|
||||
details: (),
|
||||
});
|
||||
}
|
||||
|
||||
suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
|
||||
}
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param_span,
|
||||
item: param.path().to_string(),
|
||||
expected: if features.deprecated_suggestion() {
|
||||
&["since", "note", "suggestion"]
|
||||
} else {
|
||||
&["since", "note"]
|
||||
},
|
||||
});
|
||||
match args {
|
||||
ArgParser::NoArgs => {
|
||||
// ok
|
||||
}
|
||||
ArgParser::List(list) => {
|
||||
for param in list.mixed() {
|
||||
let Some(param) = param.meta_item() else {
|
||||
cx.unexpected_literal(param.span());
|
||||
return None;
|
||||
};
|
||||
|
||||
let ident_name = param.path().word_sym();
|
||||
|
||||
match ident_name {
|
||||
Some(name @ sym::since) => {
|
||||
since = Some(get(cx, name, param.span(), param.args(), &since)?);
|
||||
}
|
||||
Some(name @ sym::note) => {
|
||||
note = Some(get(cx, name, param.span(), param.args(), ¬e)?);
|
||||
}
|
||||
Some(name @ sym::suggestion) => {
|
||||
if !features.deprecated_suggestion() {
|
||||
cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
|
||||
span: param.span(),
|
||||
is_nightly: cx.sess().is_nightly_build(),
|
||||
details: (),
|
||||
});
|
||||
}
|
||||
|
||||
suggestion =
|
||||
Some(get(cx, name, param.span(), param.args(), &suggestion)?);
|
||||
}
|
||||
_ => {
|
||||
cx.unknown_key(
|
||||
param.span(),
|
||||
param.path().to_string(),
|
||||
if features.deprecated_suggestion() {
|
||||
&["since", "note", "suggestion"]
|
||||
} else {
|
||||
&["since", "note"]
|
||||
},
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(v) => {
|
||||
let Some(value) = v.value_as_str() else {
|
||||
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
note = Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
let since = if let Some(since) = since {
|
||||
|
|
|
|||
97
compiler/rustc_attr_parsing/src/attributes/inline.rs
Normal file
97
compiler/rustc_attr_parsing/src/attributes/inline.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here.
|
||||
// note: need to model better how duplicate attr errors work when not using
|
||||
// SingleAttributeParser which is what we have two of here.
|
||||
|
||||
use rustc_attr_data_structures::lints::AttributeLintKind;
|
||||
use rustc_attr_data_structures::{AttributeKind, InlineAttr};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use super::{AcceptContext, AttributeOrder, OnDuplicate};
|
||||
use crate::attributes::SingleAttributeParser;
|
||||
use crate::context::Stage;
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct InlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args {
|
||||
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = list.single() else {
|
||||
cx.expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
match l.meta_item().and_then(|i| i.path().word_sym()) {
|
||||
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: &mut 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(), l.lit());
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(reason)
|
||||
}
|
||||
ArgParser::NameValue(v) => {
|
||||
let Some(reason) = v.value_as_str() else {
|
||||
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(reason)
|
||||
}
|
||||
};
|
||||
|
||||
Some(AttributeKind::Inline(
|
||||
InlineAttr::Force { attr_span: cx.attr_span, reason },
|
||||
cx.attr_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
21
compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Normal file
21
compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct AsPtrParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_as_ptr];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
// FIXME: check that there's no args (this is currently checked elsewhere)
|
||||
Some(AttributeKind::AsPtr(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
|
@ -12,28 +12,33 @@
|
|||
//! - [`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_PARSERS`](crate::context::ATTRIBUTE_PARSERS) 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_feature::AttributeTemplate;
|
||||
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;
|
||||
pub(crate) mod confusables;
|
||||
pub(crate) mod deprecation;
|
||||
pub(crate) mod inline;
|
||||
pub(crate) mod lint_helpers;
|
||||
pub(crate) mod repr;
|
||||
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], AttributeTemplate, AcceptFn<T, S>)];
|
||||
|
||||
/// An [`AttributeParser`] is a type which searches for syntactic attributes.
|
||||
///
|
||||
|
|
@ -54,11 +59,11 @@ type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)];
|
|||
///
|
||||
/// For a simpler attribute parsing interface, consider using [`SingleAttributeParser`]
|
||||
/// or [`CombineAttributeParser`] instead.
|
||||
pub(crate) trait AttributeParser: Default + 'static {
|
||||
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.
|
||||
|
|
@ -68,7 +73,7 @@ pub(crate) trait AttributeParser: Default + 'static {
|
|||
/// 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<'_>) -> Option<AttributeKind>;
|
||||
fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;
|
||||
}
|
||||
|
||||
/// Alternative to [`AttributeParser`] that automatically handles state management.
|
||||
|
|
@ -80,44 +85,137 @@ 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];
|
||||
pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
|
||||
const PATH: &[Symbol];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder;
|
||||
const ON_DUPLICATE: OnDuplicate<S>;
|
||||
|
||||
/// 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);
|
||||
/// The template this attribute parser should implement. Used for diagnostics.
|
||||
const TEMPLATE: AttributeTemplate;
|
||||
|
||||
/// 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,
|
||||
<T as SingleAttributeParser<S>>::TEMPLATE,
|
||||
|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.
|
||||
|
|
@ -127,35 +225,41 @@ 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>;
|
||||
|
||||
/// The template this attribute parser should implement. Used for diagnostics.
|
||||
const TEMPLATE: AttributeTemplate;
|
||||
|
||||
/// 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,
|
||||
<T as CombineAttributeParser<S>>::TEMPLATE,
|
||||
|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)) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
use rustc_abi::Align;
|
||||
use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
|
||||
use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_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,18 +20,21 @@ 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;
|
||||
// FIXME(jdonszelmann): never used
|
||||
const TEMPLATE: AttributeTemplate = template!(List: "C");
|
||||
|
||||
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 {
|
||||
cx.expected_list(cx.attr_span);
|
||||
return reprs;
|
||||
};
|
||||
|
||||
|
|
@ -91,7 +95,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 +187,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,
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@ use rustc_attr_data_structures::{
|
|||
StableSince, UnstableReason, VERSION_PLACEHOLDER,
|
||||
};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_span::{Ident, 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 +32,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,31 +42,44 @@ impl StabilityParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl AttributeParser for StabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[
|
||||
(&[sym::stable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_stability(cx, args)
|
||||
{
|
||||
this.stability = Some((Stability { level, feature }, cx.attr_span));
|
||||
}
|
||||
}),
|
||||
(&[sym::unstable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_unstability(cx, args)
|
||||
{
|
||||
this.stability = Some((Stability { level, feature }, cx.attr_span));
|
||||
}
|
||||
}),
|
||||
(&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
this.allowed_through_unstable_modules = args.name_value().and_then(|i| i.value_as_str())
|
||||
}),
|
||||
impl<S: Stage> AttributeParser<S> for StabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(
|
||||
&[sym::stable],
|
||||
template!(List: r#"feature = "name", since = "version""#),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_stability(cx, args)
|
||||
{
|
||||
this.stability = Some((Stability { level, feature }, cx.attr_span));
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
&[sym::unstable],
|
||||
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_unstability(cx, args)
|
||||
{
|
||||
this.stability = Some((Stability { level, feature }, cx.attr_span));
|
||||
}
|
||||
},
|
||||
),
|
||||
(
|
||||
&[sym::rustc_allowed_through_unstable_modules],
|
||||
template!(NameValueStr: "deprecation message"),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
this.allowed_through_unstable_modules =
|
||||
args.name_value().and_then(|i| i.value_as_str())
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
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,9 +109,11 @@ pub(crate) struct BodyStabilityParser {
|
|||
stability: Option<(DefaultBodyStability, Span)>,
|
||||
}
|
||||
|
||||
impl AttributeParser for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> =
|
||||
&[(&[sym::rustc_default_body_unstable], |this, cx, args| {
|
||||
impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
|
||||
&[sym::rustc_default_body_unstable],
|
||||
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
|
||||
|this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if this.stability.is_some() {
|
||||
cx.dcx()
|
||||
|
|
@ -105,9 +121,10 @@ impl AttributeParser for BodyStabilityParser {
|
|||
} else if let Some((feature, level)) = parse_unstability(cx, args) {
|
||||
this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span));
|
||||
}
|
||||
})];
|
||||
},
|
||||
)];
|
||||
|
||||
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 +133,13 @@ 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;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word);
|
||||
|
||||
// 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 +152,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,9 +162,9 @@ impl ConstStabilityParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl AttributeParser for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[
|
||||
(&[sym::rustc_const_stable], |this, cx, args| {
|
||||
impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
|
||||
if !this.check_duplicate(cx)
|
||||
|
|
@ -159,7 +176,7 @@ impl AttributeParser for ConstStabilityParser {
|
|||
));
|
||||
}
|
||||
}),
|
||||
(&[sym::rustc_const_unstable], |this, cx, args| {
|
||||
(&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
&& let Some((feature, level)) = parse_unstability(cx, args)
|
||||
|
|
@ -170,13 +187,13 @@ impl AttributeParser for ConstStabilityParser {
|
|||
));
|
||||
}
|
||||
}),
|
||||
(&[sym::rustc_promotable], |this, cx, _| {
|
||||
(&[sym::rustc_promotable], template!(Word), |this, cx, _| {
|
||||
reject_outside_std!(cx);
|
||||
this.promotable = true;
|
||||
}),
|
||||
];
|
||||
|
||||
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,16 +213,14 @@ 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>,
|
||||
name: Ident,
|
||||
) -> Option<()> {
|
||||
if item.is_some() {
|
||||
cx.emit_err(session_diagnostics::MultipleItem {
|
||||
span: param.span(),
|
||||
item: param.path().to_string(),
|
||||
});
|
||||
cx.duplicate_key(name.span, name.name);
|
||||
None
|
||||
} else if let Some(v) = param.args().name_value()
|
||||
&& let Some(s) = v.value_as_str()
|
||||
|
|
@ -213,18 +228,15 @@ fn insert_value_into_option_or_error(
|
|||
*item = Some(s);
|
||||
Some(())
|
||||
} else {
|
||||
cx.emit_err(session_diagnostics::IncorrectMetaItem {
|
||||
span: param.span(),
|
||||
suggestion: None,
|
||||
});
|
||||
cx.expected_name_value(param.span(), Some(name.name));
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
|
@ -242,9 +254,14 @@ pub(crate) fn parse_stability(
|
|||
return None;
|
||||
};
|
||||
|
||||
match param.path().word_sym() {
|
||||
Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?,
|
||||
Some(sym::since) => insert_value_into_option_or_error(cx, ¶m, &mut since)?,
|
||||
let word = param.path().word();
|
||||
match word.map(|i| i.name) {
|
||||
Some(sym::feature) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut feature, word.unwrap())?
|
||||
}
|
||||
Some(sym::since) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut since, word.unwrap())?
|
||||
}
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param_span,
|
||||
|
|
@ -289,8 +306,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 +316,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 {
|
||||
|
|
@ -310,11 +328,16 @@ pub(crate) fn parse_unstability(
|
|||
return None;
|
||||
};
|
||||
|
||||
match param.path().word_sym() {
|
||||
Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?,
|
||||
Some(sym::reason) => insert_value_into_option_or_error(cx, ¶m, &mut reason)?,
|
||||
let word = param.path().word();
|
||||
match word.map(|i| i.name) {
|
||||
Some(sym::feature) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut feature, word.unwrap())?
|
||||
}
|
||||
Some(sym::reason) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut reason, word.unwrap())?
|
||||
}
|
||||
Some(sym::issue) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut issue)?;
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut issue, word.unwrap())?;
|
||||
|
||||
// These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item
|
||||
// is a name/value pair string literal.
|
||||
|
|
@ -344,13 +367,16 @@ pub(crate) fn parse_unstability(
|
|||
is_soft = true;
|
||||
}
|
||||
Some(sym::implied_by) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut implied_by)?
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut implied_by, word.unwrap())?
|
||||
}
|
||||
Some(sym::old_name) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut old_name, word.unwrap())?
|
||||
}
|
||||
_ => {
|
||||
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 +401,7 @@ pub(crate) fn parse_unstability(
|
|||
issue: issue_num,
|
||||
is_soft,
|
||||
implied_by,
|
||||
old_name,
|
||||
};
|
||||
Some((feature, level))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
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,20 +12,29 @@ 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");
|
||||
});
|
||||
const TEMPLATE: AttributeTemplate =
|
||||
template!(NameValueStr: "transparent|semitransparent|opaque");
|
||||
|
||||
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> {
|
||||
match args.name_value().and_then(|nv| nv.value_as_str()) {
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let Some(nv) = args.name_value() else {
|
||||
cx.expected_name_value(cx.attr_span, None);
|
||||
return None;
|
||||
};
|
||||
match nv.value_as_str() {
|
||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||
Some(sym::opaque) => Some(Transparency::Opaque),
|
||||
Some(other) => {
|
||||
cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));
|
||||
Some(_) => {
|
||||
cx.expected_specific_argument_strings(
|
||||
nv.value_span,
|
||||
vec!["transparent", "semitransparent", "opaque"],
|
||||
);
|
||||
None
|
||||
}
|
||||
None => None,
|
||||
|
|
|
|||
|
|
@ -1,19 +1,24 @@
|
|||
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 rustc_ast as ast;
|
||||
use private::Sealed;
|
||||
use rustc_ast::{self as ast, MetaItemLit, 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_feature::{AttributeTemplate, Features};
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
|
||||
use crate::attributes::lint_helpers::AsPtrParser;
|
||||
use crate::attributes::repr::ReprParser;
|
||||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
|
|
@ -21,34 +26,54 @@ use crate::attributes::stability::{
|
|||
use crate::attributes::transparency::TransparencyParser;
|
||||
use crate::attributes::{AttributeParser as _, Combine, Single};
|
||||
use crate::parser::{ArgParser, MetaItemParser};
|
||||
use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
|
||||
|
||||
macro_rules! group_type {
|
||||
($stage: ty) => {
|
||||
LazyLock<(
|
||||
BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
|
||||
Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
|
||||
)>
|
||||
};
|
||||
}
|
||||
|
||||
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::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
|
||||
let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
|
||||
};
|
||||
|
||||
for (k, v) in <$names>::ATTRIBUTES {
|
||||
let old = accepts.insert(*k, Box::new(|cx, args| {
|
||||
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
|
||||
accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
|
||||
STATE_OBJECT.with_borrow_mut(|s| {
|
||||
v(s, cx, args)
|
||||
accept_fn(s, cx, args)
|
||||
})
|
||||
}));
|
||||
assert!(old.is_none());
|
||||
})));
|
||||
}
|
||||
|
||||
finalizes.push(Box::new(|cx| {
|
||||
|
|
@ -62,7 +87,6 @@ macro_rules! attribute_parsers {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
attribute_parsers!(
|
||||
pub(crate) static ATTRIBUTE_PARSERS = [
|
||||
// tidy-alphabetical-start
|
||||
|
|
@ -79,57 +103,255 @@ attribute_parsers!(
|
|||
// tidy-alphabetical-end
|
||||
|
||||
// tidy-alphabetical-start
|
||||
Single<AsPtrParser>,
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<InlineParser>,
|
||||
Single<RustcForceInlineParser>,
|
||||
Single<TransparencyParser>,
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
);
|
||||
|
||||
/// 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) finalize_cx: &'a FinalizeContext<'a>,
|
||||
/// The span of the attribute currently being parsed
|
||||
pub(crate) attr_span: Span,
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for super::Early {}
|
||||
impl Sealed for super::Late {}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for AcceptContext<'a> {
|
||||
type Target = FinalizeContext<'a>;
|
||||
// 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<'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,
|
||||
|
||||
/// The expected structure of the attribute.
|
||||
///
|
||||
/// Used in reporting errors to give a hint to users what the attribute *should* look like.
|
||||
pub(crate) template: &'f AttributeTemplate,
|
||||
|
||||
/// The name of the attribute we're currently accepting.
|
||||
pub(crate) attr_path: AttrPath,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
|
||||
/// must be delayed until after HIR is built. This method will take care of the details of
|
||||
/// that.
|
||||
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
|
||||
let id = self.target_id;
|
||||
(self.emit_lint)(AttributeLint { id, span, kind: lint });
|
||||
}
|
||||
|
||||
pub(crate) fn unknown_key(
|
||||
&self,
|
||||
span: Span,
|
||||
found: String,
|
||||
options: &'static [&'static str],
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(UnknownMetaItem { span, item: found, expected: options })
|
||||
}
|
||||
|
||||
/// error that a string literal was expected.
|
||||
/// You can optionally give the literal you did find (which you found not to be a string literal)
|
||||
/// which can make better errors. For example, if the literal was a byte string it will suggest
|
||||
/// removing the `b` prefix.
|
||||
pub(crate) fn expected_string_literal(
|
||||
&self,
|
||||
span: Span,
|
||||
actual_literal: Option<&MetaItemLit>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedStringLiteral {
|
||||
byte_string: actual_literal.and_then(|i| {
|
||||
i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedList,
|
||||
})
|
||||
}
|
||||
|
||||
/// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
|
||||
/// a nicer error message talking about the specific name that was found lacking a value.
|
||||
pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedNameValue(name),
|
||||
})
|
||||
}
|
||||
|
||||
/// emit an error that a `name = value` pair was found where that name was already seen.
|
||||
pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::DuplicateKey(key),
|
||||
})
|
||||
}
|
||||
|
||||
/// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
|
||||
/// was expected *not* to be a literal, but instead a meta item.
|
||||
pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::UnexpectedLiteral,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedSingleArgument,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn expected_specific_argument(
|
||||
&self,
|
||||
span: Span,
|
||||
possibilities: Vec<&'static str>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn expected_specific_argument_strings(
|
||||
&self,
|
||||
span: Span,
|
||||
possibilities: Vec<&'static str>,
|
||||
) -> ErrorGuaranteed {
|
||||
self.emit_err(AttributeParseError {
|
||||
span,
|
||||
attr_span: self.attr_span,
|
||||
template: self.template.clone(),
|
||||
attribute: self.attr_path.clone(),
|
||||
reason: AttributeParseErrorReason::ExpectedSpecificArgument {
|
||||
possibilities,
|
||||
strings: true,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
|
||||
type Target = FinalizeContext<'f, 'sess, S>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&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
|
||||
}
|
||||
}
|
||||
|
||||
/// Context given to every attribute parser during finalization.
|
||||
///
|
||||
/// 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 +363,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 +387,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 +441,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 finalize_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,13 +507,22 @@ impl<'sess> AttributeParser<'sess> {
|
|||
let args = parser.args();
|
||||
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accept) = ATTRIBUTE_PARSERS.0.get(parts.as_slice()) {
|
||||
let cx = AcceptContext {
|
||||
finalize_cx: &finalize_cx,
|
||||
attr_span: lower_span(attr.span),
|
||||
};
|
||||
if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
|
||||
for (template, accept) in accepts {
|
||||
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),
|
||||
template,
|
||||
attr_path: path.get_attribute_path(),
|
||||
};
|
||||
|
||||
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.
|
||||
|
|
@ -304,8 +552,13 @@ impl<'sess> AttributeParser<'sess> {
|
|||
}
|
||||
|
||||
let mut parsed_attributes = Vec::new();
|
||||
for f in &ATTRIBUTE_PARSERS.1 {
|
||||
if let Some(attr) = f(&finalize_cx) {
|
||||
for f in &S::parsers().1 {
|
||||
if let Some(attr) = f(&mut FinalizeContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target_id,
|
||||
emit_lint: &mut emit_lint,
|
||||
}) {
|
||||
parsed_attributes.push(Attribute::Parsed(attr));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@
|
|||
|
||||
#[macro_use]
|
||||
mod attributes;
|
||||
mod context;
|
||||
pub(crate) mod context;
|
||||
mod lints;
|
||||
pub mod parser;
|
||||
mod session_diagnostics;
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ pub use attributes::cfg::*;
|
|||
pub use attributes::util::{
|
||||
find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
|
||||
};
|
||||
pub use context::{AttributeParser, OmitDoc};
|
||||
pub use context::{AttributeParser, Early, Late, OmitDoc};
|
||||
pub use lints::emit_attribute_lint;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
|
|
|||
32
compiler/rustc_attr_parsing/src/lints.rs
Normal file
32
compiler/rustc_attr_parsing/src/lints.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_errors::{DiagArgValue, 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 },
|
||||
),
|
||||
AttributeLintKind::IllFormedAttributeInput { suggestions } => {
|
||||
lint_emitter.emit_node_span_lint(
|
||||
rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT,
|
||||
*id,
|
||||
*span,
|
||||
session_diagnostics::IllFormedAttributeInput {
|
||||
num_suggestions: suggestions.len(),
|
||||
suggestions: DiagArgValue::StrListSepByAnd(
|
||||
suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@ 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_errors::{
|
||||
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
|
||||
};
|
||||
use rustc_feature::AttributeTemplate;
|
||||
use rustc_hir::AttrPath;
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
|
@ -12,8 +16,6 @@ pub(crate) enum UnsupportedLiteralReason {
|
|||
Generic,
|
||||
CfgString,
|
||||
CfgBoolean,
|
||||
DeprecatedString,
|
||||
DeprecatedKvPair,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
|
@ -32,37 +34,6 @@ pub(crate) struct InvalidPredicate {
|
|||
pub predicate: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_multiple_item, code = E0538)]
|
||||
pub(crate) struct MultipleItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
pub item: String,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_incorrect_meta_item, code = E0539)]
|
||||
pub(crate) struct IncorrectMetaItem {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[subdiagnostic]
|
||||
pub suggestion: Option<IncorrectMetaItemSuggestion>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(
|
||||
attr_parsing_incorrect_meta_item_suggestion,
|
||||
applicability = "maybe-incorrect"
|
||||
)]
|
||||
pub(crate) struct IncorrectMetaItemSuggestion {
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub lo: Span,
|
||||
#[suggestion_part(code = "\"")]
|
||||
pub hi: Span,
|
||||
}
|
||||
|
||||
/// Error code: E0541
|
||||
pub(crate) struct UnknownMetaItem<'a> {
|
||||
pub span: Span,
|
||||
|
|
@ -217,6 +188,7 @@ pub(crate) struct InvalidReprHintNoValue {
|
|||
}
|
||||
|
||||
/// Error code: E0565
|
||||
// FIXME(jdonszelmann): slowly phased out
|
||||
pub(crate) struct UnsupportedLiteral {
|
||||
pub span: Span,
|
||||
pub reason: UnsupportedLiteralReason,
|
||||
|
|
@ -239,12 +211,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
|
|||
UnsupportedLiteralReason::CfgBoolean => {
|
||||
fluent::attr_parsing_unsupported_literal_cfg_boolean
|
||||
}
|
||||
UnsupportedLiteralReason::DeprecatedString => {
|
||||
fluent::attr_parsing_unsupported_literal_deprecated_string
|
||||
}
|
||||
UnsupportedLiteralReason::DeprecatedKvPair => {
|
||||
fluent::attr_parsing_unsupported_literal_deprecated_kv_pair
|
||||
}
|
||||
},
|
||||
);
|
||||
diag.span(self.span);
|
||||
|
|
@ -451,6 +417,25 @@ 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,
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): duplicated in rustc_lints, should be moved here completely.
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(attr_parsing_ill_formed_attribute_input)]
|
||||
pub(crate) struct IllFormedAttributeInput {
|
||||
pub num_suggestions: usize,
|
||||
pub suggestions: DiagArgValue,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_stability_outside_std, code = E0734)]
|
||||
pub(crate) struct StabilityOutsideStd {
|
||||
|
|
@ -479,3 +464,115 @@ pub(crate) struct UnrecognizedReprHint {
|
|||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub(crate) enum AttributeParseErrorReason {
|
||||
ExpectedStringLiteral { byte_string: Option<Span> },
|
||||
ExpectedSingleArgument,
|
||||
ExpectedList,
|
||||
UnexpectedLiteral,
|
||||
ExpectedNameValue(Option<Symbol>),
|
||||
DuplicateKey(Symbol),
|
||||
ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
|
||||
}
|
||||
|
||||
pub(crate) struct AttributeParseError {
|
||||
pub(crate) span: Span,
|
||||
pub(crate) attr_span: Span,
|
||||
pub(crate) template: AttributeTemplate,
|
||||
pub(crate) attribute: AttrPath,
|
||||
pub(crate) reason: AttributeParseErrorReason,
|
||||
}
|
||||
|
||||
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
|
||||
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
|
||||
let name = self.attribute.to_string();
|
||||
|
||||
let mut diag = Diag::new(dcx, level, format!("malformed `{name}` attribute input"));
|
||||
diag.span(self.attr_span);
|
||||
diag.code(E0539);
|
||||
match self.reason {
|
||||
AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => {
|
||||
if let Some(start_point_span) = byte_string {
|
||||
diag.span_suggestion(
|
||||
start_point_span,
|
||||
fluent::attr_parsing_unsupported_literal_suggestion,
|
||||
"",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
diag.note("expected a normal string literal, not a byte string literal");
|
||||
|
||||
return diag;
|
||||
} else {
|
||||
diag.span_label(self.span, "expected a string literal here");
|
||||
}
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSingleArgument => {
|
||||
diag.span_label(self.span, "expected a single argument here");
|
||||
diag.code(E0805);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedList => {
|
||||
diag.span_label(self.span, "expected this to be a list");
|
||||
}
|
||||
AttributeParseErrorReason::DuplicateKey(key) => {
|
||||
diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
|
||||
diag.code(E0538);
|
||||
}
|
||||
AttributeParseErrorReason::UnexpectedLiteral => {
|
||||
diag.span_label(self.span, format!("didn't expect a literal here"));
|
||||
diag.code(E0565);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedNameValue(None) => {
|
||||
diag.span_label(
|
||||
self.span,
|
||||
format!("expected this to be of the form `{name} = \"...\"`"),
|
||||
);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedNameValue(Some(name)) => {
|
||||
diag.span_label(
|
||||
self.span,
|
||||
format!("expected this to be of the form `{name} = \"...\"`"),
|
||||
);
|
||||
}
|
||||
AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => {
|
||||
let quote = if strings { '"' } else { '`' };
|
||||
match possibilities.as_slice() {
|
||||
&[] => {}
|
||||
&[x] => {
|
||||
diag.span_label(
|
||||
self.span,
|
||||
format!("the only valid argument here is {quote}{x}{quote}"),
|
||||
);
|
||||
}
|
||||
[first, second] => {
|
||||
diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
|
||||
}
|
||||
[first @ .., second_to_last, last] => {
|
||||
let mut res = String::new();
|
||||
for i in first {
|
||||
res.push_str(&format!("{quote}{i}{quote}, "));
|
||||
}
|
||||
res.push_str(&format!(
|
||||
"{quote}{second_to_last}{quote} or {quote}{last}{quote}"
|
||||
));
|
||||
|
||||
diag.span_label(self.span, format!("valid arguments are {res}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let suggestions = self.template.suggestions(false, &name);
|
||||
diag.span_suggestions(
|
||||
self.attr_span,
|
||||
if suggestions.len() == 1 {
|
||||
"must be of the form"
|
||||
} else {
|
||||
"try changing it to one of the following valid forms of the attribute"
|
||||
},
|
||||
suggestions,
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
|
||||
diag
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::fmt;
|
|||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::graph;
|
||||
use rustc_index::bit_set::DenseBitSet;
|
||||
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
|
||||
use rustc_middle::mir::{
|
||||
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
|
||||
};
|
||||
|
|
@ -548,7 +548,7 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
type BorrowsDomain = DenseBitSet<BorrowIndex>;
|
||||
type BorrowsDomain = MixedBitSet<BorrowIndex>;
|
||||
|
||||
/// Forward dataflow computation of the set of borrows that are in scope at a particular location.
|
||||
/// - we gen the introduced loans
|
||||
|
|
@ -564,7 +564,7 @@ impl<'tcx> rustc_mir_dataflow::Analysis<'tcx> for Borrows<'_, 'tcx> {
|
|||
|
||||
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
|
||||
// bottom = nothing is reserved or activated yet;
|
||||
DenseBitSet::new_empty(self.borrow_set.len())
|
||||
MixedBitSet::new_empty(self.borrow_set.len())
|
||||
}
|
||||
|
||||
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
|
||||
|
|
|
|||
|
|
@ -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![
|
||||
|
|
|
|||
|
|
@ -342,6 +342,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
}
|
||||
}
|
||||
} else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
|
||||
let sp = info.span.find_oldest_ancestor_in_same_ctxt();
|
||||
if info.tail_result_is_ignored {
|
||||
// #85581: If the first mutable borrow's scope contains
|
||||
// the second borrow, this suggestion isn't helpful.
|
||||
|
|
@ -349,7 +350,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
old.to(info.span.shrink_to_hi()).contains(new)
|
||||
}) {
|
||||
err.span_suggestion_verbose(
|
||||
info.span.shrink_to_hi(),
|
||||
sp.shrink_to_hi(),
|
||||
"consider adding semicolon after the expression so its \
|
||||
temporaries are dropped sooner, before the local variables \
|
||||
declared by the block are dropped",
|
||||
|
|
@ -368,8 +369,8 @@ impl<'tcx> BorrowExplanation<'tcx> {
|
|||
local variable `x` and then make `x` be the expression at the \
|
||||
end of the block",
|
||||
vec![
|
||||
(info.span.shrink_to_lo(), "let x = ".to_string()),
|
||||
(info.span.shrink_to_hi(), "; x".to_string()),
|
||||
(sp.shrink_to_lo(), "let x = ".to_string()),
|
||||
(sp.shrink_to_hi(), "; x".to_string()),
|
||||
],
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use rustc_errors::LintDiagnostic;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_index::bit_set::{DenseBitSet, MixedBitSet};
|
||||
use rustc_index::bit_set::MixedBitSet;
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
|
||||
|
|
@ -1151,11 +1151,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
|
|||
&self,
|
||||
location: Location,
|
||||
state: &'s BorrowckDomain,
|
||||
) -> Cow<'s, DenseBitSet<BorrowIndex>> {
|
||||
) -> Cow<'s, MixedBitSet<BorrowIndex>> {
|
||||
if let Some(polonius) = &self.polonius_output {
|
||||
// Use polonius output if it has been enabled.
|
||||
let location = self.location_table.start_index(location);
|
||||
let mut polonius_output = DenseBitSet::new_empty(self.borrow_set.len());
|
||||
let mut polonius_output = MixedBitSet::new_empty(self.borrow_set.len());
|
||||
for &idx in polonius.errors_at(location) {
|
||||
polonius_output.insert(idx);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -373,8 +373,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn unsized_feature_enabled(&self) -> bool {
|
||||
let features = self.tcx().features();
|
||||
features.unsized_locals() || features.unsized_fn_params()
|
||||
self.tcx().features().unsized_fn_params()
|
||||
}
|
||||
|
||||
/// Equate the inferred type and the annotated type for user type annotations
|
||||
|
|
@ -957,7 +956,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` or `unsized_locals` is enabled, only function calls
|
||||
// When `unsized_fn_params` is enabled, only function calls
|
||||
// and nullary ops are checked in `check_call_dest`.
|
||||
if !self.unsized_feature_enabled() {
|
||||
match self.body.local_kind(local) {
|
||||
|
|
@ -1941,7 +1940,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
// When `unsized_fn_params` and `unsized_locals` are both not enabled,
|
||||
// When `unsized_fn_params` is not enabled,
|
||||
// this check is done at `check_local`.
|
||||
if self.unsized_feature_enabled() {
|
||||
let span = term.source_info.span;
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ impl CfgEval<'_> {
|
|||
|
||||
impl MutVisitor for CfgEval<'_> {
|
||||
#[instrument(level = "trace", skip(self))]
|
||||
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
|
||||
fn visit_expr(&mut self, expr: &mut ast::Expr) {
|
||||
self.0.configure_expr(expr, false);
|
||||
mut_visit::walk_expr(self, expr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use ast::HasAttrs;
|
||||
use ast::ptr::P;
|
||||
use rustc_ast::mut_visit::MutVisitor;
|
||||
use rustc_ast::visit::BoundKind;
|
||||
use rustc_ast::{
|
||||
|
|
@ -378,11 +377,11 @@ struct TypeSubstitution<'a> {
|
|||
}
|
||||
|
||||
impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
||||
fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
|
||||
fn visit_ty(&mut self, ty: &mut ast::Ty) {
|
||||
if let Some(name) = ty.kind.is_simple_path()
|
||||
&& name == self.from_name
|
||||
{
|
||||
**ty = self.to_ty.clone();
|
||||
*ty = self.to_ty.clone();
|
||||
self.rewritten = true;
|
||||
} else {
|
||||
ast::mut_visit::walk_ty(self, ty);
|
||||
|
|
|
|||
|
|
@ -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(..)))
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -118,10 +118,7 @@ pub(crate) fn expand_test_or_bench(
|
|||
|
||||
let (item, is_stmt) = match item {
|
||||
Annotatable::Item(i) => (i, false),
|
||||
Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => {
|
||||
// FIXME: Use an 'if let' guard once they are implemented
|
||||
if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() }
|
||||
}
|
||||
Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true),
|
||||
other => {
|
||||
not_testable_error(cx, attr_sp, None);
|
||||
return vec![other];
|
||||
|
|
|
|||
|
|
@ -32,10 +32,6 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
|
|||
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
|
||||
|
||||
trait Trait {
|
||||
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
|
||||
// without unsized_locals), but wrappers around `Self` currently are not.
|
||||
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
|
||||
// fn wrapper(self: Wrapper<Self>) -> i32;
|
||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
||||
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
|
||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
|
||||
|
|
|
|||
|
|
@ -14,8 +14,14 @@
|
|||
#![no_core]
|
||||
#![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)]
|
||||
|
||||
#[lang = "pointee_sized"]
|
||||
pub trait PointeeSized {}
|
||||
|
||||
#[lang = "meta_sized"]
|
||||
pub trait MetaSized: PointeeSized {}
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
pub trait Sized: MetaSized {}
|
||||
|
||||
#[lang = "destruct"]
|
||||
pub trait Destruct {}
|
||||
|
|
@ -24,35 +30,35 @@ pub trait Destruct {}
|
|||
pub trait Tuple {}
|
||||
|
||||
#[lang = "unsize"]
|
||||
pub trait Unsize<T: ?Sized> {}
|
||||
pub trait Unsize<T: PointeeSized>: PointeeSized {}
|
||||
|
||||
#[lang = "coerce_unsized"]
|
||||
pub trait CoerceUnsized<T> {}
|
||||
|
||||
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
|
||||
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
|
||||
impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
|
||||
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *const T {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {}
|
||||
|
||||
#[lang = "dispatch_from_dyn"]
|
||||
pub trait DispatchFromDyn<T> {}
|
||||
|
||||
// &T -> &U
|
||||
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
|
||||
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {}
|
||||
// &mut T -> &mut U
|
||||
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
|
||||
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {}
|
||||
// *const T -> *const U
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*const U> for *const T {}
|
||||
// *mut T -> *mut U
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {}
|
||||
impl<T: MetaSized + Unsize<U>, U: MetaSized> DispatchFromDyn<Box<U>> for Box<T> {}
|
||||
|
||||
#[lang = "legacy_receiver"]
|
||||
pub trait LegacyReceiver {}
|
||||
|
||||
impl<T: ?Sized> LegacyReceiver for &T {}
|
||||
impl<T: ?Sized> LegacyReceiver for &mut T {}
|
||||
impl<T: ?Sized> LegacyReceiver for Box<T> {}
|
||||
impl<T: PointeeSized> LegacyReceiver for &T {}
|
||||
impl<T: PointeeSized> LegacyReceiver for &mut T {}
|
||||
impl<T: MetaSized> LegacyReceiver for Box<T> {}
|
||||
|
||||
#[lang = "copy"]
|
||||
pub trait Copy {}
|
||||
|
|
@ -74,9 +80,9 @@ impl Copy for isize {}
|
|||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for char {}
|
||||
impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
impl<T: ?Sized> Copy for *const T {}
|
||||
impl<T: ?Sized> Copy for *mut T {}
|
||||
impl<'a, T: PointeeSized> Copy for &'a T {}
|
||||
impl<T: PointeeSized> Copy for *const T {}
|
||||
impl<T: PointeeSized> Copy for *mut T {}
|
||||
impl<T: Copy> Copy for Option<T> {}
|
||||
|
||||
#[lang = "sync"]
|
||||
|
|
@ -94,17 +100,17 @@ unsafe impl Sync for i32 {}
|
|||
unsafe impl Sync for isize {}
|
||||
unsafe impl Sync for char {}
|
||||
unsafe impl Sync for f32 {}
|
||||
unsafe impl<'a, T: ?Sized> Sync for &'a T {}
|
||||
unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
|
||||
unsafe impl<T: Sync, const N: usize> Sync for [T; N] {}
|
||||
|
||||
#[lang = "freeze"]
|
||||
unsafe auto trait Freeze {}
|
||||
|
||||
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
|
||||
unsafe impl<T: ?Sized> Freeze for *const T {}
|
||||
unsafe impl<T: ?Sized> Freeze for *mut T {}
|
||||
unsafe impl<T: ?Sized> Freeze for &T {}
|
||||
unsafe impl<T: ?Sized> Freeze for &mut T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for PhantomData<T> {}
|
||||
unsafe impl<T: PointeeSized> Freeze for *const T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for *mut T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for &T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for &mut T {}
|
||||
|
||||
#[lang = "structural_peq"]
|
||||
pub trait StructuralPartialEq {}
|
||||
|
|
@ -443,7 +449,7 @@ pub enum Option<T> {
|
|||
pub use Option::*;
|
||||
|
||||
#[lang = "phantom_data"]
|
||||
pub struct PhantomData<T: ?Sized>;
|
||||
pub struct PhantomData<T: PointeeSized>;
|
||||
|
||||
#[lang = "fn_once"]
|
||||
#[rustc_paren_sugar]
|
||||
|
|
@ -564,18 +570,18 @@ pub trait Deref {
|
|||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(1)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
pub struct NonNull<T: ?Sized>(pub *const T);
|
||||
pub struct NonNull<T: PointeeSized>(pub *const T);
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
|
||||
pub struct Unique<T: ?Sized> {
|
||||
pub struct Unique<T: PointeeSized> {
|
||||
pub pointer: NonNull<T>,
|
||||
pub _marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
|
||||
#[lang = "global_alloc_ty"]
|
||||
pub struct Global;
|
||||
|
|
@ -644,9 +650,9 @@ pub mod intrinsics {
|
|||
#[rustc_intrinsic]
|
||||
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
pub fn align_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||
#[rustc_intrinsic]
|
||||
|
|
|
|||
|
|
@ -204,11 +204,8 @@ fn main() {
|
|||
assert_eq!(intrinsics::size_of_val(a) as u8, 16);
|
||||
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
|
||||
|
||||
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
|
||||
assert_eq!(
|
||||
intrinsics::min_align_of_val(&a) as u8,
|
||||
intrinsics::min_align_of::<&str>() as u8
|
||||
);
|
||||
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
|
||||
|
||||
assert!(!intrinsics::needs_drop::<u8>());
|
||||
assert!(!intrinsics::needs_drop::<[u8]>());
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv(
|
|||
CanonAbi::Rust | CanonAbi::C => default_call_conv,
|
||||
CanonAbi::RustCold => CallConv::Cold,
|
||||
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => default_call_conv,
|
||||
|
||||
CanonAbi::X86(x86_call) => match x86_call {
|
||||
X86Call::SysV64 => CallConv::SystemV,
|
||||
X86Call::Win64 => CallConv::WindowsFastcall,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Argument passing
|
||||
|
||||
use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
|
||||
use cranelift_codegen::ir::ArgumentPurpose;
|
||||
use rustc_abi::{Reg, RegKind};
|
||||
use rustc_target::callconv::{
|
||||
ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode,
|
||||
|
|
@ -32,16 +32,26 @@ fn reg_to_abi_param(reg: Reg) -> AbiParam {
|
|||
AbiParam::new(clif_ty)
|
||||
}
|
||||
|
||||
fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
|
||||
fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
|
||||
match arg_attrs.arg_ext {
|
||||
RustcArgExtension::None => {}
|
||||
RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext,
|
||||
RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext,
|
||||
RustcArgExtension::None => param,
|
||||
RustcArgExtension::Zext => param.uext(),
|
||||
RustcArgExtension::Sext => param.sext(),
|
||||
}
|
||||
param
|
||||
}
|
||||
|
||||
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
|
||||
fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2]> {
|
||||
if let Some(offset_from_start) = cast.rest_offset {
|
||||
assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
|
||||
assert_eq!(cast.rest.unit.size, cast.rest.total);
|
||||
let first = cast.prefix[0].unwrap();
|
||||
let second = cast.rest.unit;
|
||||
return smallvec![
|
||||
(Size::ZERO, reg_to_abi_param(first)),
|
||||
(offset_from_start, reg_to_abi_param(second))
|
||||
];
|
||||
}
|
||||
|
||||
let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
|
||||
(0, 0)
|
||||
} else {
|
||||
|
|
@ -56,25 +66,32 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
|
|||
// different types in Cranelift IR. Instead a single array of primitive types is used.
|
||||
|
||||
// Create list of fields in the main structure
|
||||
let mut args = cast
|
||||
let args = cast
|
||||
.prefix
|
||||
.iter()
|
||||
.flatten()
|
||||
.map(|®| reg_to_abi_param(reg))
|
||||
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
|
||||
.collect::<SmallVec<_>>();
|
||||
.chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)));
|
||||
|
||||
let mut res = SmallVec::new();
|
||||
let mut offset = Size::ZERO;
|
||||
|
||||
for arg in args {
|
||||
res.push((offset, arg));
|
||||
offset += Size::from_bytes(arg.value_type.bytes());
|
||||
}
|
||||
|
||||
// Append final integer
|
||||
if rem_bytes != 0 {
|
||||
// Only integers can be really split further.
|
||||
assert_eq!(cast.rest.unit.kind, RegKind::Integer);
|
||||
args.push(reg_to_abi_param(Reg {
|
||||
kind: RegKind::Integer,
|
||||
size: Size::from_bytes(rem_bytes),
|
||||
}));
|
||||
res.push((
|
||||
offset,
|
||||
reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }),
|
||||
));
|
||||
}
|
||||
|
||||
args
|
||||
res
|
||||
}
|
||||
|
||||
impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
||||
|
|
@ -82,7 +99,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
match self.mode {
|
||||
PassMode::Ignore => smallvec![],
|
||||
PassMode::Direct(attrs) => match self.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => smallvec![apply_arg_attrs_to_abi_param(
|
||||
BackendRepr::Scalar(scalar) => smallvec![apply_attrs_to_abi_param(
|
||||
AbiParam::new(scalar_to_clif_type(tcx, scalar)),
|
||||
attrs
|
||||
)],
|
||||
|
|
@ -97,34 +114,34 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
let a = scalar_to_clif_type(tcx, a);
|
||||
let b = scalar_to_clif_type(tcx, b);
|
||||
smallvec![
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a),
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b),
|
||||
apply_attrs_to_abi_param(AbiParam::new(a), attrs_a),
|
||||
apply_attrs_to_abi_param(AbiParam::new(b), attrs_b),
|
||||
]
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.backend_repr),
|
||||
},
|
||||
PassMode::Cast { ref cast, pad_i32 } => {
|
||||
assert!(!pad_i32, "padding support not yet implemented");
|
||||
cast_target_to_abi_params(cast)
|
||||
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect()
|
||||
}
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
||||
if on_stack {
|
||||
// Abi requires aligning struct size to pointer size
|
||||
let size = self.layout.size.align_to(tcx.data_layout.pointer_align.abi);
|
||||
let size = u32::try_from(size.bytes()).unwrap();
|
||||
smallvec![apply_arg_attrs_to_abi_param(
|
||||
smallvec![apply_attrs_to_abi_param(
|
||||
AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),),
|
||||
attrs
|
||||
)]
|
||||
} else {
|
||||
smallvec![apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
|
||||
smallvec![apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs)]
|
||||
}
|
||||
}
|
||||
PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
|
||||
assert!(!on_stack);
|
||||
smallvec![
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
|
||||
apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
|
||||
apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
|
||||
apply_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), meta_attrs),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -133,30 +150,47 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) {
|
||||
match self.mode {
|
||||
PassMode::Ignore => (None, vec![]),
|
||||
PassMode::Direct(_) => match self.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => {
|
||||
(None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))])
|
||||
}
|
||||
PassMode::Direct(attrs) => match self.layout.backend_repr {
|
||||
BackendRepr::Scalar(scalar) => (
|
||||
None,
|
||||
vec![apply_attrs_to_abi_param(
|
||||
AbiParam::new(scalar_to_clif_type(tcx, scalar)),
|
||||
attrs,
|
||||
)],
|
||||
),
|
||||
BackendRepr::SimdVector { .. } => {
|
||||
let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
|
||||
(None, vec![AbiParam::new(vector_ty)])
|
||||
(None, vec![apply_attrs_to_abi_param(AbiParam::new(vector_ty), attrs)])
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.backend_repr),
|
||||
},
|
||||
PassMode::Pair(_, _) => match self.layout.backend_repr {
|
||||
PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr {
|
||||
BackendRepr::ScalarPair(a, b) => {
|
||||
let a = scalar_to_clif_type(tcx, a);
|
||||
let b = scalar_to_clif_type(tcx, b);
|
||||
(None, vec![AbiParam::new(a), AbiParam::new(b)])
|
||||
(
|
||||
None,
|
||||
vec![
|
||||
apply_attrs_to_abi_param(AbiParam::new(a), attrs_a),
|
||||
apply_attrs_to_abi_param(AbiParam::new(b), attrs_b),
|
||||
],
|
||||
)
|
||||
}
|
||||
_ => unreachable!("{:?}", self.layout.backend_repr),
|
||||
},
|
||||
PassMode::Cast { ref cast, .. } => {
|
||||
(None, cast_target_to_abi_params(cast).into_iter().collect())
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: None, on_stack } => {
|
||||
PassMode::Cast { ref cast, .. } => (
|
||||
None,
|
||||
cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(),
|
||||
),
|
||||
PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
|
||||
assert!(!on_stack);
|
||||
(Some(AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn)), vec![])
|
||||
(
|
||||
Some(apply_attrs_to_abi_param(
|
||||
AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructReturn),
|
||||
attrs,
|
||||
)),
|
||||
vec![],
|
||||
)
|
||||
}
|
||||
PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => {
|
||||
unreachable!("unsized return value")
|
||||
|
|
@ -172,12 +206,14 @@ pub(super) fn to_casted_value<'tcx>(
|
|||
) -> SmallVec<[Value; 2]> {
|
||||
let (ptr, meta) = arg.force_stack(fx);
|
||||
assert!(meta.is_none());
|
||||
let mut offset = 0;
|
||||
cast_target_to_abi_params(cast)
|
||||
.into_iter()
|
||||
.map(|param| {
|
||||
let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new());
|
||||
offset += i64::from(param.value_type.bytes());
|
||||
.map(|(offset, param)| {
|
||||
let val = ptr.offset_i64(fx, offset.bytes() as i64).load(
|
||||
fx,
|
||||
param.value_type,
|
||||
MemFlags::new(),
|
||||
);
|
||||
val
|
||||
})
|
||||
.collect()
|
||||
|
|
@ -190,7 +226,7 @@ pub(super) fn from_casted_value<'tcx>(
|
|||
cast: &CastTarget,
|
||||
) -> CValue<'tcx> {
|
||||
let abi_params = cast_target_to_abi_params(cast);
|
||||
let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
|
||||
let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum();
|
||||
let layout_size = u32::try_from(layout.size.bytes()).unwrap();
|
||||
let ptr = fx.create_stack_slot(
|
||||
// Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
|
||||
|
|
@ -199,16 +235,13 @@ pub(super) fn from_casted_value<'tcx>(
|
|||
std::cmp::max(abi_param_size, layout_size),
|
||||
u32::try_from(layout.align.abi.bytes()).unwrap(),
|
||||
);
|
||||
let mut offset = 0;
|
||||
let mut block_params_iter = block_params.iter().copied();
|
||||
for param in abi_params {
|
||||
let val = ptr.offset_i64(fx, offset).store(
|
||||
for (offset, _) in abi_params {
|
||||
ptr.offset_i64(fx, offset.bytes() as i64).store(
|
||||
fx,
|
||||
block_params_iter.next().unwrap(),
|
||||
MemFlags::new(),
|
||||
);
|
||||
offset += i64::from(param.value_type.bytes());
|
||||
val
|
||||
)
|
||||
}
|
||||
assert_eq!(block_params_iter.next(), None, "Leftover block param");
|
||||
CValue::by_ref(ptr, layout)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//! Allocator shim
|
||||
// Adapted from rustc
|
||||
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use rustc_ast::expand::allocator::{
|
||||
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
|
||||
alloc_error_handler_name, default_fn_name, global_fn_name,
|
||||
|
|
@ -97,16 +98,31 @@ fn codegen_inner(
|
|||
data.define(Box::new([val]));
|
||||
module.define_data(data_id, &data).unwrap();
|
||||
|
||||
let data_id = module
|
||||
.declare_data(
|
||||
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
|
||||
Linkage::Export,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
let mut data = DataDescription::new();
|
||||
data.set_align(1);
|
||||
data.define(Box::new([0]));
|
||||
module.define_data(data_id, &data).unwrap();
|
||||
{
|
||||
let sig = Signature {
|
||||
call_conv: module.target_config().default_call_conv,
|
||||
params: vec![],
|
||||
returns: vec![],
|
||||
};
|
||||
let func_id = module
|
||||
.declare_function(
|
||||
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
|
||||
Linkage::Export,
|
||||
&sig,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut ctx = Context::new();
|
||||
ctx.func.signature = sig;
|
||||
let mut func_ctx = FunctionBuilderContext::new();
|
||||
let mut bcx = FunctionBuilder::new(&mut ctx.func, &mut func_ctx);
|
||||
|
||||
let block = bcx.create_block();
|
||||
bcx.switch_to_block(block);
|
||||
bcx.ins().return_(&[]);
|
||||
bcx.seal_all_blocks();
|
||||
bcx.finalize();
|
||||
|
||||
module.define_function(func_id, &mut ctx).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ use std::thread::JoinHandle;
|
|||
use cranelift_object::{ObjectBuilder, ObjectModule};
|
||||
use rustc_codegen_ssa::assert_module_sources::CguReuse;
|
||||
use rustc_codegen_ssa::back::link::ensure_removed;
|
||||
use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file;
|
||||
use rustc_codegen_ssa::base::determine_cgu_reuse;
|
||||
use rustc_codegen_ssa::{
|
||||
CodegenResults, CompiledModule, CrateInfo, ModuleKind, errors as ssa_errors,
|
||||
|
|
@ -19,7 +18,6 @@ use rustc_codegen_ssa::{
|
|||
use rustc_data_structures::profiling::SelfProfilerRef;
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_metadata::fs::copy_to_stdout;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
|
||||
|
|
@ -61,8 +59,6 @@ impl<HCX> HashStable<HCX> for OngoingModuleCodegen {
|
|||
pub(crate) struct OngoingCodegen {
|
||||
modules: Vec<OngoingModuleCodegen>,
|
||||
allocator_module: Option<CompiledModule>,
|
||||
metadata_module: Option<CompiledModule>,
|
||||
metadata: EncodedMetadata,
|
||||
crate_info: CrateInfo,
|
||||
concurrency_limiter: ConcurrencyLimiter,
|
||||
}
|
||||
|
|
@ -134,8 +130,6 @@ impl OngoingCodegen {
|
|||
let codegen_results = CodegenResults {
|
||||
modules,
|
||||
allocator_module: self.allocator_module,
|
||||
metadata_module: self.metadata_module,
|
||||
metadata: self.metadata,
|
||||
crate_info: self.crate_info,
|
||||
};
|
||||
|
||||
|
|
@ -646,42 +640,6 @@ fn module_codegen(
|
|||
}))
|
||||
}
|
||||
|
||||
fn emit_metadata_module(tcx: TyCtxt<'_>, metadata: &EncodedMetadata) -> CompiledModule {
|
||||
use rustc_middle::mir::mono::CodegenUnitNameBuilder;
|
||||
|
||||
let _timer = tcx.sess.timer("write compressed metadata");
|
||||
|
||||
let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
|
||||
let metadata_cgu_name = cgu_name_builder
|
||||
.build_cgu_name(LOCAL_CRATE, ["crate"], Some("metadata"))
|
||||
.as_str()
|
||||
.to_string();
|
||||
|
||||
let tmp_file = tcx.output_filenames(()).temp_path_for_cgu(
|
||||
OutputType::Metadata,
|
||||
&metadata_cgu_name,
|
||||
tcx.sess.invocation_temp.as_deref(),
|
||||
);
|
||||
|
||||
let symbol_name = rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx);
|
||||
let obj = create_compressed_metadata_file(tcx.sess, metadata, &symbol_name);
|
||||
|
||||
if let Err(err) = std::fs::write(&tmp_file, obj) {
|
||||
tcx.dcx().fatal(format!("error writing metadata object file: {}", err));
|
||||
}
|
||||
|
||||
CompiledModule {
|
||||
name: metadata_cgu_name,
|
||||
kind: ModuleKind::Metadata,
|
||||
object: Some(tmp_file),
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
assembly: None,
|
||||
llvm_ir: None,
|
||||
links_from_incr_cache: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> {
|
||||
let mut allocator_module = make_module(tcx.sess, "allocator_shim".to_string());
|
||||
let created_alloc_shim = crate::allocator::codegen(tcx, &mut allocator_module);
|
||||
|
|
@ -706,11 +664,7 @@ fn emit_allocator_module(tcx: TyCtxt<'_>) -> Option<CompiledModule> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn run_aot(
|
||||
tcx: TyCtxt<'_>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<OngoingCodegen> {
|
||||
pub(crate) fn run_aot(tcx: TyCtxt<'_>) -> Box<OngoingCodegen> {
|
||||
// FIXME handle `-Ctarget-cpu=native`
|
||||
let target_cpu = match tcx.sess.opts.cg.target_cpu {
|
||||
Some(ref name) => name,
|
||||
|
|
@ -726,8 +680,6 @@ pub(crate) fn run_aot(
|
|||
return Box::new(OngoingCodegen {
|
||||
modules: vec![],
|
||||
allocator_module: None,
|
||||
metadata_module: None,
|
||||
metadata,
|
||||
crate_info: CrateInfo::new(tcx, target_cpu),
|
||||
concurrency_limiter: ConcurrencyLimiter::new(0),
|
||||
});
|
||||
|
|
@ -787,14 +739,9 @@ pub(crate) fn run_aot(
|
|||
|
||||
let allocator_module = emit_allocator_module(tcx);
|
||||
|
||||
let metadata_module =
|
||||
if need_metadata_module { Some(emit_metadata_module(tcx, &metadata)) } else { None };
|
||||
|
||||
Box::new(OngoingCodegen {
|
||||
modules,
|
||||
allocator_module,
|
||||
metadata_module,
|
||||
metadata,
|
||||
crate_info: CrateInfo::new(tcx, target_cpu),
|
||||
concurrency_limiter: concurrency_limiter.0,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +46,6 @@ use cranelift_codegen::isa::TargetIsa;
|
|||
use cranelift_codegen::settings::{self, Configurable};
|
||||
use rustc_codegen_ssa::traits::CodegenBackend;
|
||||
use rustc_codegen_ssa::{CodegenResults, TargetConfig};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::OutputFilenames;
|
||||
|
|
@ -238,12 +237,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
println!("Cranelift version: {}", cranelift_codegen::VERSION);
|
||||
}
|
||||
|
||||
fn codegen_crate(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> {
|
||||
info!("codegen crate {}", tcx.crate_name(LOCAL_CRATE));
|
||||
let config = self.config.clone().unwrap_or_else(|| {
|
||||
BackendConfig::from_opts(&tcx.sess.opts.cg.llvm_args)
|
||||
|
|
@ -256,7 +250,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
|
|||
#[cfg(not(feature = "jit"))]
|
||||
tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift");
|
||||
} else {
|
||||
driver::aot::run_aot(tcx, metadata, need_metadata_module)
|
||||
driver::aot::run_aot(tcx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>(
|
|||
// load size/align from vtable
|
||||
(
|
||||
crate::vtable::size_of_obj(fx, info.unwrap()),
|
||||
crate::vtable::min_align_of_obj(fx, info.unwrap()),
|
||||
crate::vtable::align_of_obj(fx, info.unwrap()),
|
||||
)
|
||||
}
|
||||
ty::Slice(_) | ty::Str => {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
|
||||
pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
|
||||
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
|
||||
fx.bcx.ins().load(
|
||||
fx.pointer_type,
|
||||
|
|
|
|||
27
compiler/rustc_codegen_gcc/.cspell.json
Normal file
27
compiler/rustc_codegen_gcc/.cspell.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"allowCompoundWords": true,
|
||||
"dictionaries": ["cpp", "rust-extra", "rustc_codegen_gcc"],
|
||||
"dictionaryDefinitions": [
|
||||
{
|
||||
"name": "rust-extra",
|
||||
"path": "tools/cspell_dicts/rust.txt",
|
||||
"addWords": true
|
||||
},
|
||||
{
|
||||
"name": "rustc_codegen_gcc",
|
||||
"path": "tools/cspell_dicts/rustc_codegen_gcc.txt",
|
||||
"addWords": true
|
||||
}
|
||||
],
|
||||
"files": [
|
||||
"src/**/*.rs"
|
||||
],
|
||||
"ignorePaths": [
|
||||
"src/intrinsic/archs.rs",
|
||||
"src/intrinsic/llvm.rs"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"/(FIXME|NOTE|TODO)\\([^)]+\\)/",
|
||||
"__builtin_\\w*"
|
||||
]
|
||||
}
|
||||
|
|
@ -12,6 +12,8 @@ permissions:
|
|||
env:
|
||||
# Enable backtraces for easier debugging
|
||||
RUST_BACKTRACE: 1
|
||||
# For the run-make tests.
|
||||
LLVM_BIN_DIR: /usr/bin
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
@ -48,7 +50,7 @@ jobs:
|
|||
|
||||
- name: Install packages
|
||||
# `llvm-14-tools` is needed to install the `FileCheck` binary which is used for asm tests.
|
||||
run: sudo apt-get install ninja-build ripgrep llvm-14-tools
|
||||
run: sudo apt-get install ninja-build ripgrep llvm-14-tools llvm
|
||||
|
||||
- name: Install rustfmt & clippy
|
||||
run: rustup component add rustfmt clippy
|
||||
|
|
@ -61,11 +63,15 @@ jobs:
|
|||
sudo dpkg --force-overwrite -i ${{ matrix.libgccjit_version.gcc }}
|
||||
echo 'gcc-path = "/usr/lib/"' > config.toml
|
||||
|
||||
# Some run-make tests fail if we use our forked GCC because it doesn't
|
||||
# bundle libstdc++, so we switch to gcc-14 to have a GCC that has
|
||||
# libstdc++.
|
||||
- name: Set default GCC to gcc-14
|
||||
run: sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-14 30
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
#- name: Cache rust repository
|
||||
## We only clone the rust repository for rustc tests
|
||||
|
|
@ -76,12 +82,22 @@ jobs:
|
|||
#path: rust
|
||||
#key: ${{ runner.os }}-packages-${{ hashFiles('rust/.git/HEAD') }}
|
||||
|
||||
- name: Prepare
|
||||
run: ./y.sh prepare --only-libcore
|
||||
|
||||
- name: Check formatting
|
||||
run: ./y.sh fmt --check
|
||||
|
||||
- name: clippy
|
||||
run: |
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
cargo clippy --all-targets --no-default-features -- -D warnings
|
||||
cargo clippy --manifest-path build_system/Cargo.toml --all-targets -- -D warnings
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
./y.sh build --sysroot
|
||||
./y.sh test --mini-tests
|
||||
cargo test
|
||||
./y.sh test --cargo-tests
|
||||
|
||||
- name: Run y.sh cargo build
|
||||
run: |
|
||||
|
|
@ -101,20 +117,19 @@ jobs:
|
|||
run: |
|
||||
./y.sh test --release --clean --build-sysroot ${{ matrix.commands }}
|
||||
|
||||
- name: Check formatting
|
||||
run: ./y.sh fmt --check
|
||||
|
||||
- name: clippy
|
||||
run: |
|
||||
cargo clippy --all-targets -- -D warnings
|
||||
cargo clippy --all-targets --features master -- -D warnings
|
||||
|
||||
duplicates:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: python tools/check_intrinsics_duplicates.py
|
||||
|
||||
spell_check:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: crate-ci/typos@v1.32.0
|
||||
- uses: streetsidesoftware/cspell-action@v7
|
||||
|
||||
build_system:
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@ jobs:
|
|||
run: |
|
||||
sudo dpkg --force-overwrite -i gcc-15.deb
|
||||
echo 'gcc-path = "/usr/lib"' > config.toml
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
|
|
|
|||
|
|
@ -65,8 +65,8 @@ jobs:
|
|||
- name: Set env
|
||||
run: |
|
||||
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
|
||||
|
||||
#- name: Cache rust repository
|
||||
## We only clone the rust repository for rustc tests
|
||||
|
|
@ -95,7 +95,7 @@ jobs:
|
|||
./y.sh prepare --only-libcore --cross
|
||||
./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu
|
||||
./y.sh test --mini-tests
|
||||
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test
|
||||
CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu ./y.sh test --cargo-tests
|
||||
./y.sh clean all
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ permissions:
|
|||
env:
|
||||
# Enable backtraces for easier debugging
|
||||
RUST_BACKTRACE: 1
|
||||
# For the run-make tests.
|
||||
LLVM_BIN_DIR: /usr/bin
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
@ -36,7 +38,8 @@ jobs:
|
|||
uses: Swatinem/rust-cache@v2
|
||||
|
||||
- name: Install packages
|
||||
run: sudo apt-get install ninja-build ripgrep
|
||||
# `llvm-14-tools` is needed to install the `FileCheck` binary which is used for run-make tests.
|
||||
run: sudo apt-get install ninja-build ripgrep llvm-14-tools llvm
|
||||
|
||||
- name: Download artifact
|
||||
run: curl -LO https://github.com/rust-lang/gcc/releases/latest/download/gcc-15.deb
|
||||
|
|
@ -46,18 +49,21 @@ jobs:
|
|||
sudo dpkg --force-overwrite -i gcc-15.deb
|
||||
echo 'gcc-path = "/usr/lib/"' > config.toml
|
||||
|
||||
# Some run-make tests fail if we use our forked GCC because it doesn't
|
||||
# bundle libstdc++, so we switch to gcc-14 to have a GCC that has
|
||||
# libstdc++.
|
||||
- name: Set default GCC to gcc-14
|
||||
run: sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-14 30
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "workspace="$GITHUB_WORKSPACE >> $GITHUB_ENV
|
||||
echo "LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
echo "LD_LIBRARY_PATH=/usr/lib" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
./y.sh prepare --only-libcore
|
||||
EMBED_LTO_BITCODE=1 ./y.sh build --sysroot --release --release-sysroot
|
||||
./y.sh test --mini-tests
|
||||
cargo test
|
||||
./y.sh test --cargo-tests
|
||||
./y.sh clean all
|
||||
|
||||
- name: Prepare dependencies
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ jobs:
|
|||
if: ${{ !matrix.cargo_runner }}
|
||||
run: |
|
||||
./y.sh test --release --clean --release-sysroot --build-sysroot --mini-tests --std-tests --test-libcore
|
||||
cargo test
|
||||
./y.sh test --cargo-tests
|
||||
|
||||
- name: Run stdarch tests
|
||||
if: ${{ !matrix.cargo_runner }}
|
||||
|
|
|
|||
3
compiler/rustc_codegen_gcc/.gitignore
vendored
3
compiler/rustc_codegen_gcc/.gitignore
vendored
|
|
@ -19,4 +19,5 @@ tools/llvmint-2
|
|||
llvm
|
||||
build_system/target
|
||||
config.toml
|
||||
build
|
||||
build
|
||||
rustlantis
|
||||
|
|
@ -33,7 +33,7 @@ To run specific tests, use appropriate flags such as:
|
|||
|
||||
- `./y.sh test --test-libcore`
|
||||
- `./y.sh test --std-tests`
|
||||
- `cargo test -- <name of test>`
|
||||
- `./y.sh test --cargo-tests -- <name of test>`
|
||||
|
||||
Additionally, you can run the tests of `libgccjit`:
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,18 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
|
|
@ -111,9 +123,9 @@ checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
|||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
|
|
@ -137,6 +149,12 @@ version = "1.20.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.8.4"
|
||||
|
|
@ -166,9 +184,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.42"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
|
|
@ -188,12 +206,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.14.0"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys",
|
||||
|
|
@ -242,6 +260,15 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
@ -345,3 +372,12 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ gccjit = "2.7"
|
|||
[dev-dependencies]
|
||||
boml = "0.3.1"
|
||||
lang_tester = "0.8.0"
|
||||
tempfile = "3.7.1"
|
||||
tempfile = "3.20"
|
||||
|
||||
[profile.dev]
|
||||
# By compiling dependencies with optimizations, performing tests gets much faster.
|
||||
|
|
|
|||
9
compiler/rustc_codegen_gcc/_typos.toml
Normal file
9
compiler/rustc_codegen_gcc/_typos.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
[default.extend-words]
|
||||
ba = "ba"
|
||||
hsa = "hsa"
|
||||
olt = "olt"
|
||||
seh = "seh"
|
||||
typ = "typ"
|
||||
|
||||
[files]
|
||||
extend-exclude = ["src/intrinsic/archs.rs"]
|
||||
|
|
@ -1,24 +1,24 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.22.0"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli 0.29.0",
|
||||
"gimli",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
name = "adler2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -33,10 +33,21 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.18"
|
||||
name = "alloctests"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||
checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
|
@ -50,10 +61,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "compiler_builtins"
|
||||
version = "0.1.118"
|
||||
version = "0.1.160"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5"
|
||||
checksum = "6376049cfa92c0aa8b9ac95fae22184b981c658208d4ed8a1dc553cd83612895"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
|
|
@ -61,11 +73,19 @@ dependencies = [
|
|||
name = "core"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "coretests"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dlmalloc"
|
||||
version = "0.2.6"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3264b043b8e977326c1ee9e723da2c1f8d09a99df52cacf00b4dbce5ac54414d"
|
||||
checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
|
|
@ -97,20 +117,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.30.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9"
|
||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
|
|
@ -119,11 +128,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -131,9 +139,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
|
|
@ -142,9 +150,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -161,11 +169,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.4"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"adler2",
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -173,9 +181,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.3"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"memchr",
|
||||
|
|
@ -188,7 +196,6 @@ name = "panic_abort"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc",
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"libc",
|
||||
|
|
@ -211,14 +218,22 @@ name = "proc_macro"
|
|||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"core",
|
||||
"rustc-literal-escaper",
|
||||
"std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "profiler_builtins"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "4.5.0"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -226,15 +241,39 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "r-efi-alloc"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31d6f09fe2b6ad044bc3d2c34ce4979796581afd2f1ebc185837e02421e02fd7"
|
||||
checksum = "e43c53ff1a01d423d1cb762fd991de07d32965ff0ca2e4f80444ac7804198203"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"r-efi",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
|
||||
[[package]]
|
||||
name = "rand_xorshift"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
|
|
@ -245,6 +284,15 @@ dependencies = [
|
|||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-literal-escaper"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
|
||||
dependencies = [
|
||||
"rustc-std-workspace-std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-std-workspace-alloc"
|
||||
version = "1.99.0"
|
||||
|
|
@ -266,6 +314,12 @@ dependencies = [
|
|||
"std",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "std"
|
||||
version = "0.0.0"
|
||||
|
|
@ -286,10 +340,13 @@ dependencies = [
|
|||
"panic_unwind",
|
||||
"r-efi",
|
||||
"r-efi-alloc",
|
||||
"rand",
|
||||
"rand_xorshift",
|
||||
"rustc-demangle",
|
||||
"std_detect",
|
||||
"unwind",
|
||||
"wasi",
|
||||
"windows-targets 0.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -298,6 +355,7 @@ version = "0.1.5"
|
|||
dependencies = [
|
||||
"cfg-if",
|
||||
"compiler_builtins",
|
||||
"libc",
|
||||
"rustc-std-workspace-alloc",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
|
@ -306,10 +364,8 @@ dependencies = [
|
|||
name = "sysroot"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"alloc",
|
||||
"compiler_builtins",
|
||||
"core",
|
||||
"proc_macro",
|
||||
"profiler_builtins",
|
||||
"std",
|
||||
"test",
|
||||
]
|
||||
|
|
@ -326,9 +382,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"rustc-std-workspace-core",
|
||||
|
|
@ -348,12 +404,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "unwinding"
|
||||
version = "0.2.2"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882"
|
||||
checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345"
|
||||
dependencies = [
|
||||
"compiler_builtins",
|
||||
"gimli 0.30.0",
|
||||
"gimli",
|
||||
"rustc-std-workspace-core",
|
||||
]
|
||||
|
||||
|
|
@ -370,13 +426,17 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ impl BuildArg {
|
|||
}
|
||||
arg => {
|
||||
if !build_arg.config_info.parse_argument(arg, &mut args)? {
|
||||
return Err(format!("Unknown argument `{}`", arg));
|
||||
return Err(format!("Unknown argument `{arg}`"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -105,14 +105,14 @@ pub fn create_build_sysroot_content(start_dir: &Path) -> Result<(), String> {
|
|||
if !start_dir.is_dir() {
|
||||
create_dir(start_dir)?;
|
||||
}
|
||||
copy_file("build_system/build_sysroot/Cargo.toml", &start_dir.join("Cargo.toml"))?;
|
||||
copy_file("build_system/build_sysroot/Cargo.lock", &start_dir.join("Cargo.lock"))?;
|
||||
copy_file("build_system/build_sysroot/Cargo.toml", start_dir.join("Cargo.toml"))?;
|
||||
copy_file("build_system/build_sysroot/Cargo.lock", start_dir.join("Cargo.lock"))?;
|
||||
|
||||
let src_dir = start_dir.join("src");
|
||||
if !src_dir.is_dir() {
|
||||
create_dir(&src_dir)?;
|
||||
}
|
||||
copy_file("build_system/build_sysroot/lib.rs", &start_dir.join("src/lib.rs"))
|
||||
copy_file("build_system/build_sysroot/lib.rs", start_dir.join("src/lib.rs"))
|
||||
}
|
||||
|
||||
pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Result<(), String> {
|
||||
|
|
@ -169,7 +169,7 @@ pub fn build_sysroot(env: &HashMap<String, String>, config: &ConfigInfo) -> Resu
|
|||
run_command(&[&"cp", &"-r", &dir_to_copy, &sysroot_path], None).map(|_| ())
|
||||
};
|
||||
walk_dir(
|
||||
start_dir.join(&format!("target/{}/{}/deps", config.target_triple, channel)),
|
||||
start_dir.join(format!("target/{}/{}/deps", config.target_triple, channel)),
|
||||
&mut copier.clone(),
|
||||
&mut copier,
|
||||
false,
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ enum CleanArg {
|
|||
impl CleanArg {
|
||||
fn new() -> Result<Self, String> {
|
||||
// We skip the binary and the "clean" option.
|
||||
for arg in std::env::args().skip(2) {
|
||||
if let Some(arg) = std::env::args().nth(2) {
|
||||
return match arg.as_str() {
|
||||
"all" => Ok(Self::All),
|
||||
"ui-tests" => Ok(Self::UiTests),
|
||||
"--help" => Ok(Self::Help),
|
||||
a => Err(format!("Unknown argument `{}`", a)),
|
||||
a => Err(format!("Unknown argument `{a}`")),
|
||||
};
|
||||
}
|
||||
Ok(Self::default())
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl Args {
|
|||
}
|
||||
arg => {
|
||||
if !command_args.config_info.parse_argument(arg, &mut args)? {
|
||||
return Err(format!("Unknown option {}", arg));
|
||||
return Err(format!("Unknown option {arg}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ impl Args {
|
|||
Some(p) => p.into(),
|
||||
None => PathBuf::from("./gcc"),
|
||||
};
|
||||
return Ok(Some(command_args));
|
||||
Ok(Some(command_args))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ pub fn run() -> Result<(), String> {
|
|||
let result = git_clone("https://github.com/rust-lang/gcc", Some(&args.out_path), false)?;
|
||||
if result.ran_clone {
|
||||
let gcc_commit = args.config_info.get_gcc_commit()?;
|
||||
println!("Checking out GCC commit `{}`...", gcc_commit);
|
||||
println!("Checking out GCC commit `{gcc_commit}`...");
|
||||
run_command_with_output(
|
||||
&[&"git", &"checkout", &gcc_commit],
|
||||
Some(Path::new(&result.repo_dir)),
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl ConfigFile {
|
|||
"Expected a boolean for `download-gccjit`",
|
||||
);
|
||||
}
|
||||
_ => return failed_config_parsing(config_file, &format!("Unknown key `{}`", key)),
|
||||
_ => return failed_config_parsing(config_file, &format!("Unknown key `{key}`")),
|
||||
}
|
||||
}
|
||||
match (config.gcc_path.as_mut(), config.download_gccjit) {
|
||||
|
|
@ -86,9 +86,7 @@ impl ConfigFile {
|
|||
let path = Path::new(gcc_path);
|
||||
*gcc_path = path
|
||||
.canonicalize()
|
||||
.map_err(|err| {
|
||||
format!("Failed to get absolute path of `{}`: {:?}", gcc_path, err)
|
||||
})?
|
||||
.map_err(|err| format!("Failed to get absolute path of `{gcc_path}`: {err:?}"))?
|
||||
.display()
|
||||
.to_string();
|
||||
}
|
||||
|
|
@ -175,7 +173,7 @@ impl ConfigInfo {
|
|||
"--sysroot-panic-abort" => self.sysroot_panic_abort = true,
|
||||
"--gcc-path" => match args.next() {
|
||||
Some(arg) if !arg.is_empty() => {
|
||||
self.gcc_path = Some(arg.into());
|
||||
self.gcc_path = Some(arg);
|
||||
}
|
||||
_ => {
|
||||
return Err("Expected a value after `--gcc-path`, found nothing".to_string());
|
||||
|
|
@ -244,7 +242,7 @@ impl ConfigInfo {
|
|||
let libgccjit_so = output_dir.join(libgccjit_so_name);
|
||||
if !libgccjit_so.is_file() && !self.no_download {
|
||||
// Download time!
|
||||
let tempfile_name = format!("{}.download", libgccjit_so_name);
|
||||
let tempfile_name = format!("{libgccjit_so_name}.download");
|
||||
let tempfile = output_dir.join(&tempfile_name);
|
||||
let is_in_ci = std::env::var("GITHUB_ACTIONS").is_ok();
|
||||
|
||||
|
|
@ -262,14 +260,14 @@ impl ConfigInfo {
|
|||
)
|
||||
})?;
|
||||
|
||||
println!("Downloaded libgccjit.so version {} successfully!", commit);
|
||||
println!("Downloaded libgccjit.so version {commit} successfully!");
|
||||
// We need to create a link named `libgccjit.so.0` because that's what the linker is
|
||||
// looking for.
|
||||
create_symlink(&libgccjit_so, output_dir.join(&format!("{}.0", libgccjit_so_name)))?;
|
||||
create_symlink(&libgccjit_so, output_dir.join(format!("{libgccjit_so_name}.0")))?;
|
||||
}
|
||||
|
||||
let gcc_path = output_dir.display().to_string();
|
||||
println!("Using `{}` as path for libgccjit", gcc_path);
|
||||
println!("Using `{gcc_path}` as path for libgccjit");
|
||||
self.gcc_path = Some(gcc_path);
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -286,8 +284,7 @@ impl ConfigInfo {
|
|||
// since we already have everything we need.
|
||||
if let Some(gcc_path) = &self.gcc_path {
|
||||
println!(
|
||||
"`--gcc-path` was provided, ignoring config file. Using `{}` as path for libgccjit",
|
||||
gcc_path
|
||||
"`--gcc-path` was provided, ignoring config file. Using `{gcc_path}` as path for libgccjit"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
|
@ -343,7 +340,7 @@ impl ConfigInfo {
|
|||
self.dylib_ext = match os_name.as_str() {
|
||||
"Linux" => "so",
|
||||
"Darwin" => "dylib",
|
||||
os => return Err(format!("unsupported OS `{}`", os)),
|
||||
os => return Err(format!("unsupported OS `{os}`")),
|
||||
}
|
||||
.to_string();
|
||||
let rustc = match env.get("RUSTC") {
|
||||
|
|
@ -355,10 +352,10 @@ impl ConfigInfo {
|
|||
None => return Err("no host found".to_string()),
|
||||
};
|
||||
|
||||
if self.target_triple.is_empty() {
|
||||
if let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE") {
|
||||
self.target_triple = overwrite.clone();
|
||||
}
|
||||
if self.target_triple.is_empty()
|
||||
&& let Some(overwrite) = env.get("OVERWRITE_TARGET_TRIPLE")
|
||||
{
|
||||
self.target_triple = overwrite.clone();
|
||||
}
|
||||
if self.target_triple.is_empty() {
|
||||
self.target_triple = self.host_triple.clone();
|
||||
|
|
@ -378,7 +375,7 @@ impl ConfigInfo {
|
|||
}
|
||||
|
||||
let current_dir =
|
||||
std_env::current_dir().map_err(|error| format!("`current_dir` failed: {:?}", error))?;
|
||||
std_env::current_dir().map_err(|error| format!("`current_dir` failed: {error:?}"))?;
|
||||
let channel = if self.channel == Channel::Release {
|
||||
"release"
|
||||
} else if let Some(channel) = env.get("CHANNEL") {
|
||||
|
|
@ -391,15 +388,15 @@ impl ConfigInfo {
|
|||
self.cg_backend_path = current_dir
|
||||
.join("target")
|
||||
.join(channel)
|
||||
.join(&format!("librustc_codegen_gcc.{}", self.dylib_ext))
|
||||
.join(format!("librustc_codegen_gcc.{}", self.dylib_ext))
|
||||
.display()
|
||||
.to_string();
|
||||
self.sysroot_path =
|
||||
current_dir.join(&get_sysroot_dir()).join("sysroot").display().to_string();
|
||||
current_dir.join(get_sysroot_dir()).join("sysroot").display().to_string();
|
||||
if let Some(backend) = &self.backend {
|
||||
// This option is only used in the rust compiler testsuite. The sysroot is handled
|
||||
// by its build system directly so no need to set it ourselves.
|
||||
rustflags.push(format!("-Zcodegen-backend={}", backend));
|
||||
rustflags.push(format!("-Zcodegen-backend={backend}"));
|
||||
} else {
|
||||
rustflags.extend_from_slice(&[
|
||||
"--sysroot".to_string(),
|
||||
|
|
@ -412,10 +409,10 @@ impl ConfigInfo {
|
|||
// We have a different environment variable than RUSTFLAGS to make sure those flags are
|
||||
// only sent to rustc_codegen_gcc and not the LLVM backend.
|
||||
if let Some(cg_rustflags) = env.get("CG_RUSTFLAGS") {
|
||||
rustflags.extend_from_slice(&split_args(&cg_rustflags)?);
|
||||
rustflags.extend_from_slice(&split_args(cg_rustflags)?);
|
||||
}
|
||||
if let Some(test_flags) = env.get("TEST_FLAGS") {
|
||||
rustflags.extend_from_slice(&split_args(&test_flags)?);
|
||||
rustflags.extend_from_slice(&split_args(test_flags)?);
|
||||
}
|
||||
|
||||
if let Some(linker) = linker {
|
||||
|
|
@ -438,8 +435,8 @@ impl ConfigInfo {
|
|||
env.insert("RUSTC_LOG".to_string(), "warn".to_string());
|
||||
|
||||
let sysroot = current_dir
|
||||
.join(&get_sysroot_dir())
|
||||
.join(&format!("sysroot/lib/rustlib/{}/lib", self.target_triple));
|
||||
.join(get_sysroot_dir())
|
||||
.join(format!("sysroot/lib/rustlib/{}/lib", self.target_triple));
|
||||
let ld_library_path = format!(
|
||||
"{target}:{sysroot}:{gcc_path}",
|
||||
target = self.cargo_target_dir,
|
||||
|
|
@ -505,7 +502,7 @@ fn download_gccjit(
|
|||
with_progress_bar: bool,
|
||||
) -> Result<(), String> {
|
||||
let url = if std::env::consts::OS == "linux" && std::env::consts::ARCH == "x86_64" {
|
||||
format!("https://github.com/rust-lang/gcc/releases/download/master-{}/libgccjit.so", commit)
|
||||
format!("https://github.com/rust-lang/gcc/releases/download/master-{commit}/libgccjit.so")
|
||||
} else {
|
||||
eprintln!(
|
||||
"\
|
||||
|
|
@ -518,7 +515,7 @@ to `download-gccjit = false` and set `gcc-path` to the appropriate directory."
|
|||
));
|
||||
};
|
||||
|
||||
println!("Downloading `{}`...", url);
|
||||
println!("Downloading `{url}`...");
|
||||
|
||||
// Try curl. If that fails and we are on windows, fallback to PowerShell.
|
||||
let mut ret = run_command_with_output(
|
||||
|
|
@ -538,7 +535,7 @@ to `download-gccjit = false` and set `gcc-path` to the appropriate directory."
|
|||
if with_progress_bar { &"--progress-bar" } else { &"-s" },
|
||||
&url.as_str(),
|
||||
],
|
||||
Some(&output_dir),
|
||||
Some(output_dir),
|
||||
);
|
||||
if ret.is_err() && cfg!(windows) {
|
||||
eprintln!("Fallback to PowerShell");
|
||||
|
|
@ -549,12 +546,11 @@ to `download-gccjit = false` and set `gcc-path` to the appropriate directory."
|
|||
&"-Command",
|
||||
&"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
|
||||
&format!(
|
||||
"(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
|
||||
url, tempfile_name,
|
||||
"(New-Object System.Net.WebClient).DownloadFile('{url}', '{tempfile_name}')",
|
||||
)
|
||||
.as_str(),
|
||||
],
|
||||
Some(&output_dir),
|
||||
Some(output_dir),
|
||||
);
|
||||
}
|
||||
ret
|
||||
|
|
|
|||
|
|
@ -16,21 +16,21 @@ fn show_usage() {
|
|||
pub fn run() -> Result<(), String> {
|
||||
let mut check = false;
|
||||
// We skip binary name and the `info` command.
|
||||
let mut args = std::env::args().skip(2);
|
||||
while let Some(arg) = args.next() {
|
||||
let args = std::env::args().skip(2);
|
||||
for arg in args {
|
||||
match arg.as_str() {
|
||||
"--help" => {
|
||||
show_usage();
|
||||
return Ok(());
|
||||
}
|
||||
"--check" => check = true,
|
||||
_ => return Err(format!("Unknown option {}", arg)),
|
||||
_ => return Err(format!("Unknown option {arg}")),
|
||||
}
|
||||
}
|
||||
|
||||
let cmd: &[&dyn AsRef<OsStr>] =
|
||||
if check { &[&"cargo", &"fmt", &"--check"] } else { &[&"cargo", &"fmt"] };
|
||||
|
||||
run_command_with_output(cmd, Some(&Path::new(".")))?;
|
||||
run_command_with_output(cmd, Some(&Path::new("build_system")))
|
||||
run_command_with_output(cmd, Some(Path::new(".")))?;
|
||||
run_command_with_output(cmd, Some(Path::new("build_system")))
|
||||
}
|
||||
|
|
|
|||
289
compiler/rustc_codegen_gcc/build_system/src/fuzz.rs
Normal file
289
compiler/rustc_codegen_gcc/build_system/src/fuzz.rs
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
|
||||
mod reduce;
|
||||
|
||||
use crate::utils::run_command_with_output;
|
||||
|
||||
fn show_usage() {
|
||||
println!(
|
||||
r#"
|
||||
`fuzz` command help:
|
||||
--reduce : Reduces a file generated by rustlantis
|
||||
--help : Show this help
|
||||
--start : Start of the fuzzed range
|
||||
--count : The number of cases to fuzz
|
||||
-j --jobs : The number of threads to use during fuzzing"#
|
||||
);
|
||||
}
|
||||
|
||||
pub fn run() -> Result<(), String> {
|
||||
// We skip binary name and the `fuzz` command.
|
||||
let mut args = std::env::args().skip(2);
|
||||
let mut start = 0;
|
||||
let mut count = 100;
|
||||
let mut threads =
|
||||
std::thread::available_parallelism().map(|threads| threads.get()).unwrap_or(1);
|
||||
while let Some(arg) = args.next() {
|
||||
match arg.as_str() {
|
||||
"--reduce" => {
|
||||
let Some(path) = args.next() else {
|
||||
return Err("--reduce must be provided with a path".into());
|
||||
};
|
||||
if !std::fs::exists(&path).unwrap_or(false) {
|
||||
return Err("--reduce must be provided with a valid path".into());
|
||||
}
|
||||
reduce::reduce(&path);
|
||||
return Ok(());
|
||||
}
|
||||
"--help" => {
|
||||
show_usage();
|
||||
return Ok(());
|
||||
}
|
||||
"--start" => {
|
||||
start =
|
||||
str::parse(&args.next().ok_or_else(|| "Fuzz start not provided!".to_string())?)
|
||||
.map_err(|err| (format!("Fuzz start not a number {err:?}!")))?;
|
||||
}
|
||||
"--count" => {
|
||||
count =
|
||||
str::parse(&args.next().ok_or_else(|| "Fuzz count not provided!".to_string())?)
|
||||
.map_err(|err| (format!("Fuzz count not a number {err:?}!")))?;
|
||||
}
|
||||
"-j" | "--jobs" => {
|
||||
threads = str::parse(
|
||||
&args.next().ok_or_else(|| "Fuzz thread count not provided!".to_string())?,
|
||||
)
|
||||
.map_err(|err| (format!("Fuzz thread count not a number {err:?}!")))?;
|
||||
}
|
||||
_ => return Err(format!("Unknown option {arg}")),
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that we have a cloned version of rustlantis on hand.
|
||||
crate::utils::git_clone(
|
||||
"https://github.com/cbeuw/rustlantis.git",
|
||||
Some("clones/rustlantis".as_ref()),
|
||||
true,
|
||||
)
|
||||
.map_err(|err| (format!("Git clone failed with message: {err:?}!")))?;
|
||||
|
||||
// Ensure that we are on the newest rustlantis commit.
|
||||
let cmd: &[&dyn AsRef<OsStr>] = &[&"git", &"pull", &"origin"];
|
||||
run_command_with_output(cmd, Some(Path::new("clones/rustlantis")))?;
|
||||
|
||||
// Build the release version of rustlantis
|
||||
let cmd: &[&dyn AsRef<OsStr>] = &[&"cargo", &"build", &"--release"];
|
||||
run_command_with_output(cmd, Some(Path::new("clones/rustlantis")))?;
|
||||
// Fuzz a given range
|
||||
fuzz_range(start, start + count, threads);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fuzzes a range `start..end` with `threads`.
|
||||
fn fuzz_range(start: u64, end: u64, threads: usize) {
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
use std::time::{Duration, Instant};
|
||||
// Total amount of files to fuzz
|
||||
let total = end - start;
|
||||
// Currently fuzzed element
|
||||
let start = Arc::new(AtomicU64::new(start));
|
||||
// Count time during fuzzing
|
||||
let start_time = Instant::now();
|
||||
let mut workers = Vec::with_capacity(threads);
|
||||
// Spawn `threads`..
|
||||
for _ in 0..threads {
|
||||
let start = start.clone();
|
||||
// .. which each will ..
|
||||
workers.push(std::thread::spawn(move || {
|
||||
// ... grab the next fuzz seed ...
|
||||
while start.load(Ordering::Relaxed) < end {
|
||||
let next = start.fetch_add(1, Ordering::Relaxed);
|
||||
// .. test that seed .
|
||||
match test(next, false) {
|
||||
Err(err) => {
|
||||
// If the test failed at compile-time...
|
||||
println!("test({next}) failed because {err:?}");
|
||||
// ... copy that file to the directory `target/fuzz/compiletime_error`...
|
||||
let mut out_path: std::path::PathBuf =
|
||||
"target/fuzz/compiletime_error".into();
|
||||
std::fs::create_dir_all(&out_path).unwrap();
|
||||
// .. into a file named `fuzz{seed}.rs`.
|
||||
out_path.push(format!("fuzz{next}.rs"));
|
||||
std::fs::copy(err, out_path).unwrap();
|
||||
}
|
||||
Ok(Err(err)) => {
|
||||
// If the test failed at run-time...
|
||||
println!("The LLVM and GCC results don't match for {err:?}");
|
||||
// ... generate a new file, which prints temporaries(instead of hashing them)...
|
||||
let mut out_path: std::path::PathBuf = "target/fuzz/runtime_error".into();
|
||||
std::fs::create_dir_all(&out_path).unwrap();
|
||||
let Ok(Err(tmp_print_err)) = test(next, true) else {
|
||||
// ... if that file does not reproduce the issue...
|
||||
// ... save the original sample in a file named `fuzz{seed}.rs`...
|
||||
out_path.push(format!("fuzz{next}.rs"));
|
||||
std::fs::copy(err, &out_path).unwrap();
|
||||
continue;
|
||||
};
|
||||
// ... if that new file still produces the issue, copy it to `fuzz{seed}.rs`..
|
||||
out_path.push(format!("fuzz{next}.rs"));
|
||||
std::fs::copy(tmp_print_err, &out_path).unwrap();
|
||||
// ... and start reducing it, using some properties of `rustlantis` to speed up the process.
|
||||
reduce::reduce(&out_path);
|
||||
}
|
||||
// If the test passed, do nothing
|
||||
Ok(Ok(())) => (),
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
// The "manager" thread loop.
|
||||
while start.load(Ordering::Relaxed) < end || !workers.iter().all(|t| t.is_finished()) {
|
||||
// Every 500 ms...
|
||||
let five_hundred_millis = Duration::from_millis(500);
|
||||
std::thread::sleep(five_hundred_millis);
|
||||
// ... calculate the remaining fuzz iters ...
|
||||
let remaining = end - start.load(Ordering::Relaxed);
|
||||
// ... fix the count(the start counter counts the cases that
|
||||
// begun fuzzing, and not only the ones that are done)...
|
||||
let fuzzed = (total - remaining).saturating_sub(threads as u64);
|
||||
// ... and the fuzz speed ...
|
||||
let iter_per_sec = fuzzed as f64 / start_time.elapsed().as_secs_f64();
|
||||
// .. and use them to display fuzzing stats.
|
||||
println!(
|
||||
"fuzzed {fuzzed} cases({}%), at rate {iter_per_sec} iter/s, remaining ~{}s",
|
||||
(100 * fuzzed) as f64 / total as f64,
|
||||
(remaining as f64) / iter_per_sec
|
||||
)
|
||||
}
|
||||
drop(workers);
|
||||
}
|
||||
|
||||
/// Builds & runs a file with LLVM.
|
||||
fn debug_llvm(path: &std::path::Path) -> Result<Vec<u8>, String> {
|
||||
// Build a file named `llvm_elf`...
|
||||
let exe_path = path.with_extension("llvm_elf");
|
||||
// ... using the LLVM backend ...
|
||||
let output = std::process::Command::new("rustc")
|
||||
.arg(path)
|
||||
.arg("-o")
|
||||
.arg(&exe_path)
|
||||
.output()
|
||||
.map_err(|err| format!("{err:?}"))?;
|
||||
// ... check that the compilation succeeded ...
|
||||
if !output.status.success() {
|
||||
return Err(format!("LLVM compilation failed:{output:?}"));
|
||||
}
|
||||
// ... run the resulting executable ...
|
||||
let output =
|
||||
std::process::Command::new(&exe_path).output().map_err(|err| format!("{err:?}"))?;
|
||||
// ... check it run normally ...
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"The program at {path:?}, compiled with LLVM, exited unsuccessfully:{output:?}"
|
||||
));
|
||||
}
|
||||
// ... cleanup that executable ...
|
||||
std::fs::remove_file(exe_path).map_err(|err| format!("{err:?}"))?;
|
||||
// ... and return the output(stdout + stderr - this allows UB checks to fire).
|
||||
let mut res = output.stdout;
|
||||
res.extend(output.stderr);
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
/// Builds & runs a file with GCC.
|
||||
fn release_gcc(path: &std::path::Path) -> Result<Vec<u8>, String> {
|
||||
// Build a file named `gcc_elf`...
|
||||
let exe_path = path.with_extension("gcc_elf");
|
||||
// ... using the GCC backend ...
|
||||
let output = std::process::Command::new("./y.sh")
|
||||
.arg("rustc")
|
||||
.arg(path)
|
||||
.arg("-O")
|
||||
.arg("-o")
|
||||
.arg(&exe_path)
|
||||
.output()
|
||||
.map_err(|err| format!("{err:?}"))?;
|
||||
// ... check that the compilation succeeded ...
|
||||
if !output.status.success() {
|
||||
return Err(format!("GCC compilation failed:{output:?}"));
|
||||
}
|
||||
// ... run the resulting executable ..
|
||||
let output =
|
||||
std::process::Command::new(&exe_path).output().map_err(|err| format!("{err:?}"))?;
|
||||
// ... check it run normally ...
|
||||
if !output.status.success() {
|
||||
return Err(format!(
|
||||
"The program at {path:?}, compiled with GCC, exited unsuccessfully:{output:?}"
|
||||
));
|
||||
}
|
||||
// ... cleanup that executable ...
|
||||
std::fs::remove_file(exe_path).map_err(|err| format!("{err:?}"))?;
|
||||
// ... and return the output(stdout + stderr - this allows UB checks to fire).
|
||||
let mut res = output.stdout;
|
||||
res.extend(output.stderr);
|
||||
Ok(res)
|
||||
}
|
||||
type ResultCache = Option<(Vec<u8>, Vec<u8>)>;
|
||||
/// Generates a new rustlantis file, & compares the result of running it with GCC and LLVM.
|
||||
fn test(seed: u64, print_tmp_vars: bool) -> Result<Result<(), std::path::PathBuf>, String> {
|
||||
// Generate a Rust source...
|
||||
let source_file = generate(seed, print_tmp_vars)?;
|
||||
test_file(&source_file, true)
|
||||
}
|
||||
/// Tests a file with a cached LLVM result. Used for reduction, when it is known
|
||||
/// that a given transformation should not change the execution result.
|
||||
fn test_cached(
|
||||
source_file: &Path,
|
||||
remove_tmps: bool,
|
||||
cache: &mut ResultCache,
|
||||
) -> Result<Result<(), std::path::PathBuf>, String> {
|
||||
// Test `source_file` with release GCC ...
|
||||
let gcc_res = release_gcc(source_file)?;
|
||||
if cache.is_none() {
|
||||
// ...test `source_file` with debug LLVM ...
|
||||
*cache = Some((debug_llvm(source_file)?, gcc_res.clone()));
|
||||
}
|
||||
let (llvm_res, old_gcc) = cache.as_ref().unwrap();
|
||||
// ... compare the results ...
|
||||
if *llvm_res != gcc_res && gcc_res == *old_gcc {
|
||||
// .. if they don't match, report an error.
|
||||
Ok(Err(source_file.to_path_buf()))
|
||||
} else {
|
||||
if remove_tmps {
|
||||
std::fs::remove_file(source_file).map_err(|err| format!("{err:?}"))?;
|
||||
}
|
||||
Ok(Ok(()))
|
||||
}
|
||||
}
|
||||
fn test_file(
|
||||
source_file: &Path,
|
||||
remove_tmps: bool,
|
||||
) -> Result<Result<(), std::path::PathBuf>, String> {
|
||||
let mut uncached = None;
|
||||
test_cached(source_file, remove_tmps, &mut uncached)
|
||||
}
|
||||
|
||||
/// Generates a new rustlantis file for us to run tests on.
|
||||
fn generate(seed: u64, print_tmp_vars: bool) -> Result<std::path::PathBuf, String> {
|
||||
use std::io::Write;
|
||||
let mut out_path = std::env::temp_dir();
|
||||
out_path.push(format!("fuzz{seed}.rs"));
|
||||
// We need to get the command output here.
|
||||
let mut generate = std::process::Command::new("cargo");
|
||||
generate
|
||||
.args(["run", "--release", "--bin", "generate"])
|
||||
.arg(format!("{seed}"))
|
||||
.current_dir("clones/rustlantis");
|
||||
if print_tmp_vars {
|
||||
generate.arg("--debug");
|
||||
}
|
||||
let out = generate.output().map_err(|err| format!("{err:?}"))?;
|
||||
// Stuff the rustlantis output in a source file.
|
||||
std::fs::File::create(&out_path)
|
||||
.map_err(|err| format!("{err:?}"))?
|
||||
.write_all(&out.stdout)
|
||||
.map_err(|err| format!("{err:?}"))?;
|
||||
Ok(out_path)
|
||||
}
|
||||
432
compiler/rustc_codegen_gcc/build_system/src/fuzz/reduce.rs
Normal file
432
compiler/rustc_codegen_gcc/build_system/src/fuzz/reduce.rs
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::ResultCache;
|
||||
|
||||
/// Saves a reduced file for a given `stage`
|
||||
fn save_reduction(lines: &[String], path: &Path, stage: &str) {
|
||||
let mut path = path.to_path_buf();
|
||||
path.set_extension(format!("rs.{stage}"));
|
||||
let mut file = std::fs::File::create(&path).expect("Could not create the reduced example file");
|
||||
for line in lines {
|
||||
file.write_all(line.as_bytes()).expect("Could not save the reduced example");
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if a given reduction is valid.
|
||||
fn test_reduction(lines: &[String], path: &Path, cache: &mut ResultCache) -> bool {
|
||||
let mut path = path.to_path_buf();
|
||||
path.set_extension("rs_reduced");
|
||||
let mut file = std::fs::File::create(&path).expect("Could not create the reduced example file");
|
||||
for line in lines {
|
||||
file.write_all(line.as_bytes()).expect("Could not save the reduced example");
|
||||
}
|
||||
let res = super::test_cached(&path, false, cache);
|
||||
let Ok(Err(_)) = res else {
|
||||
return false;
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
/// Removes duplicate assignments in bulk.
|
||||
/// If a line A = B is followed directly by A = C,
|
||||
/// then removing the first line ought to be fully sound,
|
||||
/// and not change the behaviour of the program at all. Detect & remove such lines.
|
||||
fn remove_dup_assign(
|
||||
file: &mut Vec<String>,
|
||||
path: &PathBuf,
|
||||
starts: usize,
|
||||
ends: usize,
|
||||
cache: &mut ResultCache,
|
||||
) {
|
||||
let mut file_copy = file.clone();
|
||||
let mut reduction_count = 0;
|
||||
// Not worth it.
|
||||
if ends - starts < 8 {
|
||||
return;
|
||||
}
|
||||
for index in starts..ends {
|
||||
let Some((prefix, _)) = file_copy[index].split_once('=') else {
|
||||
continue;
|
||||
};
|
||||
let Some((prefix2, postifx2)) = file_copy[index + 1].split_once('=') else {
|
||||
continue;
|
||||
};
|
||||
let prefix = prefix.trim();
|
||||
let prefix2 = prefix2.trim();
|
||||
// FIXME: Right now, remove_dup_assign cares about assignments to the exact same place.
|
||||
// However, given an assigemnt like this:
|
||||
// ```
|
||||
// A.0 = 1_u32;
|
||||
// A = (2_u32, 3.0);
|
||||
// ```
|
||||
// The first assignment could be safely omitted.
|
||||
// Additionally, we try to check if the second assignment could depend on the first one.
|
||||
// In such cases, the result is likely to change, so we bail.
|
||||
if prefix == prefix2 && !postifx2.contains(prefix) {
|
||||
file_copy[index] = "".into();
|
||||
reduction_count += 1;
|
||||
}
|
||||
}
|
||||
// We have removed no lines - no point in testing.
|
||||
if reduction_count == 0 {
|
||||
return;
|
||||
}
|
||||
// Check if the removed lines affected the execution result in any way, shape or form.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {reduction_count} lines `remove_dup_assign`");
|
||||
*file = file_copy;
|
||||
} else {
|
||||
// The execution result changed.
|
||||
// This can occur if the second assignment depended on the first one.
|
||||
// Eg.
|
||||
// ```
|
||||
// a = b + c;
|
||||
// a = a + d;
|
||||
// ```
|
||||
remove_dup_assign(file, path, starts, (starts + ends) / 2, cache);
|
||||
remove_dup_assign(file, path, (starts + ends) / 2, ends, cache);
|
||||
}
|
||||
save_reduction(file, path, "remove_dup_assign");
|
||||
}
|
||||
|
||||
/// Removes all the unneeded calls to `dump_var`. This is not something tools like `cvise` can do,
|
||||
/// but it greately speeds up MIR interpretation + native execution.
|
||||
fn remove_dump_var(file: &mut Vec<String>, path: &PathBuf) {
|
||||
let mut curr = 0;
|
||||
// ... try disabling `dump_vars` one by one, until only the necessary ones are left.
|
||||
while curr < file.len() {
|
||||
let Some(line) = file[curr..].iter().position(|line| line.contains("dump_var")) else {
|
||||
// No more `dump_var`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
// Make the line absolute again.
|
||||
let line = line + curr;
|
||||
let mut file_copy = file.clone();
|
||||
// Try removing 3 consecutive lines(the call, block end and block beginning). This effectively removes a `dump_var`.
|
||||
file_copy.remove(line);
|
||||
file_copy.remove(line);
|
||||
file_copy.remove(line);
|
||||
// Not cached - the execution result can change.
|
||||
let mut uncached = None;
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, &mut uncached) {
|
||||
println!("Reduced {path:?} by 3 lines `remove_dump_var`");
|
||||
*file = file_copy;
|
||||
curr = line;
|
||||
} else {
|
||||
curr = line + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_dump_var");
|
||||
}
|
||||
|
||||
/// Replaces matches with gotos where possible.
|
||||
/// This exploits some properties of rustlantis(match arm order),
|
||||
/// and is only soundly applicable to MIR generated by it.
|
||||
/// Still, it is not something `cvise` can do, but it simplifies the code a ton.
|
||||
fn match_to_goto(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
while curr < file.len() {
|
||||
let Some(match_starts) = file[curr..].iter().position(|line| line.contains("match")) else {
|
||||
// No more `match`es to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let match_starts = match_starts + curr;
|
||||
// Find the end of the match
|
||||
let Some(match_ends) = file[match_starts..].iter().position(|line| line.contains('}'))
|
||||
else {
|
||||
// Can't find match end - exit early.
|
||||
break;
|
||||
};
|
||||
let match_ends = match_ends + match_starts;
|
||||
let match_body = &file[match_starts..match_ends];
|
||||
|
||||
// Find where this match should normally jump to.
|
||||
// This *should* be the second-last arm of the match, as per the paper(the remaining blocks are decoys).
|
||||
// If this ever changes, this reduction may not always be sound.
|
||||
// This is not a problem, however: we NEED to use MIRI for reduction anwyway,
|
||||
// and it will catch this issue.
|
||||
let jumps_to = &match_body[match_body.len() - 2].trim();
|
||||
let Some((_, bb_ident)) = jumps_to.split_once("bb") else {
|
||||
break;
|
||||
};
|
||||
// We now have the number of the block we jump to at runtime.
|
||||
let bb_ident = bb_ident.trim_matches(',');
|
||||
// Try replacing this match with an unconditional jump.
|
||||
let mut file_copy = file.clone();
|
||||
for _ in match_starts..(match_ends + 1) {
|
||||
file_copy.remove(match_starts);
|
||||
}
|
||||
file_copy.insert(match_starts, format!("Goto(bb{bb_ident})\n"));
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `match_to_goto`", match_ends - match_starts);
|
||||
*file = file_copy;
|
||||
curr = match_starts;
|
||||
} else {
|
||||
curr = match_ends;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "match_to_goto");
|
||||
}
|
||||
|
||||
/// At this point, we can try "killing" blocks, by replacing their bodies with calls to `abort`.
|
||||
/// This is always sound(the program aborts, so no UB can occur after the block),
|
||||
/// and allows us to safely remove *a lot* of unneeded blocks.
|
||||
fn block_abort(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
while curr < file.len() {
|
||||
let Some(block_starts) = file[curr..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to kill - exit early.
|
||||
break;
|
||||
};
|
||||
let block_starts = block_starts + curr;
|
||||
// Find the beginning of the next block to find the end of this block.
|
||||
let Some(block_ends) = file[(block_starts + 1)..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to kill - exit early.
|
||||
break;
|
||||
};
|
||||
let block_ends = block_starts + block_ends;
|
||||
let block_starts = block_starts + 1;
|
||||
let mut file_copy = file.clone();
|
||||
// Remove the block body...
|
||||
for _ in block_starts..(block_ends) {
|
||||
file_copy.remove(block_starts);
|
||||
}
|
||||
// ..and insert an unconditional call to abort.
|
||||
file_copy.insert(
|
||||
block_starts,
|
||||
"Call(tmp = core::intrinsics::abort(), ReturnTo(bb1), UnwindUnreachable())\n"
|
||||
.to_string(),
|
||||
);
|
||||
file_copy.insert(block_starts, "let tmp = ();\n".to_string());
|
||||
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `block_abort`", block_ends - block_starts - 2);
|
||||
*file = file_copy;
|
||||
curr = block_starts;
|
||||
} else {
|
||||
curr = block_ends;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "block_abort");
|
||||
}
|
||||
|
||||
/// Removes unreachable basic blocks
|
||||
fn remove_block(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
// Next, we try to outright remove blocks.
|
||||
while curr < file.len() {
|
||||
let Some(block_starts) = file[curr..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let block_starts = block_starts + curr;
|
||||
// Find the beginning of the next block to find the end of this block.
|
||||
let Some(block_ends) = file[(block_starts + 1)..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let block_ends = block_starts + block_ends + 1;
|
||||
// Large blocks are likely to be necessary.
|
||||
if block_ends - block_starts > 6 {
|
||||
curr = block_starts + 1;
|
||||
continue;
|
||||
}
|
||||
let mut file_copy = file.clone();
|
||||
file_copy.drain(block_starts..block_ends);
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `remove_blocks`", block_ends - block_starts);
|
||||
*file = file_copy;
|
||||
curr = block_starts;
|
||||
} else {
|
||||
curr = block_starts + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_block");
|
||||
}
|
||||
|
||||
/// Merges blocks ending with unconditional jumps.
|
||||
fn linearize_cf(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
// Next, we try to linearize the control flow. What the does that mean?
|
||||
// Given a sequence like this:
|
||||
// Goto(bb22)
|
||||
// }
|
||||
// bb22 = {
|
||||
// We remove those 3 lines, merging the blocks together. This is not something `cvise` can do,
|
||||
// and it makes other transformations easier.
|
||||
while curr < file.len() {
|
||||
let Some(block_starts) = file[curr..]
|
||||
.iter()
|
||||
.position(|line| line.starts_with("bb") && line.trim_end().ends_with(" = {"))
|
||||
else {
|
||||
// No more `block`s to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let block_starts = block_starts + curr;
|
||||
// Extract the block id.
|
||||
let Some((block, _)) = file[block_starts].split_once('=') else {
|
||||
curr = block_starts + 1;
|
||||
continue;
|
||||
};
|
||||
let block = block.trim();
|
||||
if file[block_starts - 2].trim() != format!("Goto({block})") {
|
||||
curr = block_starts + 1;
|
||||
continue;
|
||||
}
|
||||
let mut file_copy = file.clone();
|
||||
// Try removing 3 consecutive lines(the goto, block end and block beginning). This effectively removes a `Goto(next)`.
|
||||
file_copy.remove(block_starts - 2);
|
||||
file_copy.remove(block_starts - 2);
|
||||
file_copy.remove(block_starts - 2);
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by 3 lines `linearize_cf`");
|
||||
*file = file_copy;
|
||||
curr = block_starts;
|
||||
} else {
|
||||
curr = block_starts + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "linearize_cf");
|
||||
}
|
||||
|
||||
/// Replaces a call to a given function with a 0 assignment to the destination place, and a Goto.
|
||||
/// This is always sound, because:
|
||||
/// 1. All the functions arguments are always initialized
|
||||
/// 2. and point to initialized memory(the operand of &raw must be an initialized place in rustlantis).
|
||||
fn remove_fn_calls(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
while curr < file.len() {
|
||||
let Some(fn_call) =
|
||||
file[curr..].iter().position(|line| line.contains("Call(") && line.contains(" = fn"))
|
||||
else {
|
||||
// No more calls to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let fn_call = fn_call + curr;
|
||||
let line = file[fn_call].trim();
|
||||
// Skip the Call(
|
||||
let line = &line["Call(".len()..];
|
||||
// Extract the destination place
|
||||
let Some((place, line)) = line.split_once('=') else {
|
||||
curr = fn_call + 1;
|
||||
continue;
|
||||
};
|
||||
// Skip till the return block id.
|
||||
let Some((_, line)) = line.split_once("ReturnTo(") else {
|
||||
curr = fn_call + 1;
|
||||
continue;
|
||||
};
|
||||
// Extract the full return block
|
||||
let Some((block, _)) = line.split_once(')') else {
|
||||
curr = fn_call + 1;
|
||||
continue;
|
||||
};
|
||||
let mut file_copy = file.clone();
|
||||
// Remove the call.
|
||||
file_copy.remove(fn_call);
|
||||
file_copy.insert(fn_call, format!("Goto({block})\n"));
|
||||
file_copy.insert(fn_call, format!("{place} = 0;\n"));
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} using `remove_fn_calls` {cache:?}");
|
||||
*file = file_copy;
|
||||
curr = fn_call;
|
||||
} else {
|
||||
curr = fn_call + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_fn_calls");
|
||||
}
|
||||
|
||||
/// Fully removes unreachable functions.
|
||||
fn remove_fns(file: &mut Vec<String>, path: &PathBuf, cache: &mut ResultCache) {
|
||||
let mut curr = 0;
|
||||
|
||||
while curr < file.len() {
|
||||
// Find a function start
|
||||
let Some(fn_start) = file[curr..].iter().position(|line| {
|
||||
line.contains("#[custom_mir(dialect = \"runtime\", phase = \"initial\")]")
|
||||
}) else {
|
||||
// No more functions to remove - exit early.
|
||||
break;
|
||||
};
|
||||
// Find the next function(and use that to find the end of this one).
|
||||
// FIXME: this check is flawed: it will never remove the very last function(the one before main).
|
||||
// The other checks will turn that function into a single call to abort, but it is still annoying that it is kept.
|
||||
let fn_start = fn_start + curr;
|
||||
let Some(fn_end) = file[(fn_start + 3)..].iter().position(|line| line.contains("fn fn"))
|
||||
else {
|
||||
// No more functions to remove - exit early.
|
||||
break;
|
||||
};
|
||||
let fn_end = fn_start + 2 + fn_end;
|
||||
let mut file_copy = file.clone();
|
||||
// Remove the function.\\
|
||||
file_copy.drain(fn_start..fn_end);
|
||||
// Check if this reduction is valid.
|
||||
if test_reduction(&file_copy, path, cache) {
|
||||
println!("Reduced {path:?} by {} lines `remove_fns`", fn_end - fn_start);
|
||||
*file = file_copy;
|
||||
} else {
|
||||
curr = fn_start + 1;
|
||||
}
|
||||
}
|
||||
save_reduction(file, path, "remove_fns");
|
||||
}
|
||||
|
||||
pub(super) fn reduce(path: impl AsRef<Path>) {
|
||||
let path = path.as_ref().to_owned();
|
||||
// ... read the file to a buffer ..
|
||||
let file = std::fs::read_to_string(&path).expect("Could not open the file to reduce");
|
||||
let mut file: Vec<_> = file.split_inclusive('\n').map(|s| s.to_string()).collect();
|
||||
|
||||
// ... and run reduction passes.
|
||||
println!("running `remove_dump_var` on {path:?}.");
|
||||
remove_dump_var(&mut file, &path);
|
||||
// After `dump_var`, the execution results ought not to change. Cache them.
|
||||
let mut cache = None;
|
||||
// Fill the cache
|
||||
assert!(
|
||||
test_reduction(&file, &path, &mut cache),
|
||||
"Reduction error: check that the input file is a valid reproducer."
|
||||
);
|
||||
println!("cache:{cache:?}");
|
||||
println!("running `remove_fn_calls` on {path:?}.");
|
||||
remove_fn_calls(&mut file, &path, &mut cache);
|
||||
println!("running `remove_fns` on {path:?}.");
|
||||
remove_fns(&mut file, &path, &mut cache);
|
||||
let len = file.len();
|
||||
println!("running `remove_dup_assign` on {path:?}.");
|
||||
remove_dup_assign(&mut file, &path, 0, len, &mut cache);
|
||||
file.retain(|line| !line.is_empty());
|
||||
println!("running `match_to_goto` on {path:?}.");
|
||||
match_to_goto(&mut file, &path, &mut cache);
|
||||
println!("running `block_abort` on {path:?}.");
|
||||
block_abort(&mut file, &path, &mut cache);
|
||||
println!("running `remove_block` on {path:?}.");
|
||||
remove_block(&mut file, &path, &mut cache);
|
||||
println!("running `linearize_cf` on {path:?}.");
|
||||
linearize_cf(&mut file, &path, &mut cache);
|
||||
let mut out = std::fs::File::create(&path).expect("Could not save the reduction result.");
|
||||
let file = file.into_iter().collect::<String>();
|
||||
out.write_all(file.as_bytes()).expect("failed to write into file");
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ pub fn run() -> Result<(), String> {
|
|||
config.no_download = true;
|
||||
config.setup_gcc_path()?;
|
||||
if let Some(gcc_path) = config.gcc_path {
|
||||
println!("{}", gcc_path);
|
||||
println!("{gcc_path}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ mod clean;
|
|||
mod clone_gcc;
|
||||
mod config;
|
||||
mod fmt;
|
||||
mod fuzz;
|
||||
mod info;
|
||||
mod prepare;
|
||||
mod rust_tools;
|
||||
|
|
@ -42,7 +43,8 @@ Commands:
|
|||
test : Runs tests for the project.
|
||||
info : Displays information about the build environment and project configuration.
|
||||
clone-gcc : Clones the GCC compiler from a specified source.
|
||||
fmt : Runs rustfmt"
|
||||
fmt : Runs rustfmt
|
||||
fuzz : Fuzzes `cg_gcc` using rustlantis"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +58,7 @@ pub enum Command {
|
|||
Test,
|
||||
Info,
|
||||
Fmt,
|
||||
Fuzz,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
@ -75,6 +78,7 @@ fn main() {
|
|||
Some("info") => Command::Info,
|
||||
Some("clone-gcc") => Command::CloneGcc,
|
||||
Some("fmt") => Command::Fmt,
|
||||
Some("fuzz") => Command::Fuzz,
|
||||
Some("--help") => {
|
||||
usage();
|
||||
process::exit(0);
|
||||
|
|
@ -97,6 +101,7 @@ fn main() {
|
|||
Command::Info => info::run(),
|
||||
Command::CloneGcc => clone_gcc::run(),
|
||||
Command::Fmt => fmt::run(),
|
||||
Command::Fuzz => fuzz::run(),
|
||||
} {
|
||||
eprintln!("Command failed to run: {e}");
|
||||
process::exit(1);
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ fn prepare_libcore(
|
|||
if let Some(path) = sysroot_source {
|
||||
rustlib_dir = Path::new(&path)
|
||||
.canonicalize()
|
||||
.map_err(|error| format!("Failed to canonicalize path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to canonicalize path: {error:?}"))?;
|
||||
if !rustlib_dir.is_dir() {
|
||||
return Err(format!("Custom sysroot path {:?} not found", rustlib_dir));
|
||||
return Err(format!("Custom sysroot path {rustlib_dir:?} not found"));
|
||||
}
|
||||
} else {
|
||||
let rustc_path = match get_rustc_path() {
|
||||
|
|
@ -36,17 +36,17 @@ fn prepare_libcore(
|
|||
rustlib_dir = parent
|
||||
.join("../lib/rustlib/src/rust")
|
||||
.canonicalize()
|
||||
.map_err(|error| format!("Failed to canonicalize path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to canonicalize path: {error:?}"))?;
|
||||
if !rustlib_dir.is_dir() {
|
||||
return Err("Please install `rust-src` component".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let sysroot_dir = sysroot_path.join("sysroot_src");
|
||||
if sysroot_dir.is_dir() {
|
||||
if let Err(error) = fs::remove_dir_all(&sysroot_dir) {
|
||||
return Err(format!("Failed to remove `{}`: {:?}", sysroot_dir.display(), error,));
|
||||
}
|
||||
if sysroot_dir.is_dir()
|
||||
&& let Err(error) = fs::remove_dir_all(&sysroot_dir)
|
||||
{
|
||||
return Err(format!("Failed to remove `{}`: {:?}", sysroot_dir.display(), error,));
|
||||
}
|
||||
|
||||
let sysroot_library_dir = sysroot_dir.join("library");
|
||||
|
|
@ -122,7 +122,7 @@ fn prepare_rand() -> Result<(), String> {
|
|||
// Apply patch for the rand crate.
|
||||
let file_path = "patches/crates/0001-Remove-deny-warnings.patch";
|
||||
let rand_dir = Path::new("build/rand");
|
||||
println!("[GIT] apply `{}`", file_path);
|
||||
println!("[GIT] apply `{file_path}`");
|
||||
let path = Path::new("../..").join(file_path);
|
||||
run_command_with_output(&[&"git", &"apply", &path], Some(rand_dir))?;
|
||||
run_command_with_output(&[&"git", &"add", &"-A"], Some(rand_dir))?;
|
||||
|
|
@ -149,7 +149,7 @@ fn clone_and_setup<F>(repo_url: &str, checkout_commit: &str, extra: Option<F>) -
|
|||
where
|
||||
F: Fn(&Path) -> Result<(), String>,
|
||||
{
|
||||
let clone_result = git_clone_root_dir(repo_url, &Path::new(crate::BUILD_DIR), false)?;
|
||||
let clone_result = git_clone_root_dir(repo_url, Path::new(crate::BUILD_DIR), false)?;
|
||||
if !clone_result.ran_clone {
|
||||
println!("`{}` has already been cloned", clone_result.repo_name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,22 @@
|
|||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::config::ConfigInfo;
|
||||
use crate::utils::{
|
||||
get_toolchain, run_command_with_output_and_env_no_err, rustc_toolchain_version_info,
|
||||
rustc_version_info,
|
||||
};
|
||||
use crate::utils::{get_toolchain, rustc_toolchain_version_info, rustc_version_info};
|
||||
|
||||
fn args(command: &str) -> Result<Option<Vec<String>>, String> {
|
||||
// We skip the binary and the "cargo"/"rustc" option.
|
||||
if let Some("--help") = std::env::args().skip(2).next().as_deref() {
|
||||
if let Some("--help") = std::env::args().nth(2).as_deref() {
|
||||
usage(command);
|
||||
return Ok(None);
|
||||
}
|
||||
let args = std::env::args().skip(2).collect::<Vec<_>>();
|
||||
if args.is_empty() {
|
||||
return Err(format!(
|
||||
"Expected at least one argument for `{}` subcommand, found none",
|
||||
command
|
||||
"Expected at least one argument for `{command}` subcommand, found none"
|
||||
));
|
||||
}
|
||||
Ok(Some(args))
|
||||
|
|
@ -27,12 +25,11 @@ fn args(command: &str) -> Result<Option<Vec<String>>, String> {
|
|||
fn usage(command: &str) {
|
||||
println!(
|
||||
r#"
|
||||
`{}` command help:
|
||||
`{command}` command help:
|
||||
|
||||
[args] : Arguments to be passed to the cargo command
|
||||
--help : Show this help
|
||||
"#,
|
||||
command,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -51,10 +48,10 @@ impl RustcTools {
|
|||
// expected.
|
||||
let current_dir = std::env::current_dir()
|
||||
.and_then(|path| path.canonicalize())
|
||||
.map_err(|error| format!("Failed to get current directory path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to get current directory path: {error:?}"))?;
|
||||
let current_exe = std::env::current_exe()
|
||||
.and_then(|path| path.canonicalize())
|
||||
.map_err(|error| format!("Failed to get current exe path: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to get current exe path: {error:?}"))?;
|
||||
let mut parent_dir =
|
||||
current_exe.components().map(|comp| comp.as_os_str()).collect::<Vec<_>>();
|
||||
// We run this script from "build_system/target/release/y", so we need to remove these elements.
|
||||
|
|
@ -68,7 +65,7 @@ impl RustcTools {
|
|||
));
|
||||
}
|
||||
}
|
||||
let parent_dir = PathBuf::from(parent_dir.join(&OsStr::new("/")));
|
||||
let parent_dir = PathBuf::from(parent_dir.join(OsStr::new("/")));
|
||||
std::env::set_current_dir(&parent_dir).map_err(|error| {
|
||||
format!("Failed to go to `{}` folder: {:?}", parent_dir.display(), error)
|
||||
})?;
|
||||
|
|
@ -92,11 +89,31 @@ impl RustcTools {
|
|||
std::env::set_current_dir(¤t_dir).map_err(|error| {
|
||||
format!("Failed to go back to `{}` folder: {:?}", current_dir.display(), error)
|
||||
})?;
|
||||
let toolchain = format!("+{}", toolchain);
|
||||
let toolchain = format!("+{toolchain}");
|
||||
Ok(Some(Self { toolchain, args, env, config }))
|
||||
}
|
||||
}
|
||||
|
||||
fn exec(input: &[&dyn AsRef<OsStr>], env: &HashMap<String, String>) -> Result<(), String> {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
// We use `exec` to call the `execvp` syscall instead of creating a new process where the
|
||||
// command will be executed because very few signals can actually kill a current process,
|
||||
// so if segmentation fault (SIGSEGV signal) happens and we raise to the current process,
|
||||
// it will simply do nothing and we won't have the nice error message for the shell.
|
||||
let error = crate::utils::get_command_inner(input, None, Some(env)).exec();
|
||||
eprintln!("execvp syscall failed: {error:?}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
{
|
||||
if crate::utils::run_command_with_output_and_env_no_err(input, None, Some(env)).is_err() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_cargo() -> Result<(), String> {
|
||||
let Some(mut tools) = RustcTools::new("cargo")? else { return Ok(()) };
|
||||
let rustflags = tools.env.get("RUSTFLAGS").cloned().unwrap_or_default();
|
||||
|
|
@ -105,11 +122,7 @@ pub fn run_cargo() -> Result<(), String> {
|
|||
for arg in &tools.args {
|
||||
command.push(arg);
|
||||
}
|
||||
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
exec(&command, &tools.env)
|
||||
}
|
||||
|
||||
pub fn run_rustc() -> Result<(), String> {
|
||||
|
|
@ -118,8 +131,5 @@ pub fn run_rustc() -> Result<(), String> {
|
|||
for arg in &tools.args {
|
||||
command.push(arg);
|
||||
}
|
||||
if run_command_with_output_and_env_no_err(&command, None, Some(&tools.env)).is_err() {
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(())
|
||||
exec(&command, &tools.env)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ use crate::build;
|
|||
use crate::config::{Channel, ConfigInfo};
|
||||
use crate::utils::{
|
||||
create_dir, get_sysroot_dir, get_toolchain, git_clone, git_clone_root_dir, remove_file,
|
||||
run_command, run_command_with_env, run_command_with_output_and_env, rustc_version_info,
|
||||
split_args, walk_dir,
|
||||
run_command, run_command_with_env, run_command_with_output, run_command_with_output_and_env,
|
||||
rustc_version_info, split_args, walk_dir,
|
||||
};
|
||||
|
||||
type Env = HashMap<String, String>;
|
||||
|
|
@ -42,7 +42,7 @@ fn get_runners() -> Runners {
|
|||
);
|
||||
runners.insert("--extended-regex-tests", ("Run extended regex tests", extended_regex_tests));
|
||||
runners.insert("--mini-tests", ("Run mini tests", mini_tests));
|
||||
|
||||
runners.insert("--cargo-tests", ("Run cargo tests", cargo_tests));
|
||||
runners
|
||||
}
|
||||
|
||||
|
|
@ -53,9 +53,9 @@ fn get_number_after_arg(
|
|||
match args.next() {
|
||||
Some(nb) if !nb.is_empty() => match usize::from_str(&nb) {
|
||||
Ok(nb) => Ok(nb),
|
||||
Err(_) => Err(format!("Expected a number after `{}`, found `{}`", option, nb)),
|
||||
Err(_) => Err(format!("Expected a number after `{option}`, found `{nb}`")),
|
||||
},
|
||||
_ => Err(format!("Expected a number after `{}`, found nothing", option)),
|
||||
_ => Err(format!("Expected a number after `{option}`, found nothing")),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,8 +76,8 @@ fn show_usage() {
|
|||
for (option, (doc, _)) in get_runners() {
|
||||
// FIXME: Instead of using the hard-coded `23` value, better to compute it instead.
|
||||
let needed_spaces = 23_usize.saturating_sub(option.len());
|
||||
let spaces: String = std::iter::repeat(' ').take(needed_spaces).collect();
|
||||
println!(" {}{}: {}", option, spaces, doc);
|
||||
let spaces: String = std::iter::repeat_n(' ', needed_spaces).collect();
|
||||
println!(" {option}{spaces}: {doc}");
|
||||
}
|
||||
println!(" --help : Show this help");
|
||||
}
|
||||
|
|
@ -88,6 +88,8 @@ struct TestArg {
|
|||
use_system_gcc: bool,
|
||||
runners: Vec<String>,
|
||||
flags: Vec<String>,
|
||||
/// Additional arguments, to be passed to commands like `cargo test`.
|
||||
test_args: Vec<String>,
|
||||
nb_parts: Option<usize>,
|
||||
current_part: Option<usize>,
|
||||
sysroot_panic_abort: bool,
|
||||
|
|
@ -137,13 +139,14 @@ impl TestArg {
|
|||
test_arg.sysroot_features.push(feature);
|
||||
}
|
||||
_ => {
|
||||
return Err(format!("Expected an argument after `{}`, found nothing", arg));
|
||||
return Err(format!("Expected an argument after `{arg}`, found nothing"));
|
||||
}
|
||||
},
|
||||
"--help" => {
|
||||
show_usage();
|
||||
return Ok(None);
|
||||
}
|
||||
"--" => test_arg.test_args.extend(&mut args),
|
||||
x if runners.contains_key(x)
|
||||
&& !test_arg.runners.iter().any(|runner| runner == x) =>
|
||||
{
|
||||
|
|
@ -151,7 +154,7 @@ impl TestArg {
|
|||
}
|
||||
arg => {
|
||||
if !test_arg.config_info.parse_argument(arg, &mut args)? {
|
||||
return Err(format!("Unknown option {}", arg));
|
||||
return Err(format!("Unknown option {arg}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,7 +192,7 @@ fn build_if_no_backend(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
command.push(&"--release");
|
||||
&tmp_env
|
||||
} else {
|
||||
&env
|
||||
env
|
||||
};
|
||||
for flag in args.flags.iter() {
|
||||
command.push(flag);
|
||||
|
|
@ -203,6 +206,33 @@ fn clean(_env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
create_dir(&path)
|
||||
}
|
||||
|
||||
fn cargo_tests(test_env: &Env, test_args: &TestArg) -> Result<(), String> {
|
||||
// First, we call `mini_tests` to build minicore for us. This ensures we are testing with a working `minicore`,
|
||||
// and that any changes we have made affect `minicore`(since it would get rebuilt).
|
||||
mini_tests(test_env, test_args)?;
|
||||
// Then, we copy some of the env vars from `test_env`
|
||||
// We don't want to pass things like `RUSTFLAGS`, since they contain the -Zcodegen-backend flag.
|
||||
// That would force `cg_gcc` to *rebuild itself* and only then run tests, which is undesirable.
|
||||
let mut env = HashMap::new();
|
||||
env.insert(
|
||||
"LD_LIBRARY_PATH".into(),
|
||||
test_env.get("LD_LIBRARY_PATH").expect("LD_LIBRARY_PATH missing!").to_string(),
|
||||
);
|
||||
env.insert(
|
||||
"LIBRARY_PATH".into(),
|
||||
test_env.get("LIBRARY_PATH").expect("LIBRARY_PATH missing!").to_string(),
|
||||
);
|
||||
env.insert(
|
||||
"CG_RUSTFLAGS".into(),
|
||||
test_env.get("CG_RUSTFLAGS").map(|s| s.as_str()).unwrap_or("").to_string(),
|
||||
);
|
||||
// Pass all the default args + the user-specified ones.
|
||||
let mut args: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &"test"];
|
||||
args.extend(test_args.test_args.iter().map(|s| s as &dyn AsRef<OsStr>));
|
||||
run_command_with_output_and_env(&args, None, Some(&env))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[BUILD] mini_core");
|
||||
|
|
@ -222,7 +252,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
&"--target",
|
||||
&args.config_info.target_triple,
|
||||
]);
|
||||
run_command_with_output_and_env(&command, None, Some(&env))?;
|
||||
run_command_with_output_and_env(&command, None, Some(env))?;
|
||||
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[BUILD] example");
|
||||
|
|
@ -234,7 +264,7 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
&"--target",
|
||||
&args.config_info.target_triple,
|
||||
]);
|
||||
run_command_with_output_and_env(&command, None, Some(&env))?;
|
||||
run_command_with_output_and_env(&command, None, Some(env))?;
|
||||
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[AOT] mini_core_hello_world");
|
||||
|
|
@ -249,14 +279,14 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
&"--target",
|
||||
&args.config_info.target_triple,
|
||||
]);
|
||||
run_command_with_output_and_env(&command, None, Some(&env))?;
|
||||
run_command_with_output_and_env(&command, None, Some(env))?;
|
||||
|
||||
let command: &[&dyn AsRef<OsStr>] = &[
|
||||
&Path::new(&args.config_info.cargo_target_dir).join("mini_core_hello_world"),
|
||||
&"abc",
|
||||
&"bcd",
|
||||
];
|
||||
maybe_run_command_in_vm(&command, env, args)?;
|
||||
maybe_run_command_in_vm(command, env, args)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -454,22 +484,47 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
|||
} else {
|
||||
run_command_with_output_and_env(&[&"git", &"checkout"], rust_dir, Some(env))?;
|
||||
}
|
||||
|
||||
let mut patches = Vec::new();
|
||||
walk_dir(
|
||||
"patches/tests",
|
||||
&mut |_| Ok(()),
|
||||
&mut |file_path: &Path| {
|
||||
patches.push(file_path.to_path_buf());
|
||||
Ok(())
|
||||
},
|
||||
false,
|
||||
)?;
|
||||
patches.sort();
|
||||
// TODO: remove duplication with prepare.rs by creating a apply_patch function in the utils
|
||||
// module.
|
||||
for file_path in patches {
|
||||
println!("[GIT] apply `{}`", file_path.display());
|
||||
let path = Path::new("../..").join(file_path);
|
||||
run_command_with_output(&[&"git", &"apply", &path], rust_dir)?;
|
||||
run_command_with_output(&[&"git", &"add", &"-A"], rust_dir)?;
|
||||
run_command_with_output(
|
||||
&[&"git", &"commit", &"--no-gpg-sign", &"-m", &format!("Patch {}", path.display())],
|
||||
rust_dir,
|
||||
)?;
|
||||
}
|
||||
|
||||
let cargo = String::from_utf8(
|
||||
run_command_with_env(&[&"rustup", &"which", &"cargo"], rust_dir, Some(env))?.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve cargo path: {:?}", error))
|
||||
.map_err(|error| format!("Failed to retrieve cargo path: {error:?}"))
|
||||
.and_then(|cargo| {
|
||||
let cargo = cargo.trim().to_owned();
|
||||
if cargo.is_empty() { Err(format!("`cargo` path is empty")) } else { Ok(cargo) }
|
||||
if cargo.is_empty() { Err("`cargo` path is empty".to_string()) } else { Ok(cargo) }
|
||||
})?;
|
||||
let rustc = String::from_utf8(
|
||||
run_command_with_env(&[&"rustup", &toolchain, &"which", &"rustc"], rust_dir, Some(env))?
|
||||
.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve rustc path: {:?}", error))
|
||||
.map_err(|error| format!("Failed to retrieve rustc path: {error:?}"))
|
||||
.and_then(|rustc| {
|
||||
let rustc = rustc.trim().to_owned();
|
||||
if rustc.is_empty() { Err(format!("`rustc` path is empty")) } else { Ok(rustc) }
|
||||
if rustc.is_empty() { Err("`rustc` path is empty".to_string()) } else { Ok(rustc) }
|
||||
})?;
|
||||
let llvm_filecheck = match run_command_with_env(
|
||||
&[
|
||||
|
|
@ -479,7 +534,8 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
|||
which FileCheck-11 || \
|
||||
which FileCheck-12 || \
|
||||
which FileCheck-13 || \
|
||||
which FileCheck-14",
|
||||
which FileCheck-14 || \
|
||||
which FileCheck",
|
||||
],
|
||||
rust_dir,
|
||||
Some(env),
|
||||
|
|
@ -487,13 +543,15 @@ fn setup_rustc(env: &mut Env, args: &TestArg) -> Result<PathBuf, String> {
|
|||
Ok(cmd) => String::from_utf8_lossy(&cmd.stdout).to_string(),
|
||||
Err(_) => {
|
||||
eprintln!("Failed to retrieve LLVM FileCheck, ignoring...");
|
||||
// FIXME: the test tests/run-make/no-builtins-attribute will fail if we cannot find
|
||||
// FileCheck.
|
||||
String::new()
|
||||
}
|
||||
};
|
||||
let file_path = rust_dir_path.join("config.toml");
|
||||
std::fs::write(
|
||||
&file_path,
|
||||
&format!(
|
||||
format!(
|
||||
r#"change-id = 115898
|
||||
|
||||
[rust]
|
||||
|
|
@ -532,7 +590,7 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
let codegen_backend_path = format!(
|
||||
"{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
|
||||
pwd = std::env::current_dir()
|
||||
.map_err(|error| format!("`current_dir` failed: {:?}", error))?
|
||||
.map_err(|error| format!("`current_dir` failed: {error:?}"))?
|
||||
.display(),
|
||||
channel = args.config_info.channel.as_str(),
|
||||
dylib_ext = args.config_info.dylib_ext,
|
||||
|
|
@ -587,11 +645,11 @@ where
|
|||
F: Fn(&[&dyn AsRef<OsStr>], Option<&Path>, &Env) -> Result<(), String>,
|
||||
{
|
||||
let toolchain = get_toolchain()?;
|
||||
let toolchain_arg = format!("+{}", toolchain);
|
||||
let toolchain_arg = format!("+{toolchain}");
|
||||
let rustc_version = String::from_utf8(
|
||||
run_command_with_env(&[&args.config_info.rustc_command[0], &"-V"], cwd, Some(env))?.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve rustc version: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to retrieve rustc version: {error:?}"))?;
|
||||
let rustc_toolchain_version = String::from_utf8(
|
||||
run_command_with_env(
|
||||
&[&args.config_info.rustc_command[0], &toolchain_arg, &"-V"],
|
||||
|
|
@ -600,20 +658,19 @@ where
|
|||
)?
|
||||
.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve rustc +toolchain version: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to retrieve rustc +toolchain version: {error:?}"))?;
|
||||
|
||||
if rustc_version != rustc_toolchain_version {
|
||||
eprintln!(
|
||||
"rustc_codegen_gcc is built for `{}` but the default rustc version is `{}`.",
|
||||
rustc_toolchain_version, rustc_version,
|
||||
"rustc_codegen_gcc is built for `{rustc_toolchain_version}` but the default rustc version is `{rustc_version}`.",
|
||||
);
|
||||
eprintln!("Using `{}`.", rustc_toolchain_version);
|
||||
eprintln!("Using `{rustc_toolchain_version}`.");
|
||||
}
|
||||
let mut env = env.clone();
|
||||
let rustflags = env.get("RUSTFLAGS").cloned().unwrap_or_default();
|
||||
env.insert("RUSTDOCFLAGS".to_string(), rustflags);
|
||||
let mut cargo_command: Vec<&dyn AsRef<OsStr>> = vec![&"cargo", &toolchain_arg];
|
||||
cargo_command.extend_from_slice(&command);
|
||||
cargo_command.extend_from_slice(command);
|
||||
callback(&cargo_command, cwd, &env)
|
||||
}
|
||||
|
||||
|
|
@ -680,7 +737,15 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
println!("[TEST] libcore");
|
||||
let path = get_sysroot_dir().join("sysroot_src/library/coretests");
|
||||
let _ = remove_dir_all(path.join("target"));
|
||||
run_cargo_command(&[&"test"], Some(&path), env, args)?;
|
||||
// TODO(antoyo): run in release mode when we fix the failures.
|
||||
// TODO(antoyo): remove the --skip f16::test_total_cmp when this issue is fixed:
|
||||
// https://github.com/rust-lang/rust/issues/141503
|
||||
run_cargo_command(
|
||||
&[&"test", &"--", &"--skip", &"f16::test_total_cmp"],
|
||||
Some(&path),
|
||||
env,
|
||||
args,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -818,7 +883,7 @@ fn contains_ui_error_patterns(file_path: &Path, keep_lto_tests: bool) -> Result<
|
|||
// Tests generating errors.
|
||||
let file = File::open(file_path)
|
||||
.map_err(|error| format!("Failed to read `{}`: {:?}", file_path.display(), error))?;
|
||||
for line in BufReader::new(file).lines().filter_map(|line| line.ok()) {
|
||||
for line in BufReader::new(file).lines().map_while(Result::ok) {
|
||||
let line = line.trim();
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
|
|
@ -887,7 +952,7 @@ where
|
|||
|
||||
if !prepare_files_callback(&rust_path)? {
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("Keeping all {} tests", test_type);
|
||||
println!("Keeping all {test_type} tests");
|
||||
}
|
||||
|
||||
if test_type == "ui" {
|
||||
|
|
@ -919,8 +984,7 @@ where
|
|||
"borrowck",
|
||||
"test-attrs",
|
||||
]
|
||||
.iter()
|
||||
.any(|name| *name == dir_name)
|
||||
.contains(&dir_name)
|
||||
{
|
||||
remove_dir_all(dir).map_err(|error| {
|
||||
format!("Failed to remove folder `{}`: {:?}", dir.display(), error)
|
||||
|
|
@ -975,10 +1039,7 @@ where
|
|||
if nb_parts > 0 {
|
||||
let current_part = args.current_part.unwrap();
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!(
|
||||
"Splitting ui_test into {} parts (and running part {})",
|
||||
nb_parts, current_part
|
||||
);
|
||||
println!("Splitting ui_test into {nb_parts} parts (and running part {current_part})");
|
||||
let out = String::from_utf8(
|
||||
run_command(
|
||||
&[
|
||||
|
|
@ -996,7 +1057,7 @@ where
|
|||
)?
|
||||
.stdout,
|
||||
)
|
||||
.map_err(|error| format!("Failed to retrieve output of find command: {:?}", error))?;
|
||||
.map_err(|error| format!("Failed to retrieve output of find command: {error:?}"))?;
|
||||
let mut files = out
|
||||
.split('\n')
|
||||
.map(|line| line.trim())
|
||||
|
|
@ -1016,7 +1077,7 @@ where
|
|||
}
|
||||
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[TEST] rustc {} test suite", test_type);
|
||||
println!("[TEST] rustc {test_type} test suite");
|
||||
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
|
||||
|
||||
let extra =
|
||||
|
|
@ -1040,7 +1101,7 @@ where
|
|||
&"always",
|
||||
&"--stage",
|
||||
&"0",
|
||||
&format!("tests/{}", test_type),
|
||||
&format!("tests/{test_type}"),
|
||||
&"--compiletest-rustc-args",
|
||||
&rustc_args,
|
||||
],
|
||||
|
|
@ -1051,19 +1112,18 @@ where
|
|||
}
|
||||
|
||||
fn test_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
//test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "run-make")?;
|
||||
test_rustc_inner(env, args, |_| Ok(false), false, "ui")
|
||||
}
|
||||
|
||||
fn test_failing_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
let result1 = Ok(());
|
||||
/*test_rustc_inner(
|
||||
let result1 = test_rustc_inner(
|
||||
env,
|
||||
args,
|
||||
retain_files_callback("tests/failing-run-make-tests.txt", "run-make"),
|
||||
false,
|
||||
"run-make",
|
||||
)*/
|
||||
);
|
||||
|
||||
let result2 = test_rustc_inner(
|
||||
env,
|
||||
|
|
@ -1084,14 +1144,13 @@ fn test_successful_rustc(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
false,
|
||||
"ui",
|
||||
)?;
|
||||
Ok(())
|
||||
/*test_rustc_inner(
|
||||
test_rustc_inner(
|
||||
env,
|
||||
args,
|
||||
remove_files_callback("tests/failing-run-make-tests.txt", "run-make"),
|
||||
false,
|
||||
"run-make",
|
||||
)*/
|
||||
)
|
||||
}
|
||||
|
||||
fn test_failing_ui_pattern_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
||||
|
|
@ -1118,7 +1177,7 @@ fn retain_files_callback<'a>(
|
|||
run_command(
|
||||
&[
|
||||
&"find",
|
||||
&format!("tests/{}", test_type),
|
||||
&format!("tests/{test_type}"),
|
||||
&"-mindepth",
|
||||
&"1",
|
||||
&"-type",
|
||||
|
|
@ -1137,7 +1196,7 @@ fn retain_files_callback<'a>(
|
|||
run_command(
|
||||
&[
|
||||
&"find",
|
||||
&format!("tests/{}", test_type),
|
||||
&format!("tests/{test_type}"),
|
||||
&"-type",
|
||||
&"f",
|
||||
&"-name",
|
||||
|
|
@ -1152,15 +1211,12 @@ fn retain_files_callback<'a>(
|
|||
}
|
||||
|
||||
// Putting back only the failing ones.
|
||||
if let Ok(files) = std::fs::read_to_string(&file_path) {
|
||||
if let Ok(files) = std::fs::read_to_string(file_path) {
|
||||
for file in files.split('\n').map(|line| line.trim()).filter(|line| !line.is_empty()) {
|
||||
run_command(&[&"git", &"checkout", &"--", &file], Some(&rust_path))?;
|
||||
run_command(&[&"git", &"checkout", &"--", &file], Some(rust_path))?;
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"Failed to read `{}`, not putting back failing {} tests",
|
||||
file_path, test_type
|
||||
);
|
||||
println!("Failed to read `{file_path}`, not putting back failing {test_type} tests");
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
|
|
@ -1188,8 +1244,7 @@ fn remove_files_callback<'a>(
|
|||
}
|
||||
} else {
|
||||
println!(
|
||||
"Failed to read `{}`, not putting back failing {} tests",
|
||||
file_path, test_type
|
||||
"Failed to read `{file_path}`, not putting back failing {test_type} tests"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1202,7 +1257,7 @@ fn remove_files_callback<'a>(
|
|||
remove_file(&path)?;
|
||||
}
|
||||
} else {
|
||||
println!("Failed to read `{}`, not putting back failing ui tests", file_path);
|
||||
println!("Failed to read `{file_path}`, not putting back failing ui tests");
|
||||
}
|
||||
}
|
||||
Ok(true)
|
||||
|
|
@ -1217,7 +1272,9 @@ fn run_all(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
// asm_tests(env, args)?;
|
||||
test_libcore(env, args)?;
|
||||
extended_sysroot_tests(env, args)?;
|
||||
cargo_tests(env, args)?;
|
||||
test_rustc(env, args)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
#[cfg(unix)]
|
||||
use std::ffi::c_int;
|
||||
use std::fmt::Debug;
|
||||
use std::fs;
|
||||
#[cfg(unix)]
|
||||
|
|
@ -9,11 +7,6 @@ use std::os::unix::process::ExitStatusExt;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::process::{Command, ExitStatus, Output};
|
||||
|
||||
#[cfg(unix)]
|
||||
unsafe extern "C" {
|
||||
fn raise(signal: c_int) -> c_int;
|
||||
}
|
||||
|
||||
fn exec_command(
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
|
|
@ -27,17 +20,14 @@ fn exec_command(
|
|||
#[cfg(unix)]
|
||||
{
|
||||
if let Some(signal) = status.signal() {
|
||||
unsafe {
|
||||
raise(signal as _);
|
||||
}
|
||||
// In case the signal didn't kill the current process.
|
||||
return Err(command_error(input, &cwd, format!("Process received signal {}", signal)));
|
||||
return Err(command_error(input, &cwd, format!("Process received signal {signal}")));
|
||||
}
|
||||
}
|
||||
Ok(status)
|
||||
}
|
||||
|
||||
fn get_command_inner(
|
||||
pub(crate) fn get_command_inner(
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
env: Option<&HashMap<String, String>>,
|
||||
|
|
@ -75,18 +65,18 @@ fn check_exit_status(
|
|||
);
|
||||
let input = input.iter().map(|i| i.as_ref()).collect::<Vec<&OsStr>>();
|
||||
if show_err {
|
||||
eprintln!("Command `{:?}` failed", input);
|
||||
eprintln!("Command `{input:?}` failed");
|
||||
}
|
||||
if let Some(output) = output {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
if !stdout.is_empty() {
|
||||
error.push_str("\n==== STDOUT ====\n");
|
||||
error.push_str(&*stdout);
|
||||
error.push_str(&stdout);
|
||||
}
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
if !stderr.is_empty() {
|
||||
error.push_str("\n==== STDERR ====\n");
|
||||
error.push_str(&*stderr);
|
||||
error.push_str(&stderr);
|
||||
}
|
||||
}
|
||||
Err(error)
|
||||
|
|
@ -136,6 +126,7 @@ pub fn run_command_with_output_and_env(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
pub fn run_command_with_output_and_env_no_err(
|
||||
input: &[&dyn AsRef<OsStr>],
|
||||
cwd: Option<&Path>,
|
||||
|
|
@ -242,7 +233,7 @@ pub fn get_toolchain() -> Result<String, String> {
|
|||
if !line.starts_with("channel") {
|
||||
return None;
|
||||
}
|
||||
line.split('"').skip(1).next()
|
||||
line.split('"').nth(1)
|
||||
})
|
||||
.next()
|
||||
{
|
||||
|
|
@ -281,7 +272,7 @@ fn git_clone_inner(
|
|||
}
|
||||
|
||||
fn get_repo_name(url: &str) -> String {
|
||||
let repo_name = url.split('/').last().unwrap();
|
||||
let repo_name = url.split('/').next_back().unwrap();
|
||||
match repo_name.strip_suffix(".git") {
|
||||
Some(n) => n.to_string(),
|
||||
None => repo_name.to_string(),
|
||||
|
|
|
|||
|
|
@ -37,10 +37,6 @@ impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
|
|||
|
||||
|
||||
trait Trait {
|
||||
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
|
||||
// without unsized_locals), but wrappers around `Self` currently are not.
|
||||
// FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
|
||||
// fn wrapper(self: Wrapper<Self>) -> i32;
|
||||
fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
|
||||
fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
|
||||
fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
|
||||
|
|
|
|||
|
|
@ -19,8 +19,14 @@ unsafe extern "C" fn _Unwind_Resume() {
|
|||
intrinsics::unreachable();
|
||||
}
|
||||
|
||||
#[lang = "pointee_sized"]
|
||||
pub trait PointeeSized {}
|
||||
|
||||
#[lang = "meta_sized"]
|
||||
pub trait MetaSized: PointeeSized {}
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
pub trait Sized: MetaSized {}
|
||||
|
||||
#[lang = "destruct"]
|
||||
pub trait Destruct {}
|
||||
|
|
@ -29,35 +35,35 @@ pub trait Destruct {}
|
|||
pub trait Tuple {}
|
||||
|
||||
#[lang = "unsize"]
|
||||
pub trait Unsize<T: ?Sized> {}
|
||||
pub trait Unsize<T: PointeeSized>: PointeeSized {}
|
||||
|
||||
#[lang = "coerce_unsized"]
|
||||
pub trait CoerceUnsized<T> {}
|
||||
|
||||
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
|
||||
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
|
||||
impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
|
||||
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *const T {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {}
|
||||
|
||||
#[lang = "dispatch_from_dyn"]
|
||||
pub trait DispatchFromDyn<T> {}
|
||||
|
||||
// &T -> &U
|
||||
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
|
||||
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {}
|
||||
// &mut T -> &mut U
|
||||
impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
|
||||
impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {}
|
||||
// *const T -> *const U
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*const U> for *const T {}
|
||||
// *mut T -> *mut U
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
|
||||
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
|
||||
impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {}
|
||||
impl<T: MetaSized + Unsize<U>, U: MetaSized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
|
||||
|
||||
#[lang = "legacy_receiver"]
|
||||
pub trait LegacyReceiver {}
|
||||
|
||||
impl<T: ?Sized> LegacyReceiver for &T {}
|
||||
impl<T: ?Sized> LegacyReceiver for &mut T {}
|
||||
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
|
||||
impl<T: PointeeSized> LegacyReceiver for &T {}
|
||||
impl<T: PointeeSized> LegacyReceiver for &mut T {}
|
||||
impl<T: MetaSized> LegacyReceiver for Box<T> {}
|
||||
|
||||
#[lang = "receiver"]
|
||||
trait Receiver {}
|
||||
|
|
@ -84,9 +90,9 @@ impl Copy for i128 {}
|
|||
impl Copy for f32 {}
|
||||
impl Copy for f64 {}
|
||||
impl Copy for char {}
|
||||
impl<'a, T: ?Sized> Copy for &'a T {}
|
||||
impl<T: ?Sized> Copy for *const T {}
|
||||
impl<T: ?Sized> Copy for *mut T {}
|
||||
impl<'a, T: PointeeSized> Copy for &'a T {}
|
||||
impl<T: PointeeSized> Copy for *const T {}
|
||||
impl<T: PointeeSized> Copy for *mut T {}
|
||||
|
||||
#[lang = "sync"]
|
||||
pub unsafe trait Sync {}
|
||||
|
|
@ -102,17 +108,17 @@ unsafe impl Sync for i16 {}
|
|||
unsafe impl Sync for i32 {}
|
||||
unsafe impl Sync for isize {}
|
||||
unsafe impl Sync for char {}
|
||||
unsafe impl<'a, T: ?Sized> Sync for &'a T {}
|
||||
unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
|
||||
unsafe impl Sync for [u8; 16] {}
|
||||
|
||||
#[lang = "freeze"]
|
||||
unsafe auto trait Freeze {}
|
||||
|
||||
unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
|
||||
unsafe impl<T: ?Sized> Freeze for *const T {}
|
||||
unsafe impl<T: ?Sized> Freeze for *mut T {}
|
||||
unsafe impl<T: ?Sized> Freeze for &T {}
|
||||
unsafe impl<T: ?Sized> Freeze for &mut T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for PhantomData<T> {}
|
||||
unsafe impl<T: PointeeSized> Freeze for *const T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for *mut T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for &T {}
|
||||
unsafe impl<T: PointeeSized> Freeze for &mut T {}
|
||||
|
||||
#[lang = "structural_peq"]
|
||||
pub trait StructuralPartialEq {}
|
||||
|
|
@ -456,7 +462,7 @@ pub enum Option<T> {
|
|||
pub use Option::*;
|
||||
|
||||
#[lang = "phantom_data"]
|
||||
pub struct PhantomData<T: ?Sized>;
|
||||
pub struct PhantomData<T: PointeeSized>;
|
||||
|
||||
#[lang = "fn_once"]
|
||||
#[rustc_paren_sugar]
|
||||
|
|
@ -576,18 +582,18 @@ impl Allocator for Global {}
|
|||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(1)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
pub struct NonNull<T: ?Sized>(pub *const T);
|
||||
pub struct NonNull<T: PointeeSized>(pub *const T);
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
|
||||
|
||||
pub struct Unique<T: ?Sized> {
|
||||
pub struct Unique<T: PointeeSized> {
|
||||
pub pointer: NonNull<T>,
|
||||
pub _marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
|
||||
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T: ?Sized, A: Allocator = Global>(Unique<T>, A);
|
||||
|
|
@ -655,9 +661,9 @@ pub mod intrinsics {
|
|||
#[rustc_intrinsic]
|
||||
pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub fn min_align_of<T>() -> usize;
|
||||
pub fn align_of<T>() -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
|
||||
#[rustc_intrinsic]
|
||||
pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
|
||||
#[rustc_intrinsic]
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ fn main() {
|
|||
let slice = &[0, 1] as &[i32];
|
||||
let slice_ptr = slice as *const [i32] as *const i32;
|
||||
|
||||
let align = intrinsics::min_align_of::<*const i32>();
|
||||
let align = intrinsics::align_of::<*const i32>();
|
||||
assert_eq!(slice_ptr as usize % align, 0);
|
||||
|
||||
//return;
|
||||
|
|
@ -194,8 +194,8 @@ fn main() {
|
|||
assert_eq!(intrinsics::size_of_val(a) as u8, 8);
|
||||
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
|
||||
|
||||
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
|
||||
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
|
||||
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
|
||||
|
||||
assert!(!intrinsics::needs_drop::<u8>());
|
||||
assert!(!intrinsics::needs_drop::<[u8]>());
|
||||
|
|
|
|||
|
|
@ -77,18 +77,18 @@ fn main() {
|
|||
assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
|
||||
|
||||
// Check that all u/i128 <-> float casts work correctly.
|
||||
let houndred_u128 = 100u128;
|
||||
let houndred_i128 = 100i128;
|
||||
let houndred_f32 = 100.0f32;
|
||||
let houndred_f64 = 100.0f64;
|
||||
assert_eq!(houndred_u128 as f32, 100.0);
|
||||
assert_eq!(houndred_u128 as f64, 100.0);
|
||||
assert_eq!(houndred_f32 as u128, 100);
|
||||
assert_eq!(houndred_f64 as u128, 100);
|
||||
assert_eq!(houndred_i128 as f32, 100.0);
|
||||
assert_eq!(houndred_i128 as f64, 100.0);
|
||||
assert_eq!(houndred_f32 as i128, 100);
|
||||
assert_eq!(houndred_f64 as i128, 100);
|
||||
let hundred_u128 = 100u128;
|
||||
let hundred_i128 = 100i128;
|
||||
let hundred_f32 = 100.0f32;
|
||||
let hundred_f64 = 100.0f64;
|
||||
assert_eq!(hundred_u128 as f32, 100.0);
|
||||
assert_eq!(hundred_u128 as f64, 100.0);
|
||||
assert_eq!(hundred_f32 as u128, 100);
|
||||
assert_eq!(hundred_f64 as u128, 100);
|
||||
assert_eq!(hundred_i128 as f32, 100.0);
|
||||
assert_eq!(hundred_i128 as f64, 100.0);
|
||||
assert_eq!(hundred_f32 as i128, 100);
|
||||
assert_eq!(hundred_f64 as i128, 100);
|
||||
|
||||
let _a = 1u32 << 2u8;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
From cdb3d407740e4f15c3746051f8ba89b8e74e99d3 Mon Sep 17 00:00:00 2001
|
||||
From: None <none@example.com>
|
||||
Date: Fri, 30 May 2025 13:46:22 -0400
|
||||
Subject: [PATCH] Pin compiler_builtins to 0.1.160
|
||||
|
||||
---
|
||||
library/alloc/Cargo.toml | 2 +-
|
||||
library/std/Cargo.toml | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
|
||||
index 9d0d957..365c9dc 100644
|
||||
--- a/library/alloc/Cargo.toml
|
||||
+++ b/library/alloc/Cargo.toml
|
||||
@@ -16,7 +16,7 @@ bench = false
|
||||
|
||||
[dependencies]
|
||||
core = { path = "../core", public = true }
|
||||
-compiler_builtins = { version = "=0.1.159", features = ['rustc-dep-of-std'] }
|
||||
+compiler_builtins = { version = "=0.1.160", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[features]
|
||||
compiler-builtins-mem = ['compiler_builtins/mem']
|
||||
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
|
||||
index 4ff4895..31371f0 100644
|
||||
--- a/library/std/Cargo.toml
|
||||
+++ b/library/std/Cargo.toml
|
||||
@@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
|
||||
panic_unwind = { path = "../panic_unwind", optional = true }
|
||||
panic_abort = { path = "../panic_abort" }
|
||||
core = { path = "../core", public = true }
|
||||
-compiler_builtins = { version = "=0.1.159" }
|
||||
+compiler_builtins = { version = "=0.1.160" }
|
||||
unwind = { path = "../unwind" }
|
||||
hashbrown = { version = "0.15", default-features = false, features = [
|
||||
'rustc-dep-of-std',
|
||||
--
|
||||
2.49.0
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
From a131c69e54b5c02fe3b517e8f3ad23d4f784ffc8 Mon Sep 17 00:00:00 2001
|
||||
From: Antoni Boucher <bouanto@zoho.com>
|
||||
Date: Fri, 13 Jun 2025 20:25:33 -0400
|
||||
Subject: [PATCH] Workaround to make a run-make test pass
|
||||
|
||||
---
|
||||
tests/run-make/linker-warning/rmake.rs | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
|
||||
index bc21739fefc..0946a7e2a48 100644
|
||||
--- a/tests/run-make/linker-warning/rmake.rs
|
||||
+++ b/tests/run-make/linker-warning/rmake.rs
|
||||
@@ -55,7 +55,7 @@ fn main() {
|
||||
diff()
|
||||
.expected_file("short-error.txt")
|
||||
.actual_text("(linker error)", out.stderr())
|
||||
- .normalize(r#"/rustc[^/]*/"#, "/rustc/")
|
||||
+ .normalize(r#"/tmp/rustc[^/]*/"#, "/tmp/rustc/")
|
||||
.normalize(
|
||||
regex::escape(run_make_support::build_root().to_str().unwrap()),
|
||||
"/build-root",
|
||||
--
|
||||
2.49.0
|
||||
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2025-05-12"
|
||||
channel = "nightly-2025-05-21"
|
||||
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen(
|
|||
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
|
||||
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
|
||||
|
||||
create_wrapper_function(tcx, context, &from_name, &to_name, &types, output);
|
||||
create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ pub(crate) unsafe fn codegen(
|
|||
tcx,
|
||||
context,
|
||||
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
|
||||
&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)),
|
||||
Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
|
||||
&[usize, usize],
|
||||
None,
|
||||
);
|
||||
|
|
@ -81,21 +81,21 @@ pub(crate) unsafe fn codegen(
|
|||
let value = context.new_rvalue_from_int(i8, value as i32);
|
||||
global.global_set_initializer_rvalue(value);
|
||||
|
||||
let name = mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE);
|
||||
let global = context.new_global(None, GlobalKind::Exported, i8, name);
|
||||
#[cfg(feature = "master")]
|
||||
global.add_attribute(VarAttribute::Visibility(symbol_visibility_to_gcc(
|
||||
tcx.sess.default_visibility(),
|
||||
)));
|
||||
let value = context.new_rvalue_from_int(i8, 0);
|
||||
global.global_set_initializer_rvalue(value);
|
||||
create_wrapper_function(
|
||||
tcx,
|
||||
context,
|
||||
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
|
||||
None,
|
||||
&[],
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
fn create_wrapper_function(
|
||||
tcx: TyCtxt<'_>,
|
||||
context: &Context<'_>,
|
||||
from_name: &str,
|
||||
to_name: &str,
|
||||
to_name: Option<&str>,
|
||||
types: &[Type<'_>],
|
||||
output: Option<Type<'_>>,
|
||||
) {
|
||||
|
|
@ -124,34 +124,40 @@ fn create_wrapper_function(
|
|||
// TODO(antoyo): emit unwind tables.
|
||||
}
|
||||
|
||||
let args: Vec<_> = types
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index)))
|
||||
.collect();
|
||||
let callee = context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
output.unwrap_or(void),
|
||||
&args,
|
||||
to_name,
|
||||
false,
|
||||
);
|
||||
#[cfg(feature = "master")]
|
||||
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||
|
||||
let block = func.new_block("entry");
|
||||
|
||||
let args = args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
|
||||
.collect::<Vec<_>>();
|
||||
let ret = context.new_call(None, callee, &args);
|
||||
//llvm::LLVMSetTailCall(ret, True);
|
||||
if output.is_some() {
|
||||
block.end_with_return(None, ret);
|
||||
if let Some(to_name) = to_name {
|
||||
let args: Vec<_> = types
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, typ)| context.new_parameter(None, *typ, format!("param{}", index)))
|
||||
.collect();
|
||||
let callee = context.new_function(
|
||||
None,
|
||||
FunctionType::Extern,
|
||||
output.unwrap_or(void),
|
||||
&args,
|
||||
to_name,
|
||||
false,
|
||||
);
|
||||
#[cfg(feature = "master")]
|
||||
callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
|
||||
|
||||
let args = args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| func.get_param(i as i32).to_rvalue())
|
||||
.collect::<Vec<_>>();
|
||||
let ret = context.new_call(None, callee, &args);
|
||||
//llvm::LLVMSetTailCall(ret, True);
|
||||
if output.is_some() {
|
||||
block.end_with_return(None, ret);
|
||||
} else {
|
||||
block.add_eval(None, ret);
|
||||
block.end_with_void_return(None);
|
||||
}
|
||||
} else {
|
||||
assert!(output.is_none());
|
||||
block.end_with_void_return(None);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// cSpell:ignoreRegExp [afkspqvwy]reg
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use gccjit::{LValue, RValue, ToRValue, Type};
|
||||
|
|
@ -138,7 +140,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
// `outputs.len() + inputs.len()`.
|
||||
let mut labels = vec![];
|
||||
|
||||
// Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
|
||||
// Clobbers collected from `out("explicit register") _` and `inout("explicit_reg") var => _`
|
||||
let mut clobbers = vec![];
|
||||
|
||||
// We're trying to preallocate space for the template
|
||||
|
|
@ -203,7 +205,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
// is also used as an in register, do not add it to the clobbers list.
|
||||
// it will be treated as a lateout register with `out_place: None`
|
||||
if !late {
|
||||
bug!("input registers can only be used as lateout regisers");
|
||||
bug!("input registers can only be used as lateout registers");
|
||||
}
|
||||
("r", dummy_output_type(self.cx, reg.reg_class()))
|
||||
} else {
|
||||
|
|
@ -641,7 +643,8 @@ fn explicit_reg_to_gcc(reg: InlineAsmReg) -> &'static str {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
InlineAsmReg::Arm(reg) => reg.name(),
|
||||
InlineAsmReg::AArch64(reg) => reg.name(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::gcc_util::to_gcc_features;
|
|||
/// Checks if the function `instance` is recursively inline.
|
||||
/// Returns `false` if a functions is guaranteed to be non-recursive, and `true` if it *might* be recursive.
|
||||
#[cfg(feature = "master")]
|
||||
fn resursively_inline<'gcc, 'tcx>(
|
||||
fn recursively_inline<'gcc, 'tcx>(
|
||||
cx: &CodegenCx<'gcc, 'tcx>,
|
||||
instance: ty::Instance<'tcx>,
|
||||
) -> bool {
|
||||
|
|
@ -61,7 +61,7 @@ fn inline_attr<'gcc, 'tcx>(
|
|||
//
|
||||
// That prevents issues steming from recursive `#[inline(always)]` at a *relatively* small cost.
|
||||
// We *only* need to check all the terminators of a function marked with this attribute.
|
||||
if resursively_inline(cx, instance) {
|
||||
if recursively_inline(cx, instance) {
|
||||
Some(FnAttribute::Inline)
|
||||
} else {
|
||||
Some(FnAttribute::AlwaysInline)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue