Merge from rust-lang/rust
This commit is contained in:
commit
96e1d731ee
2305 changed files with 30472 additions and 16390 deletions
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
|
|
@ -11,6 +11,10 @@ name: CI
|
|||
on:
|
||||
push:
|
||||
branches:
|
||||
# CI on master only serves for caching citool builds for the `calculate_matrix` job.
|
||||
# In order to use GHA cache on PR CI (and auto/try) jobs, we need to write to it
|
||||
# from the default branch.
|
||||
- master
|
||||
- auto
|
||||
- try
|
||||
- try-perf
|
||||
|
|
@ -60,12 +64,18 @@ jobs:
|
|||
uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
|
||||
with:
|
||||
workspaces: src/ci/citool
|
||||
- name: Test citool
|
||||
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
|
||||
# on PR/try builds.
|
||||
if: ${{ github.ref == 'refs/heads/auto' }}
|
||||
run: |
|
||||
cd src/ci/citool
|
||||
CARGO_INCREMENTAL=0 cargo test
|
||||
- name: Calculate the CI job matrix
|
||||
env:
|
||||
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
||||
run: |
|
||||
cd src/ci/citool
|
||||
CARGO_INCREMENTAL=0 cargo test
|
||||
CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT
|
||||
id: jobs
|
||||
job:
|
||||
|
|
|
|||
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>
|
||||
|
|
|
|||
287
Cargo.lock
287
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",
|
||||
|
|
@ -2326,7 +2326,6 @@ dependencies = [
|
|||
"tempfile",
|
||||
"tikv-jemalloc-sys",
|
||||
"ui_test",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2464,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",
|
||||
|
|
@ -2539,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"
|
||||
|
|
@ -2559,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",
|
||||
|
|
@ -2612,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"
|
||||
|
|
@ -2638,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",
|
||||
|
|
@ -2648,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",
|
||||
|
|
@ -2803,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"
|
||||
|
|
@ -3130,11 +3135,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc-build-sysroot"
|
||||
version = "0.5.7"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10edc2e4393515193bd766e2f6c050b0536a68e56f2b6d56c07ababfdc114ff0"
|
||||
checksum = "16d115ad7e26e0d1337f64ae6598f758194696afc2e9f34c8a6f24582529c3dc"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"tempfile",
|
||||
"walkdir",
|
||||
|
|
@ -3228,9 +3234,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustc_apfloat"
|
||||
version = "0.2.2+llvm-462a31f5a5ab"
|
||||
version = "0.2.3+llvm-462a31f5a5ab"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f"
|
||||
checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"smallvec",
|
||||
|
|
@ -3787,6 +3793,7 @@ dependencies = [
|
|||
"rustc_arena",
|
||||
"rustc_ast",
|
||||
"rustc_attr_data_structures",
|
||||
"rustc_attr_parsing",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_feature",
|
||||
|
|
@ -4611,7 +4618,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 +4775,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.20"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
|
||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
||||
|
||||
[[package]]
|
||||
name = "ruzstd"
|
||||
|
|
@ -4866,9 +4873,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -4933,15 +4940,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.0"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.9"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
|
|
@ -5111,9 +5118,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.35.0"
|
||||
version = "0.35.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422"
|
||||
checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"objc2-core-foundation",
|
||||
|
|
@ -5354,9 +5361,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.45.0"
|
||||
version = "1.45.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
|
||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
|
|
@ -5386,9 +5393,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.9"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
|
@ -5420,9 +5427,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.28"
|
||||
version = "0.1.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
||||
checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -5504,11 +5511,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "type-map"
|
||||
version = "0.5.0"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f"
|
||||
checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
|
||||
dependencies = [
|
||||
"rustc-hash 1.1.0",
|
||||
"rustc-hash 2.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5729,11 +5736,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
|
||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5892,12 +5901,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.230.0"
|
||||
version = "0.233.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4349d0943718e6e434b51b9639e876293093dca4b96384fb136ab5bd5ce6660"
|
||||
checksum = "9679ae3cf7cfa2ca3a327f7fab97f27f3294d402fd1a76ca8ab514e17973e4d3"
|
||||
dependencies = [
|
||||
"leb128fmt",
|
||||
"wasmparser 0.230.0",
|
||||
"wasmparser 0.233.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -5935,17 +5944,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.230.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "808198a69b5a0535583370a51d459baa14261dfab04800c4864ee9e1a14346ed"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.232.0"
|
||||
|
|
@ -5956,23 +5954,34 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "230.0.0"
|
||||
name = "wasmparser"
|
||||
version = "0.233.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8edac03c5fa691551531533928443faf3dc61a44f814a235c7ec5d17b7b34f1"
|
||||
checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "233.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eaf4099d8d0c922b83bf3c90663f5666f0769db9e525184284ebbbdb1dd2180"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"leb128fmt",
|
||||
"memchr",
|
||||
"unicode-width 0.2.0",
|
||||
"wasm-encoder 0.230.0",
|
||||
"wasm-encoder 0.233.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wat"
|
||||
version = "1.230.0"
|
||||
version = "1.233.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d77d62229e38db83eac32bacb5f61ebb952366ab0dae90cf2b3c07a65eea894"
|
||||
checksum = "3d9bc80f5e4b25ea086ef41b91ccd244adde45d931c384d94a8ff64ab8bd7d87"
|
||||
dependencies = [
|
||||
"wast",
|
||||
]
|
||||
|
|
@ -6033,13 +6042,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.61.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90"
|
||||
checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231"
|
||||
dependencies = [
|
||||
"rayon",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6053,9 +6062,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.61.0"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
|
|
@ -6066,12 +6075,13 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
|
||||
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
|
||||
dependencies = [
|
||||
"windows-core",
|
||||
"windows-link",
|
||||
"windows-threading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6114,18 +6124,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.2"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
|
||||
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.0"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
|
@ -6204,6 +6214,15 @@ dependencies = [
|
|||
"windows_x86_64_msvc 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-threading"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.48.5"
|
||||
|
|
|
|||
|
|
@ -381,6 +381,15 @@
|
|||
# "miri", "cargo-miri" # for dev/nightly channels
|
||||
#]
|
||||
|
||||
# Specify build configuration specific for some tool, such as enabled features.
|
||||
# This option has no effect on which tools are enabled: refer to the `tools` option for that.
|
||||
#
|
||||
# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]`
|
||||
#
|
||||
# The default value for the `features` array is `[]`. However, please note that other flags in
|
||||
# `bootstrap.toml` might influence the features enabled for some tools.
|
||||
#tool.TOOL_NAME.features = [FEATURE1, FEATURE2]
|
||||
|
||||
# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
|
||||
#verbose = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ pub enum CanonAbi {
|
|||
Rust,
|
||||
RustCold,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
||||
/// ABIs relevant to 32-bit Arm targets
|
||||
Arm(ArmCall),
|
||||
/// ABI relevant to GPUs: the entry point for a GPU kernel
|
||||
|
|
@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ pub enum ExternAbi {
|
|||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define. Functions with this ABI can
|
||||
/// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
|
||||
/// be called from inline assembly.
|
||||
Custom,
|
||||
|
||||
/// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
|
||||
/// and only valid on platforms that have a UEFI standard
|
||||
EfiApi,
|
||||
|
|
@ -141,6 +146,7 @@ abi_impls! {
|
|||
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
|
||||
Cdecl { unwind: false } =><= "cdecl",
|
||||
Cdecl { unwind: true } =><= "cdecl-unwind",
|
||||
Custom =><= "custom",
|
||||
EfiApi =><= "efiapi",
|
||||
Fastcall { unwind: false } =><= "fastcall",
|
||||
Fastcall { unwind: true } =><= "fastcall-unwind",
|
||||
|
|
|
|||
|
|
@ -97,12 +97,12 @@ pub struct Path {
|
|||
pub tokens: Option<LazyAttrTokenStream>,
|
||||
}
|
||||
|
||||
// Succeeds if the path has a single segment that is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
if let [segment] = self.segments.as_ref()
|
||||
&& segment.args.is_none()
|
||||
&& segment.ident.name == *name
|
||||
&& segment == name
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
|
@ -111,6 +111,15 @@ impl PartialEq<Symbol> for Path {
|
|||
}
|
||||
}
|
||||
|
||||
// Succeeds if the path has segments that are arg-free and match the given symbols.
|
||||
impl PartialEq<&[Symbol]> for Path {
|
||||
#[inline]
|
||||
fn eq(&self, names: &&[Symbol]) -> bool {
|
||||
self.segments.len() == names.len()
|
||||
&& self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2)
|
||||
}
|
||||
}
|
||||
|
||||
impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
self.segments.len().hash_stable(hcx, hasher);
|
||||
|
|
@ -166,6 +175,14 @@ pub struct PathSegment {
|
|||
pub args: Option<P<GenericArgs>>,
|
||||
}
|
||||
|
||||
// Succeeds if the path segment is arg-free and matches the given symbol.
|
||||
impl PartialEq<Symbol> for PathSegment {
|
||||
#[inline]
|
||||
fn eq(&self, name: &Symbol) -> bool {
|
||||
self.args.is_none() && self.ident.name == *name
|
||||
}
|
||||
}
|
||||
|
||||
impl PathSegment {
|
||||
pub fn from_ident(ident: Ident) -> Self {
|
||||
PathSegment { ident, id: DUMMY_NODE_ID, args: None }
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use std::ops::DerefMut;
|
|||
use std::panic;
|
||||
|
||||
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::{Ident, Span};
|
||||
use smallvec::{Array, SmallVec, smallvec};
|
||||
use thin_vec::ThinVec;
|
||||
|
|
@ -19,7 +19,7 @@ use thin_vec::ThinVec;
|
|||
use crate::ast::*;
|
||||
use crate::ptr::P;
|
||||
use crate::tokenstream::*;
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit, visit_opt, walk_list};
|
||||
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list};
|
||||
|
||||
pub trait ExpectOne<A: Array> {
|
||||
fn expect_one(self, err: &'static str) -> A::Item;
|
||||
|
|
@ -32,7 +32,22 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait MutVisitor: Sized {
|
||||
mod sealed {
|
||||
use rustc_ast_ir::visit::VisitorResult;
|
||||
|
||||
/// This is for compatibility with the regular `Visitor`.
|
||||
pub trait MutVisitorResult {
|
||||
type Result: VisitorResult;
|
||||
}
|
||||
|
||||
impl<T> MutVisitorResult for T {
|
||||
type Result = ();
|
||||
}
|
||||
}
|
||||
|
||||
use sealed::MutVisitorResult;
|
||||
|
||||
pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
|
||||
// Methods in this trait have one of three forms:
|
||||
//
|
||||
// fn visit_t(&mut self, t: &mut T); // common
|
||||
|
|
@ -153,7 +168,7 @@ pub trait MutVisitor: Sized {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +176,7 @@ pub trait MutVisitor: Sized {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +194,7 @@ pub trait MutVisitor: Sized {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
@ -227,14 +242,6 @@ pub trait MutVisitor: Sized {
|
|||
walk_generic_args(self, p);
|
||||
}
|
||||
|
||||
fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) {
|
||||
walk_angle_bracketed_parameter_data(self, p);
|
||||
}
|
||||
|
||||
fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) {
|
||||
walk_parenthesized_parameter_data(self, p);
|
||||
}
|
||||
|
||||
fn visit_local(&mut self, l: &mut Local) {
|
||||
walk_local(self, l);
|
||||
}
|
||||
|
|
@ -303,10 +310,6 @@ pub trait MutVisitor: Sized {
|
|||
walk_flat_map_expr_field(self, f)
|
||||
}
|
||||
|
||||
fn visit_where_clause(&mut self, where_clause: &mut WhereClause) {
|
||||
walk_where_clause(self, where_clause);
|
||||
}
|
||||
|
||||
fn flat_map_where_predicate(
|
||||
&mut self,
|
||||
where_predicate: WherePredicate,
|
||||
|
|
@ -385,19 +388,14 @@ generate_flat_map_visitor_fns! {
|
|||
visit_generic_params, GenericParam, flat_map_generic_param;
|
||||
visit_stmts, Stmt, flat_map_stmt;
|
||||
visit_exprs, P<Expr>, filter_map_expr;
|
||||
visit_expr_fields, ExprField, flat_map_expr_field;
|
||||
visit_pat_fields, PatField, flat_map_pat_field;
|
||||
visit_variants, Variant, flat_map_variant;
|
||||
visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F)
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
for elem in elems {
|
||||
visit_elem(elem);
|
||||
}
|
||||
visit_where_predicates, WherePredicate, flat_map_where_predicate;
|
||||
visit_params, Param, flat_map_param;
|
||||
visit_field_defs, FieldDef, flat_map_field_def;
|
||||
visit_arms, Arm, flat_map_arm;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -410,40 +408,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F)
|
||||
where
|
||||
F: FnMut(&mut T),
|
||||
{
|
||||
if let Some(elem) = opt {
|
||||
visit_elem(elem);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) {
|
||||
for attr in attrs.iter_mut() {
|
||||
vis.visit_attribute(attr);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
|
||||
match args {
|
||||
AttrArgs::Empty => {}
|
||||
AttrArgs::Delimited(args) => visit_delim_args(vis, args),
|
||||
AttrArgs::Eq { eq_span, expr } => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_span(eq_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) {
|
||||
let DelimArgs { dspan, delim: _, tokens: _ } = args;
|
||||
let DelimSpan { open, close } = dspan;
|
||||
vis.visit_span(open);
|
||||
vis.visit_span(close);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_pat_field<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut fp: PatField,
|
||||
|
|
@ -461,40 +431,11 @@ fn visit_nested_use_tree<V: MutVisitor>(
|
|||
vis.visit_use_tree(nested_tree);
|
||||
}
|
||||
|
||||
pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) {
|
||||
let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_pat(pat);
|
||||
visit_opt(guard, |guard| vis.visit_expr(guard));
|
||||
visit_opt(body, |body| vis.visit_expr(body));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
|
||||
vis.visit_arm(&mut arm);
|
||||
smallvec![arm]
|
||||
}
|
||||
|
||||
fn walk_assoc_item_constraint<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint,
|
||||
) {
|
||||
vis.visit_id(id);
|
||||
vis.visit_ident(ident);
|
||||
if let Some(gen_args) = gen_args {
|
||||
vis.visit_generic_args(gen_args);
|
||||
}
|
||||
match kind {
|
||||
AssocItemConstraintKind::Equality { term } => match term {
|
||||
Term::Ty(ty) => vis.visit_ty(ty),
|
||||
Term::Const(c) => vis.visit_anon_const(c),
|
||||
},
|
||||
AssocItemConstraintKind::Bound { bounds } => visit_bounds(vis, bounds, BoundKind::Bound),
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_variant<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut variant: Variant,
|
||||
|
|
@ -503,64 +444,6 @@ pub fn walk_flat_map_variant<T: MutVisitor>(
|
|||
smallvec![variant]
|
||||
}
|
||||
|
||||
fn walk_generic_args<T: MutVisitor>(vis: &mut T, generic_args: &mut GenericArgs) {
|
||||
match generic_args {
|
||||
GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
|
||||
GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
|
||||
GenericArgs::ParenthesizedElided(span) => vis.visit_span(span),
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_generic_arg<T: MutVisitor>(vis: &mut T, arg: &mut GenericArg) {
|
||||
match arg {
|
||||
GenericArg::Lifetime(lt) => vis.visit_lifetime(lt),
|
||||
GenericArg::Type(ty) => vis.visit_ty(ty),
|
||||
GenericArg::Const(ct) => vis.visit_anon_const(ct),
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut AngleBracketedArgs) {
|
||||
let AngleBracketedArgs { args, span } = data;
|
||||
visit_thin_vec(args, |arg| match arg {
|
||||
AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
|
||||
AngleBracketedArg::Constraint(constraint) => vis.visit_assoc_item_constraint(constraint),
|
||||
});
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
|
||||
let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
|
||||
visit_thin_vec(inputs, |input| vis.visit_ty(input));
|
||||
vis.visit_fn_ret_ty(output);
|
||||
vis.visit_span(span);
|
||||
vis.visit_span(inputs_span);
|
||||
}
|
||||
|
||||
fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
|
||||
let Attribute { kind, id: _, style: _, span } = attr;
|
||||
match kind {
|
||||
AttrKind::Normal(normal) => {
|
||||
let NormalAttr { item: AttrItem { unsafety: _, path, args, tokens: _ }, tokens: _ } =
|
||||
&mut **normal;
|
||||
vis.visit_path(path);
|
||||
visit_attr_args(vis, args);
|
||||
}
|
||||
AttrKind::DocComment(_kind, _sym) => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_mac<T: MutVisitor>(vis: &mut T, mac: &mut MacCall) {
|
||||
let MacCall { path, args } = mac;
|
||||
vis.visit_path(path);
|
||||
visit_delim_args(vis, args);
|
||||
}
|
||||
|
||||
fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) {
|
||||
let MacroDef { body, macro_rules: _ } = macro_def;
|
||||
visit_delim_args(vis, body);
|
||||
}
|
||||
|
||||
fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut MetaItemInner) {
|
||||
match li {
|
||||
MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi),
|
||||
|
|
@ -578,138 +461,11 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
|
|||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) {
|
||||
let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_ty(ty);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
|
||||
vis.visit_param(&mut param);
|
||||
smallvec![param]
|
||||
}
|
||||
|
||||
fn walk_closure_binder<T: MutVisitor>(vis: &mut T, binder: &mut ClosureBinder) {
|
||||
match binder {
|
||||
ClosureBinder::NotPresent => {}
|
||||
ClosureBinder::For { span: _, generic_params } => {
|
||||
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
|
||||
match kind {
|
||||
FnKind::Fn(
|
||||
_ctxt,
|
||||
_vis,
|
||||
Fn {
|
||||
defaultness,
|
||||
ident,
|
||||
generics,
|
||||
contract,
|
||||
body,
|
||||
sig: FnSig { header, decl, span },
|
||||
define_opaque,
|
||||
},
|
||||
) => {
|
||||
// Visibility is visited as a part of the item.
|
||||
visit_defaultness(vis, defaultness);
|
||||
vis.visit_ident(ident);
|
||||
vis.visit_fn_header(header);
|
||||
vis.visit_generics(generics);
|
||||
vis.visit_fn_decl(decl);
|
||||
if let Some(contract) = contract {
|
||||
vis.visit_contract(contract);
|
||||
}
|
||||
if let Some(body) = body {
|
||||
vis.visit_block(body);
|
||||
}
|
||||
vis.visit_span(span);
|
||||
|
||||
walk_define_opaques(vis, define_opaque);
|
||||
}
|
||||
FnKind::Closure(binder, coroutine_kind, decl, body) => {
|
||||
vis.visit_closure_binder(binder);
|
||||
coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
|
||||
vis.visit_fn_decl(decl);
|
||||
vis.visit_expr(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut FnContract) {
|
||||
let FnContract { requires, ensures } = contract;
|
||||
if let Some(pred) = requires {
|
||||
vis.visit_expr(pred);
|
||||
}
|
||||
if let Some(pred) = ensures {
|
||||
vis.visit_expr(pred);
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut FnDecl) {
|
||||
let FnDecl { inputs, output } = decl;
|
||||
inputs.flat_map_in_place(|param| vis.flat_map_param(param));
|
||||
vis.visit_fn_ret_ty(output);
|
||||
}
|
||||
|
||||
fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
|
||||
match fn_ret_ty {
|
||||
FnRetTy::Default(span) => vis.visit_span(span),
|
||||
FnRetTy::Ty(ty) => vis.visit_ty(ty),
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_param_bound<T: MutVisitor>(vis: &mut T, pb: &mut GenericBound) {
|
||||
match pb {
|
||||
GenericBound::Trait(trait_ref) => vis.visit_poly_trait_ref(trait_ref),
|
||||
GenericBound::Outlives(lifetime) => walk_lifetime(vis, lifetime),
|
||||
GenericBound::Use(args, span) => {
|
||||
for arg in args {
|
||||
vis.visit_precise_capturing_arg(arg);
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCapturingArg) {
|
||||
match arg {
|
||||
PreciseCapturingArg::Lifetime(lt) => {
|
||||
vis.visit_lifetime(lt);
|
||||
}
|
||||
PreciseCapturingArg::Arg(path, id) => {
|
||||
vis.visit_id(id);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) {
|
||||
let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_ident(ident);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
match kind {
|
||||
GenericParamKind::Lifetime => {}
|
||||
GenericParamKind::Type { default } => {
|
||||
visit_opt(default, |default| vis.visit_ty(default));
|
||||
}
|
||||
GenericParamKind::Const { ty, kw_span: _, default } => {
|
||||
vis.visit_ty(ty);
|
||||
visit_opt(default, |default| vis.visit_anon_const(default));
|
||||
}
|
||||
}
|
||||
if let Some(colon_span) = colon_span {
|
||||
vis.visit_span(colon_span);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_generic_param<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut param: GenericParam,
|
||||
|
|
@ -718,13 +474,6 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>(
|
|||
smallvec![param]
|
||||
}
|
||||
|
||||
fn walk_generics<T: MutVisitor>(vis: &mut T, generics: &mut Generics) {
|
||||
let Generics { params, where_clause, span } = generics;
|
||||
params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_where_clause(where_clause);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) {
|
||||
let TyAliasWhereClauses { before, after, split: _ } = tawcs;
|
||||
let TyAliasWhereClause { has_where_token: _, span: span_before } = before;
|
||||
|
|
@ -733,70 +482,14 @@ fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWh
|
|||
vis.visit_span(span_after);
|
||||
}
|
||||
|
||||
fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) {
|
||||
let WhereClause { has_where_token: _, predicates, span } = wc;
|
||||
predicates.flat_map_in_place(|predicate| vis.flat_map_where_predicate(predicate));
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_where_predicate<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut pred: WherePredicate,
|
||||
) -> SmallVec<[WherePredicate; 1]> {
|
||||
let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = &mut pred;
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
vis.visit_where_predicate_kind(kind);
|
||||
vis.visit_span(span);
|
||||
walk_where_predicate(vis, &mut pred);
|
||||
smallvec![pred]
|
||||
}
|
||||
|
||||
pub fn walk_where_predicate_kind<T: MutVisitor>(vis: &mut T, kind: &mut WherePredicateKind) {
|
||||
match kind {
|
||||
WherePredicateKind::BoundPredicate(bp) => {
|
||||
let WhereBoundPredicate { bound_generic_params, bounded_ty, bounds } = bp;
|
||||
bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
|
||||
vis.visit_ty(bounded_ty);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
}
|
||||
WherePredicateKind::RegionPredicate(rp) => {
|
||||
let WhereRegionPredicate { lifetime, bounds } = rp;
|
||||
vis.visit_lifetime(lifetime);
|
||||
visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
|
||||
}
|
||||
WherePredicateKind::EqPredicate(ep) => {
|
||||
let WhereEqPredicate { lhs_ty, rhs_ty } = ep;
|
||||
vis.visit_ty(lhs_ty);
|
||||
vis.visit_ty(rhs_ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_variant_data<T: MutVisitor>(vis: &mut T, vdata: &mut VariantData) {
|
||||
match vdata {
|
||||
VariantData::Struct { fields, recovered: _ } => {
|
||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||
}
|
||||
VariantData::Tuple(fields, id) => {
|
||||
vis.visit_id(id);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
|
||||
}
|
||||
VariantData::Unit(id) => vis.visit_id(id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
|
||||
let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd;
|
||||
visitor.visit_id(id);
|
||||
visit_attrs(visitor, attrs);
|
||||
visitor.visit_vis(vis);
|
||||
visit_safety(visitor, safety);
|
||||
visit_opt(ident, |ident| visitor.visit_ident(ident));
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(default, |default| visitor.visit_anon_const(default));
|
||||
visitor.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_flat_map_field_def<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
mut fd: FieldDef,
|
||||
|
|
@ -846,255 +539,6 @@ pub fn walk_flat_map_assoc_item(
|
|||
smallvec![item]
|
||||
}
|
||||
|
||||
fn walk_inline_asm<T: MutVisitor>(vis: &mut T, asm: &mut InlineAsm) {
|
||||
// FIXME: Visit spans inside all this currently ignored stuff.
|
||||
let InlineAsm {
|
||||
asm_macro: _,
|
||||
template: _,
|
||||
template_strs: _,
|
||||
operands,
|
||||
clobber_abis: _,
|
||||
options: _,
|
||||
line_spans: _,
|
||||
} = asm;
|
||||
for (op, span) in operands {
|
||||
match op {
|
||||
InlineAsmOperand::In { expr, reg: _ }
|
||||
| InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
|
||||
| InlineAsmOperand::InOut { expr, reg: _, late: _ } => vis.visit_expr(expr),
|
||||
InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
|
||||
InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
|
||||
vis.visit_expr(in_expr);
|
||||
if let Some(out_expr) = out_expr {
|
||||
vis.visit_expr(out_expr);
|
||||
}
|
||||
}
|
||||
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
|
||||
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
|
||||
InlineAsmOperand::Label { block } => vis.visit_block(block),
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
}
|
||||
|
||||
fn walk_inline_asm_sym<T: MutVisitor>(
|
||||
vis: &mut T,
|
||||
InlineAsmSym { id, qself, path }: &mut InlineAsmSym,
|
||||
) {
|
||||
vis.visit_id(id);
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
|
||||
fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) {
|
||||
// FIXME: visit the template exhaustively.
|
||||
let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt;
|
||||
for FormatArgument { kind, expr } in arguments.all_args_mut() {
|
||||
match kind {
|
||||
FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
|
||||
vis.visit_ident(ident)
|
||||
}
|
||||
FormatArgumentKind::Normal => {}
|
||||
}
|
||||
vis.visit_expr(expr);
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, tokens: _ }: &mut Expr) {
|
||||
vis.visit_id(id);
|
||||
visit_attrs(vis, attrs);
|
||||
match kind {
|
||||
ExprKind::Array(exprs) => visit_exprs(vis, exprs),
|
||||
ExprKind::ConstBlock(anon_const) => {
|
||||
vis.visit_anon_const(anon_const);
|
||||
}
|
||||
ExprKind::Repeat(expr, count) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_anon_const(count);
|
||||
}
|
||||
ExprKind::Tup(exprs) => visit_exprs(vis, exprs),
|
||||
ExprKind::Call(f, args) => {
|
||||
vis.visit_expr(f);
|
||||
visit_exprs(vis, args);
|
||||
}
|
||||
ExprKind::MethodCall(box MethodCall {
|
||||
seg: PathSegment { ident, id, args: seg_args },
|
||||
receiver,
|
||||
args: call_args,
|
||||
span,
|
||||
}) => {
|
||||
vis.visit_method_receiver_expr(receiver);
|
||||
vis.visit_id(id);
|
||||
vis.visit_ident(ident);
|
||||
visit_opt(seg_args, |args| vis.visit_generic_args(args));
|
||||
visit_exprs(vis, call_args);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Binary(binop, lhs, rhs) => {
|
||||
vis.visit_expr(lhs);
|
||||
vis.visit_expr(rhs);
|
||||
vis.visit_span(&mut binop.span);
|
||||
}
|
||||
ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::Cast(expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
ExprKind::Type(expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
ExprKind::AddrOf(_kind, _mut, ohs) => vis.visit_expr(ohs),
|
||||
ExprKind::Let(pat, scrutinee, span, _recovered) => {
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_expr(scrutinee);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::If(cond, tr, fl) => {
|
||||
vis.visit_expr(cond);
|
||||
vis.visit_block(tr);
|
||||
visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl)));
|
||||
}
|
||||
ExprKind::While(cond, body, label) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_expr(cond);
|
||||
vis.visit_block(body);
|
||||
}
|
||||
ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_pat(pat);
|
||||
vis.visit_expr(iter);
|
||||
vis.visit_block(body);
|
||||
}
|
||||
ExprKind::Loop(body, label, span) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_block(body);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::Match(expr, arms, _kind) => {
|
||||
vis.visit_expr(expr);
|
||||
arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
|
||||
}
|
||||
ExprKind::Closure(box Closure {
|
||||
binder,
|
||||
capture_clause,
|
||||
constness,
|
||||
coroutine_kind,
|
||||
movability: _,
|
||||
fn_decl,
|
||||
body,
|
||||
fn_decl_span,
|
||||
fn_arg_span,
|
||||
}) => {
|
||||
visit_constness(vis, constness);
|
||||
vis.visit_capture_by(capture_clause);
|
||||
vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
|
||||
vis.visit_span(fn_decl_span);
|
||||
vis.visit_span(fn_arg_span);
|
||||
}
|
||||
ExprKind::Block(blk, label) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
vis.visit_block(blk);
|
||||
}
|
||||
ExprKind::Gen(_capture_by, body, _kind, decl_span) => {
|
||||
vis.visit_block(body);
|
||||
vis.visit_span(decl_span);
|
||||
}
|
||||
ExprKind::Await(expr, await_kw_span) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_span(await_kw_span);
|
||||
}
|
||||
ExprKind::Use(expr, use_kw_span) => {
|
||||
vis.visit_expr(expr);
|
||||
vis.visit_span(use_kw_span);
|
||||
}
|
||||
ExprKind::Assign(el, er, span) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_expr(er);
|
||||
vis.visit_span(span);
|
||||
}
|
||||
ExprKind::AssignOp(_op, el, er) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_expr(er);
|
||||
}
|
||||
ExprKind::Field(el, ident) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_ident(ident);
|
||||
}
|
||||
ExprKind::Index(el, er, brackets_span) => {
|
||||
vis.visit_expr(el);
|
||||
vis.visit_expr(er);
|
||||
vis.visit_span(brackets_span);
|
||||
}
|
||||
ExprKind::Range(e1, e2, _lim) => {
|
||||
visit_opt(e1, |e1| vis.visit_expr(e1));
|
||||
visit_opt(e2, |e2| vis.visit_expr(e2));
|
||||
}
|
||||
ExprKind::Underscore => {}
|
||||
ExprKind::Path(qself, path) => {
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
ExprKind::Break(label, expr) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::Continue(label) => {
|
||||
visit_opt(label, |label| vis.visit_label(label));
|
||||
}
|
||||
ExprKind::Ret(expr) => {
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::Yeet(expr) => {
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::Become(expr) => vis.visit_expr(expr),
|
||||
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
|
||||
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
|
||||
ExprKind::OffsetOf(container, fields) => {
|
||||
vis.visit_ty(container);
|
||||
for field in fields.iter_mut() {
|
||||
vis.visit_ident(field);
|
||||
}
|
||||
}
|
||||
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
ExprKind::Struct(se) => {
|
||||
let StructExpr { qself, path, fields, rest } = se.deref_mut();
|
||||
vis.visit_qself(qself);
|
||||
vis.visit_path(path);
|
||||
fields.flat_map_in_place(|field| vis.flat_map_expr_field(field));
|
||||
match rest {
|
||||
StructRest::Base(expr) => vis.visit_expr(expr),
|
||||
StructRest::Rest(_span) => {}
|
||||
StructRest::None => {}
|
||||
}
|
||||
}
|
||||
ExprKind::Paren(expr) => {
|
||||
vis.visit_expr(expr);
|
||||
}
|
||||
ExprKind::Yield(kind) => {
|
||||
let expr = kind.expr_mut();
|
||||
if let Some(expr) = expr {
|
||||
vis.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
ExprKind::Try(expr) => vis.visit_expr(expr),
|
||||
ExprKind::TryBlock(body) => vis.visit_block(body),
|
||||
ExprKind::Lit(_token) => {}
|
||||
ExprKind::IncludedBytes(_bytes) => {}
|
||||
ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
|
||||
vis.visit_expr(expr);
|
||||
if let Some(ty) = ty {
|
||||
vis.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
ExprKind::Err(_guar) => {}
|
||||
ExprKind::Dummy => {}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
|
||||
vis.visit_expr(&mut e);
|
||||
Some(e)
|
||||
|
|
@ -1139,18 +583,6 @@ fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallV
|
|||
}
|
||||
}
|
||||
|
||||
fn walk_vis<T: MutVisitor>(vis: &mut T, visibility: &mut Visibility) {
|
||||
let Visibility { kind, span, tokens: _ } = visibility;
|
||||
match kind {
|
||||
VisibilityKind::Public | VisibilityKind::Inherited => {}
|
||||
VisibilityKind::Restricted { path, id, shorthand: _ } => {
|
||||
vis.visit_id(id);
|
||||
vis.visit_path(path);
|
||||
}
|
||||
}
|
||||
vis.visit_span(span);
|
||||
}
|
||||
|
||||
fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
|
||||
match capture_by {
|
||||
CaptureBy::Ref => {}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -179,6 +179,8 @@ 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
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
|
|||
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
|
||||
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
|
||||
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::lints::DelayedLint;
|
||||
use rustc_hir::{
|
||||
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
|
||||
LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
|
||||
|
|
@ -141,6 +142,8 @@ struct LoweringContext<'a, 'hir> {
|
|||
allow_for_await: Arc<[Symbol]>,
|
||||
allow_async_fn_traits: Arc<[Symbol]>,
|
||||
|
||||
delayed_lints: Vec<DelayedLint>,
|
||||
|
||||
attribute_parser: AttributeParser<'hir>,
|
||||
}
|
||||
|
||||
|
|
@ -190,6 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
|
||||
|
||||
attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
|
||||
delayed_lints: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -198,6 +202,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
struct SpanLowerer {
|
||||
is_incremental: bool,
|
||||
def_id: LocalDefId,
|
||||
}
|
||||
|
||||
impl SpanLowerer {
|
||||
fn lower(&self, span: Span) -> Span {
|
||||
if self.is_incremental {
|
||||
span.with_parent(Some(self.def_id))
|
||||
} else {
|
||||
// Do not make spans relative when not using incremental compilation.
|
||||
span
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[extension(trait ResolverAstLoweringExt)]
|
||||
impl ResolverAstLowering {
|
||||
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
|
||||
|
|
@ -503,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
span: Span,
|
||||
) -> LocalDefId {
|
||||
let parent = self.current_hir_id_owner.def_id;
|
||||
debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
|
||||
assert_ne!(node_id, ast::DUMMY_NODE_ID);
|
||||
assert!(
|
||||
self.opt_local_def_id(node_id).is_none(),
|
||||
"adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}",
|
||||
|
|
@ -573,6 +593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
|
||||
let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
|
||||
let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
|
||||
let current_delayed_lints = std::mem::take(&mut self.delayed_lints);
|
||||
|
||||
// Do not reset `next_node_id` and `node_id_to_def_id`:
|
||||
// we want `f` to be able to refer to the `LocalDefId`s that the caller created.
|
||||
|
|
@ -586,10 +607,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
|
||||
let item = f(self);
|
||||
debug_assert_eq!(owner_id, item.def_id());
|
||||
assert_eq!(owner_id, item.def_id());
|
||||
// `f` should have consumed all the elements in these vectors when constructing `item`.
|
||||
debug_assert!(self.impl_trait_defs.is_empty());
|
||||
debug_assert!(self.impl_trait_bounds.is_empty());
|
||||
assert!(self.impl_trait_defs.is_empty());
|
||||
assert!(self.impl_trait_bounds.is_empty());
|
||||
let info = self.make_owner_info(item);
|
||||
|
||||
self.attrs = current_attrs;
|
||||
|
|
@ -606,6 +627,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
self.item_local_id_counter = current_local_counter;
|
||||
self.impl_trait_defs = current_impl_trait_defs;
|
||||
self.impl_trait_bounds = current_impl_trait_bounds;
|
||||
self.delayed_lints = current_delayed_lints;
|
||||
|
||||
debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id));
|
||||
self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info)));
|
||||
|
|
@ -616,6 +638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let mut bodies = std::mem::take(&mut self.bodies);
|
||||
let define_opaque = std::mem::take(&mut self.define_opaque);
|
||||
let trait_map = std::mem::take(&mut self.trait_map);
|
||||
let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice();
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
for (id, attrs) in attrs.iter() {
|
||||
|
|
@ -629,14 +652,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let bodies = SortedMap::from_presorted_elements(bodies);
|
||||
|
||||
// Don't hash unless necessary, because it's expensive.
|
||||
let (opt_hash_including_bodies, attrs_hash) =
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
|
||||
let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) =
|
||||
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
|
||||
let num_nodes = self.item_local_id_counter.as_usize();
|
||||
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
|
||||
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
|
||||
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
|
||||
let delayed_lints =
|
||||
hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash };
|
||||
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
|
||||
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints })
|
||||
}
|
||||
|
||||
/// This method allocates a new `HirId` for the given `NodeId`.
|
||||
|
|
@ -759,15 +784,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
})
|
||||
}
|
||||
|
||||
fn span_lowerer(&self) -> SpanLowerer {
|
||||
SpanLowerer {
|
||||
is_incremental: self.tcx.sess.opts.incremental.is_some(),
|
||||
def_id: self.current_hir_id_owner.def_id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Intercept all spans entering HIR.
|
||||
/// Mark a span as relative to the current owning item.
|
||||
fn lower_span(&self, span: Span) -> Span {
|
||||
if self.tcx.sess.opts.incremental.is_some() {
|
||||
span.with_parent(Some(self.current_hir_id_owner.def_id))
|
||||
} else {
|
||||
// Do not make spans relative when not using incremental compilation.
|
||||
span
|
||||
}
|
||||
self.span_lowerer().lower(span)
|
||||
}
|
||||
|
||||
fn lower_ident(&self, ident: Ident) -> Ident {
|
||||
|
|
@ -889,9 +916,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
if attrs.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
|
||||
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id);
|
||||
|
||||
debug_assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
let ret = self.arena.alloc_from_iter(lowered_attrs);
|
||||
|
||||
// this is possible if an item contained syntactical attribute,
|
||||
|
|
@ -909,16 +936,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> {
|
||||
self.attribute_parser
|
||||
.parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s))
|
||||
fn lower_attrs_vec(
|
||||
&mut self,
|
||||
attrs: &[Attribute],
|
||||
target_span: Span,
|
||||
target_hir_id: HirId,
|
||||
) -> Vec<hir::Attribute> {
|
||||
let l = self.span_lowerer();
|
||||
self.attribute_parser.parse_attribute_list(
|
||||
attrs,
|
||||
target_span,
|
||||
target_hir_id,
|
||||
OmitDoc::Lower,
|
||||
|s| l.lower(s),
|
||||
|l| {
|
||||
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
|
||||
debug_assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
|
||||
assert_eq!(id.owner, self.current_hir_id_owner);
|
||||
assert_eq!(target_id.owner, self.current_hir_id_owner);
|
||||
if let Some(&a) = self.attrs.get(&target_id.local_id) {
|
||||
debug_assert!(!a.is_empty());
|
||||
assert!(!a.is_empty());
|
||||
self.attrs.insert(id.local_id, a);
|
||||
}
|
||||
}
|
||||
|
|
@ -1397,7 +1438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
|
||||
self.resolver.get_lifetime_res(t.id)
|
||||
{
|
||||
debug_assert_eq!(start.plus(1), end);
|
||||
assert_eq!(start.plus(1), end);
|
||||
start
|
||||
} else {
|
||||
self.next_node_id()
|
||||
|
|
@ -1805,16 +1846,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let res = match res {
|
||||
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeKind::Param(param)
|
||||
}
|
||||
LifetimeRes::Infer => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
hir::LifetimeKind::Infer
|
||||
}
|
||||
LifetimeRes::Static { .. } => {
|
||||
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
|
||||
hir::LifetimeKind::Static
|
||||
}
|
||||
LifetimeRes::Error => hir::LifetimeKind::Error,
|
||||
|
|
@ -2106,7 +2147,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 +2219,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 +2285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
) -> hir::Stmt<'hir> {
|
||||
let hir_id = self.next_id();
|
||||
if let Some(a) = attrs {
|
||||
debug_assert!(!a.is_empty());
|
||||
assert!(!a.is_empty());
|
||||
self.attrs.insert(hir_id.local_id, a);
|
||||
}
|
||||
let local = hir::LetStmt {
|
||||
|
|
|
|||
|
|
@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
feature: sym::cmse_nonsecure_entry,
|
||||
explain: GateReason::Experimental,
|
||||
}),
|
||||
ExternAbi::Custom => {
|
||||
Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
ast_passes_abi_custom_coroutine =
|
||||
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
|
||||
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
|
||||
|
||||
ast_passes_abi_custom_invalid_signature =
|
||||
invalid signature for `extern "custom"` function
|
||||
.note = functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
.suggestion = remove the parameters and return type
|
||||
|
||||
ast_passes_abi_custom_safe_foreign_function =
|
||||
foreign functions with the `"custom"` ABI cannot be safe
|
||||
.suggestion = remove the `safe` keyword from this definition
|
||||
|
||||
ast_passes_abi_custom_safe_function =
|
||||
functions with the `"custom"` ABI must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::ExternAbi;
|
||||
|
|
@ -81,6 +82,7 @@ struct AstValidator<'a> {
|
|||
|
||||
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
||||
extern_mod_safety: Option<Safety>,
|
||||
extern_mod_abi: Option<ExternAbi>,
|
||||
|
||||
lint_node_id: NodeId,
|
||||
|
||||
|
|
@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
|
|||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
fn with_in_extern_mod(
|
||||
&mut self,
|
||||
extern_mod_safety: Safety,
|
||||
abi: Option<ExternAbi>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
|
||||
f(self);
|
||||
self.extern_mod_safety = old;
|
||||
self.extern_mod_safety = old_safety;
|
||||
self.extern_mod_abi = old_abi;
|
||||
}
|
||||
|
||||
fn with_tilde_const(
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -57,14 +57,6 @@ impl OptimizeAttr {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
|
||||
pub enum DiagnosticAttribute {
|
||||
// tidy-alphabetical-start
|
||||
DoNotRecommend,
|
||||
OnUnimplemented,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)]
|
||||
pub enum ReprAttr {
|
||||
ReprInt(IntType),
|
||||
|
|
@ -138,62 +130,107 @@ 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 {
|
||||
// tidy-alphabetical-start
|
||||
/// Represents `#[rustc_allow_const_fn_unstable]`.
|
||||
AllowConstFnUnstable(ThinVec<Symbol>),
|
||||
|
||||
/// 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,
|
||||
/// Span of the `#[rustc_default_body_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_confusables]`.
|
||||
Confusables {
|
||||
symbols: ThinVec<Symbol>,
|
||||
// FIXME(jdonszelmann): remove when target validation code is moved
|
||||
first_span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
|
||||
ConstStability {
|
||||
stability: PartialConstStability,
|
||||
/// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
|
||||
span: Span,
|
||||
},
|
||||
|
||||
/// Represents `#[rustc_const_stable_indirect]`.
|
||||
ConstStabilityIndirect,
|
||||
Deprecation {
|
||||
deprecation: Deprecation,
|
||||
span: Span,
|
||||
},
|
||||
Diagnostic(DiagnosticAttribute),
|
||||
DocComment {
|
||||
style: AttrStyle,
|
||||
kind: CommentKind,
|
||||
span: Span,
|
||||
comment: Symbol,
|
||||
},
|
||||
|
||||
/// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
|
||||
Deprecation { deprecation: Deprecation, span: Span },
|
||||
|
||||
/// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
|
||||
DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
|
||||
|
||||
/// Represents `#[rustc_macro_transparency]`.
|
||||
MacroTransparency(Transparency),
|
||||
|
||||
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
|
||||
Repr(ThinVec<(ReprAttr, Span)>),
|
||||
|
||||
/// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
|
||||
Stability {
|
||||
stability: Stability,
|
||||
/// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
|
||||
/// Span of the attribute.
|
||||
span: Span,
|
||||
},
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
|
|||
14
compiler/rustc_attr_data_structures/src/lints.rs
Normal file
14
compiler/rustc_attr_data_structures/src/lints.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use rustc_macros::HashStable_Generic;
|
||||
use rustc_span::Span;
|
||||
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub struct AttributeLint<Id> {
|
||||
pub id: Id,
|
||||
pub span: Span,
|
||||
pub kind: AttributeLintKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, HashStable_Generic)]
|
||||
pub enum AttributeLintKind {
|
||||
UnusedDuplicate { this: Span, other: Span, warning: bool },
|
||||
}
|
||||
|
|
@ -132,6 +132,7 @@ pub enum StabilityLevel {
|
|||
/// fn foobar() {}
|
||||
/// ```
|
||||
implied_by: Option<Symbol>,
|
||||
old_name: Option<Symbol>,
|
||||
},
|
||||
/// `#[stable]`
|
||||
Stable {
|
||||
|
|
|
|||
|
|
@ -131,7 +131,15 @@ attr_parsing_unsupported_literal_generic =
|
|||
attr_parsing_unsupported_literal_suggestion =
|
||||
consider removing the prefix
|
||||
|
||||
attr_parsing_unused_duplicate =
|
||||
unused attribute
|
||||
.suggestion = remove this attribute
|
||||
.note = attribute also specified here
|
||||
.warn = {-passes_previously_accepted}
|
||||
attr_parsing_unused_multiple =
|
||||
multiple `{$name}` attributes
|
||||
.suggestion = remove this attribute
|
||||
.note = attribute also specified here
|
||||
|
||||
-attr_parsing_perviously_accepted =
|
||||
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
|
|
|
|||
|
|
@ -4,41 +4,43 @@ use rustc_attr_data_structures::AttributeKind;
|
|||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::{CombineAttributeParser, ConvertFn};
|
||||
use crate::context::AcceptContext;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics;
|
||||
|
||||
pub(crate) struct AllowInternalUnstableParser;
|
||||
impl CombineAttributeParser for AllowInternalUnstableParser {
|
||||
const PATH: &'static [Symbol] = &[sym::allow_internal_unstable];
|
||||
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
|
||||
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
|
||||
type Item = (Symbol, Span);
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
|
||||
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a {
|
||||
parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span))
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> {
|
||||
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
||||
.into_iter()
|
||||
.zip(iter::repeat(cx.attr_span))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AllowConstFnUnstableParser;
|
||||
impl CombineAttributeParser for AllowConstFnUnstableParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
|
||||
type Item = Symbol;
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
|
||||
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a {
|
||||
parse_unstable(cx, args, Self::PATH[0])
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_unstable<'a>(
|
||||
cx: &AcceptContext<'_>,
|
||||
args: &'a ArgParser<'a>,
|
||||
fn parse_unstable<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser<'_>,
|
||||
symbol: Symbol,
|
||||
) -> impl IntoIterator<Item = Symbol> {
|
||||
let mut res = Vec::new();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use rustc_span::{Span, Symbol, sym};
|
|||
use thin_vec::ThinVec;
|
||||
|
||||
use super::{AcceptMapping, AttributeParser};
|
||||
use crate::context::FinalizeContext;
|
||||
use crate::context::{FinalizeContext, Stage};
|
||||
use crate::session_diagnostics;
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser {
|
|||
first_span: Option<Span>,
|
||||
}
|
||||
|
||||
impl AttributeParser for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| {
|
||||
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
|
||||
let Some(list) = args.list() else {
|
||||
// FIXME(jdonszelmann): error when not a list? Bring validation code here.
|
||||
// NOTE: currently subsequent attributes are silently ignored using
|
||||
|
|
@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser {
|
|||
this.first_span.get_or_insert(cx.attr_span);
|
||||
})];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.confusables.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::SingleAttributeParser;
|
||||
use super::util::parse_version;
|
||||
use crate::context::AcceptContext;
|
||||
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics;
|
||||
use crate::session_diagnostics::UnsupportedLiteralReason;
|
||||
|
||||
pub(crate) struct DeprecationParser;
|
||||
|
||||
fn get(
|
||||
cx: &AcceptContext<'_>,
|
||||
fn get<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
name: Symbol,
|
||||
param_span: Span,
|
||||
arg: &ArgParser<'_>,
|
||||
|
|
@ -41,19 +41,12 @@ fn get(
|
|||
}
|
||||
}
|
||||
|
||||
impl SingleAttributeParser for DeprecationParser {
|
||||
const PATH: &'static [Symbol] = &[sym::deprecated];
|
||||
impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
|
||||
const PATH: &[Symbol] = &[sym::deprecated];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
|
||||
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) {
|
||||
// FIXME(jdonszelmann): merge with errors from check_attrs.rs
|
||||
cx.emit_err(session_diagnostics::UnusedMultiple {
|
||||
this: cx.attr_span,
|
||||
other: first_span,
|
||||
name: sym::deprecated,
|
||||
});
|
||||
}
|
||||
|
||||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let features = cx.features();
|
||||
|
||||
let mut since = None;
|
||||
|
|
|
|||
97
compiler/rustc_attr_parsing/src/attributes/inline.rs
Normal file
97
compiler/rustc_attr_parsing/src/attributes/inline.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here.
|
||||
// note: need to model better how duplicate attr errors work when not using
|
||||
// SingleAttributeParser which is what we have two of here.
|
||||
|
||||
use rustc_attr_data_structures::lints::AttributeLintKind;
|
||||
use rustc_attr_data_structures::{AttributeKind, InlineAttr};
|
||||
use rustc_feature::{AttributeTemplate, template};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use super::{AcceptContext, AttributeOrder, OnDuplicate};
|
||||
use crate::attributes::SingleAttributeParser;
|
||||
use crate::context::Stage;
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct InlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
|
||||
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args {
|
||||
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = list.single() else {
|
||||
cx.expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) {
|
||||
Some(sym::always) => {
|
||||
Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
|
||||
}
|
||||
Some(sym::never) => {
|
||||
Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
|
||||
}
|
||||
_ => {
|
||||
cx.expected_specific_argument(l.span(), vec!["always", "never"]);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
ArgParser::NameValue(_) => {
|
||||
let suggestions =
|
||||
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline");
|
||||
cx.emit_lint(
|
||||
AttributeLintKind::IllFormedAttributeInput { suggestions },
|
||||
cx.attr_span,
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct RustcForceInlineParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
|
||||
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
|
||||
|
||||
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
let reason = match args {
|
||||
ArgParser::NoArgs => None,
|
||||
ArgParser::List(list) => {
|
||||
let Some(l) = list.single() else {
|
||||
cx.expected_single_argument(list.span);
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
|
||||
cx.expected_string_literal(l.span());
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(reason)
|
||||
}
|
||||
ArgParser::NameValue(v) => {
|
||||
let Some(reason) = v.value_as_str() else {
|
||||
cx.expected_string_literal(v.value_span);
|
||||
return None;
|
||||
};
|
||||
|
||||
Some(reason)
|
||||
}
|
||||
};
|
||||
|
||||
Some(AttributeKind::Inline(
|
||||
InlineAttr::Force { attr_span: cx.attr_span, reason },
|
||||
cx.attr_span,
|
||||
))
|
||||
}
|
||||
}
|
||||
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_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;
|
||||
|
||||
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,31 @@
|
|||
//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the
|
||||
//! contents of attributes, if an attribute appear multiple times in a list
|
||||
//!
|
||||
//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed.
|
||||
//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::lints::AttributeLintKind;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use crate::context::{AcceptContext, FinalizeContext};
|
||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
use crate::session_diagnostics::UnusedMultiple;
|
||||
|
||||
pub(crate) mod allow_unstable;
|
||||
pub(crate) mod cfg;
|
||||
pub(crate) mod confusables;
|
||||
pub(crate) mod deprecation;
|
||||
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], AcceptFn<T, S>)];
|
||||
|
||||
/// An [`AttributeParser`] is a type which searches for syntactic attributes.
|
||||
///
|
||||
|
|
@ -51,15 +54,24 @@ type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)];
|
|||
/// whether it has seen the attribute it has been looking for.
|
||||
///
|
||||
/// The state machine is automatically reset to parse attributes on the next item.
|
||||
pub(crate) trait AttributeParser: Default + 'static {
|
||||
///
|
||||
/// For a simpler attribute parsing interface, consider using [`SingleAttributeParser`]
|
||||
/// or [`CombineAttributeParser`] instead.
|
||||
pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
|
||||
/// The symbols for the attributes that this parser is interested in.
|
||||
///
|
||||
/// If an attribute has this symbol, the `accept` function will be called on it.
|
||||
const ATTRIBUTES: AcceptMapping<Self>;
|
||||
const ATTRIBUTES: AcceptMapping<Self, S>;
|
||||
|
||||
/// The parser has gotten a chance to accept the attributes on an item,
|
||||
/// here it can produce an attribute.
|
||||
fn finalize(self, cx: &FinalizeContext<'_>) -> Option<AttributeKind>;
|
||||
///
|
||||
/// All finalize methods of all parsers are unconditionally called.
|
||||
/// This means you can't unconditionally return `Some` here,
|
||||
/// that'd be equivalent to unconditionally applying an attribute to
|
||||
/// every single syntax item that could have attributes applied to it.
|
||||
/// Your accept mappings should determine whether this returns something.
|
||||
fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;
|
||||
}
|
||||
|
||||
/// Alternative to [`AttributeParser`] that automatically handles state management.
|
||||
|
|
@ -71,44 +83,131 @@ pub(crate) trait AttributeParser: Default + 'static {
|
|||
///
|
||||
/// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple
|
||||
/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
|
||||
pub(crate) trait SingleAttributeParser: 'static {
|
||||
const PATH: &'static [Symbol];
|
||||
|
||||
/// Called when a duplicate attribute is found.
|
||||
///
|
||||
/// `first_span` is the span of the first occurrence of this attribute.
|
||||
// FIXME(jdonszelmann): default error
|
||||
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span);
|
||||
pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
|
||||
const PATH: &[Symbol];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder;
|
||||
const ON_DUPLICATE: OnDuplicate<S>;
|
||||
|
||||
/// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
|
||||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>;
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
|
||||
}
|
||||
|
||||
pub(crate) struct Single<T: SingleAttributeParser>(PhantomData<T>, Option<(AttributeKind, Span)>);
|
||||
pub(crate) struct Single<T: SingleAttributeParser<S>, S: Stage>(
|
||||
PhantomData<(S, T)>,
|
||||
Option<(AttributeKind, Span)>,
|
||||
);
|
||||
|
||||
impl<T: SingleAttributeParser> Default for Single<T> {
|
||||
impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: SingleAttributeParser> AttributeParser for Single<T> {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| {
|
||||
if let Some((_, s)) = group.1 {
|
||||
T::on_duplicate(cx, s);
|
||||
return;
|
||||
}
|
||||
impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(T::PATH, |group: &mut Single<T, S>, cx, args| {
|
||||
if let Some(pa) = T::convert(cx, args) {
|
||||
match T::ATTRIBUTE_ORDER {
|
||||
// keep the first and report immediately. ignore this attribute
|
||||
AttributeOrder::KeepFirst => {
|
||||
if let Some((_, unused)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, cx.attr_span, unused);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// keep the new one and warn about the previous,
|
||||
// then replace
|
||||
AttributeOrder::KeepLast => {
|
||||
if let Some((_, used)) = group.1 {
|
||||
T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(pa) = T::convert(cx, args) {
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
}
|
||||
})];
|
||||
group.1 = Some((pa, cx.attr_span));
|
||||
}
|
||||
})];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
Some(self.1?.0)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing
|
||||
// them will be merged in another PR
|
||||
#[allow(unused)]
|
||||
pub(crate) enum OnDuplicate<S: Stage> {
|
||||
/// Give a default warning
|
||||
Warn,
|
||||
|
||||
/// Duplicates will be a warning, with a note that this will be an error in the future.
|
||||
WarnButFutureError,
|
||||
|
||||
/// Give a default error
|
||||
Error,
|
||||
|
||||
/// Ignore duplicates
|
||||
Ignore,
|
||||
|
||||
/// Custom function called when a duplicate attribute is found.
|
||||
///
|
||||
/// - `unused` is the span of the attribute that was unused or bad because of some
|
||||
/// duplicate reason (see [`AttributeOrder`])
|
||||
/// - `used` is the span of the attribute that was used in favor of the unused attribute
|
||||
Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)),
|
||||
}
|
||||
|
||||
impl<S: Stage> OnDuplicate<S> {
|
||||
fn exec<P: SingleAttributeParser<S>>(
|
||||
&self,
|
||||
cx: &mut AcceptContext<'_, '_, S>,
|
||||
used: Span,
|
||||
unused: Span,
|
||||
) {
|
||||
match self {
|
||||
OnDuplicate::Warn => cx.emit_lint(
|
||||
AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: false },
|
||||
unused,
|
||||
),
|
||||
OnDuplicate::WarnButFutureError => cx.emit_lint(
|
||||
AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: true },
|
||||
unused,
|
||||
),
|
||||
OnDuplicate::Error => {
|
||||
cx.emit_err(UnusedMultiple {
|
||||
this: used,
|
||||
other: unused,
|
||||
name: Symbol::intern(
|
||||
&P::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."),
|
||||
),
|
||||
});
|
||||
}
|
||||
OnDuplicate::Ignore => {}
|
||||
OnDuplicate::Custom(f) => f(cx, used, unused),
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing
|
||||
// them will be merged in another PR
|
||||
#[allow(unused)]
|
||||
pub(crate) enum AttributeOrder {
|
||||
/// Duplicates after the first attribute will be an error.
|
||||
///
|
||||
/// This should be used where duplicates would be ignored, but carry extra
|
||||
/// meaning that could cause confusion. For example, `#[stable(since="1.0")]
|
||||
/// #[stable(since="2.0")]`, which version should be used for `stable`?
|
||||
KeepFirst,
|
||||
|
||||
/// Duplicates preceding the last instance of the attribute will be a
|
||||
/// warning, with a note that this will be an error in the future.
|
||||
///
|
||||
/// This is the same as `FutureWarnFollowing`, except the last attribute is
|
||||
/// the one that is "used". Ideally these can eventually migrate to
|
||||
/// `ErrorPreceding`.
|
||||
KeepLast,
|
||||
}
|
||||
|
||||
type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
|
||||
|
||||
/// Alternative to [`AttributeParser`] that automatically handles state management.
|
||||
|
|
@ -118,35 +217,35 @@ type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
|
|||
///
|
||||
/// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple
|
||||
/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
|
||||
pub(crate) trait CombineAttributeParser: 'static {
|
||||
const PATH: &'static [Symbol];
|
||||
pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
|
||||
const PATH: &[rustc_span::Symbol];
|
||||
|
||||
type Item;
|
||||
const CONVERT: ConvertFn<Self::Item>;
|
||||
|
||||
/// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a;
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c;
|
||||
}
|
||||
|
||||
pub(crate) struct Combine<T: CombineAttributeParser>(
|
||||
PhantomData<T>,
|
||||
ThinVec<<T as CombineAttributeParser>::Item>,
|
||||
pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
|
||||
PhantomData<(S, T)>,
|
||||
ThinVec<<T as CombineAttributeParser<S>>::Item>,
|
||||
);
|
||||
|
||||
impl<T: CombineAttributeParser> Default for Combine<T> {
|
||||
impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
|
||||
fn default() -> Self {
|
||||
Self(Default::default(), Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CombineAttributeParser> AttributeParser for Combine<T> {
|
||||
const ATTRIBUTES: AcceptMapping<Self> =
|
||||
&[(T::PATH, |group: &mut Combine<T>, cx, args| group.1.extend(T::extend(cx, args)))];
|
||||
impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
|
|||
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
|
||||
|
||||
use super::{CombineAttributeParser, ConvertFn};
|
||||
use crate::context::AcceptContext;
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
|
||||
use crate::session_diagnostics;
|
||||
use crate::session_diagnostics::IncorrectReprFormatGenericCause;
|
||||
|
|
@ -19,15 +19,15 @@ use crate::session_diagnostics::IncorrectReprFormatGenericCause;
|
|||
// FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct?
|
||||
pub(crate) struct ReprParser;
|
||||
|
||||
impl CombineAttributeParser for ReprParser {
|
||||
impl<S: Stage> CombineAttributeParser<S> for ReprParser {
|
||||
type Item = (ReprAttr, Span);
|
||||
const PATH: &'static [Symbol] = &[sym::repr];
|
||||
const PATH: &[Symbol] = &[sym::repr];
|
||||
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
|
||||
|
||||
fn extend<'a>(
|
||||
cx: &'a AcceptContext<'a>,
|
||||
args: &'a ArgParser<'a>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'a {
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
let mut reprs = Vec::new();
|
||||
|
||||
let Some(list) = args.list() else {
|
||||
|
|
@ -91,7 +91,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> {
|
||||
fn parse_repr<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
param: &MetaItemParser<'_>,
|
||||
) -> Option<ReprAttr> {
|
||||
use ReprAttr::*;
|
||||
|
||||
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
|
||||
|
|
@ -180,8 +183,8 @@ enum AlignKind {
|
|||
Align,
|
||||
}
|
||||
|
||||
fn parse_repr_align(
|
||||
cx: &AcceptContext<'_>,
|
||||
fn parse_repr_align<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
list: &MetaItemListParser<'_>,
|
||||
param_span: Span,
|
||||
align_kind: AlignKind,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ use rustc_errors::ErrorGuaranteed;
|
|||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use super::util::parse_version;
|
||||
use super::{AcceptMapping, AttributeParser, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, FinalizeContext};
|
||||
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, FinalizeContext, Stage};
|
||||
use crate::parser::{ArgParser, MetaItemParser};
|
||||
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ pub(crate) struct StabilityParser {
|
|||
|
||||
impl StabilityParser {
|
||||
/// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
|
||||
fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
|
||||
fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
|
||||
if let Some((_, _)) = self.stability {
|
||||
cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
|
||||
true
|
||||
|
|
@ -41,8 +41,8 @@ impl StabilityParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl AttributeParser for StabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[
|
||||
impl<S: Stage> AttributeParser<S> for StabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[sym::stable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if !this.check_duplicate(cx)
|
||||
|
|
@ -65,7 +65,7 @@ impl AttributeParser for StabilityParser {
|
|||
}),
|
||||
];
|
||||
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if let Some(atum) = self.allowed_through_unstable_modules {
|
||||
if let Some((
|
||||
Stability {
|
||||
|
|
@ -95,8 +95,8 @@ pub(crate) struct BodyStabilityParser {
|
|||
stability: Option<(DefaultBodyStability, Span)>,
|
||||
}
|
||||
|
||||
impl AttributeParser for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> =
|
||||
impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> =
|
||||
&[(&[sym::rustc_default_body_unstable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
if this.stability.is_some() {
|
||||
|
|
@ -107,7 +107,7 @@ impl AttributeParser for BodyStabilityParser {
|
|||
}
|
||||
})];
|
||||
|
||||
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
let (stability, span) = self.stability?;
|
||||
|
||||
Some(AttributeKind::BodyStability { stability, span })
|
||||
|
|
@ -116,13 +116,12 @@ impl AttributeParser for BodyStabilityParser {
|
|||
|
||||
pub(crate) struct ConstStabilityIndirectParser;
|
||||
// FIXME(jdonszelmann): single word attribute group when we have these
|
||||
impl SingleAttributeParser for ConstStabilityIndirectParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_const_stable_indirect];
|
||||
impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
|
||||
|
||||
// ignore
|
||||
fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {}
|
||||
|
||||
fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
Some(AttributeKind::ConstStabilityIndirect)
|
||||
}
|
||||
}
|
||||
|
|
@ -135,7 +134,7 @@ pub(crate) struct ConstStabilityParser {
|
|||
|
||||
impl ConstStabilityParser {
|
||||
/// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
|
||||
fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
|
||||
fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
|
||||
if let Some((_, _)) = self.stability {
|
||||
cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
|
||||
true
|
||||
|
|
@ -145,8 +144,8 @@ impl ConstStabilityParser {
|
|||
}
|
||||
}
|
||||
|
||||
impl AttributeParser for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self> = &[
|
||||
impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
|
||||
const ATTRIBUTES: AcceptMapping<Self, S> = &[
|
||||
(&[sym::rustc_const_stable], |this, cx, args| {
|
||||
reject_outside_std!(cx);
|
||||
|
||||
|
|
@ -176,7 +175,7 @@ impl AttributeParser for ConstStabilityParser {
|
|||
}),
|
||||
];
|
||||
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
|
||||
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
|
||||
if self.promotable {
|
||||
if let Some((ref mut stab, _)) = self.stability {
|
||||
stab.promotable = true;
|
||||
|
|
@ -196,8 +195,8 @@ impl AttributeParser for ConstStabilityParser {
|
|||
///
|
||||
/// Emits an error when either the option was already Some, or the arguments weren't of form
|
||||
/// `name = value`
|
||||
fn insert_value_into_option_or_error(
|
||||
cx: &AcceptContext<'_>,
|
||||
fn insert_value_into_option_or_error<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
param: &MetaItemParser<'_>,
|
||||
item: &mut Option<Symbol>,
|
||||
) -> Option<()> {
|
||||
|
|
@ -223,8 +222,8 @@ fn insert_value_into_option_or_error(
|
|||
|
||||
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
|
||||
/// its stability information.
|
||||
pub(crate) fn parse_stability(
|
||||
cx: &AcceptContext<'_>,
|
||||
pub(crate) fn parse_stability<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser<'_>,
|
||||
) -> Option<(Symbol, StabilityLevel)> {
|
||||
let mut feature = None;
|
||||
|
|
@ -289,8 +288,8 @@ pub(crate) fn parse_stability(
|
|||
|
||||
// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
|
||||
/// attribute, and return the feature name and its stability information.
|
||||
pub(crate) fn parse_unstability(
|
||||
cx: &AcceptContext<'_>,
|
||||
pub(crate) fn parse_unstability<S: Stage>(
|
||||
cx: &AcceptContext<'_, '_, S>,
|
||||
args: &ArgParser<'_>,
|
||||
) -> Option<(Symbol, StabilityLevel)> {
|
||||
let mut feature = None;
|
||||
|
|
@ -299,6 +298,7 @@ pub(crate) fn parse_unstability(
|
|||
let mut issue_num = None;
|
||||
let mut is_soft = false;
|
||||
let mut implied_by = None;
|
||||
let mut old_name = None;
|
||||
for param in args.list()?.mixed() {
|
||||
let Some(param) = param.meta_item() else {
|
||||
cx.emit_err(session_diagnostics::UnsupportedLiteral {
|
||||
|
|
@ -346,11 +346,12 @@ pub(crate) fn parse_unstability(
|
|||
Some(sym::implied_by) => {
|
||||
insert_value_into_option_or_error(cx, ¶m, &mut implied_by)?
|
||||
}
|
||||
Some(sym::old_name) => insert_value_into_option_or_error(cx, ¶m, &mut old_name)?,
|
||||
_ => {
|
||||
cx.emit_err(session_diagnostics::UnknownMetaItem {
|
||||
span: param.span(),
|
||||
item: param.path().to_string(),
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by"],
|
||||
expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
|
||||
});
|
||||
return None;
|
||||
}
|
||||
|
|
@ -375,6 +376,7 @@ pub(crate) fn parse_unstability(
|
|||
issue: issue_num,
|
||||
is_soft,
|
||||
implied_by,
|
||||
old_name,
|
||||
};
|
||||
Some((feature, level))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_span::hygiene::Transparency;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_span::{Symbol, sym};
|
||||
|
||||
use super::{AcceptContext, SingleAttributeParser};
|
||||
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
|
||||
use crate::context::{AcceptContext, Stage};
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct TransparencyParser;
|
||||
|
|
@ -10,14 +11,14 @@ pub(crate) struct TransparencyParser;
|
|||
// FIXME(jdonszelmann): make these proper diagnostics
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
impl SingleAttributeParser for TransparencyParser {
|
||||
const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency];
|
||||
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
|
||||
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
|
||||
cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
|
||||
});
|
||||
|
||||
fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) {
|
||||
cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes");
|
||||
}
|
||||
|
||||
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
match args.name_value().and_then(|nv| nv.value_as_str()) {
|
||||
Some(sym::transparent) => Some(Transparency::Transparent),
|
||||
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
|
||||
|
|
|
|||
|
|
@ -1,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 private::Sealed;
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::NodeId;
|
||||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_errors::{DiagCtxtHandle, Diagnostic};
|
||||
use rustc_feature::Features;
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId};
|
||||
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
|
||||
use rustc_session::Session;
|
||||
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
|
||||
|
||||
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::lint_helpers::AsPtrParser;
|
||||
use crate::attributes::repr::ReprParser;
|
||||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
|
|
@ -22,20 +27,40 @@ use crate::attributes::transparency::TransparencyParser;
|
|||
use crate::attributes::{AttributeParser as _, Combine, Single};
|
||||
use crate::parser::{ArgParser, MetaItemParser};
|
||||
|
||||
macro_rules! attribute_groups {
|
||||
macro_rules! group_type {
|
||||
($stage: ty) => {
|
||||
LazyLock<(
|
||||
BTreeMap<&'static [Symbol], Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>,
|
||||
Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
|
||||
)>
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! attribute_parsers {
|
||||
(
|
||||
pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
type Accepts = BTreeMap<
|
||||
&'static [Symbol],
|
||||
Box<dyn Send + Sync + Fn(&AcceptContext<'_>, &ArgParser<'_>)>
|
||||
>;
|
||||
type Finalizes = Vec<
|
||||
Box<dyn Send + Sync + Fn(&FinalizeContext<'_>) -> Option<AttributeKind>>
|
||||
>;
|
||||
pub(crate) static $name: LazyLock<(Accepts, Finalizes)> = LazyLock::new(|| {
|
||||
let mut accepts = Accepts::new();
|
||||
let mut finalizes = Finalizes::new();
|
||||
mod early {
|
||||
use super::*;
|
||||
type Combine<T> = super::Combine<T, Early>;
|
||||
type Single<T> = super::Single<T, Early>;
|
||||
|
||||
attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
|
||||
}
|
||||
mod late {
|
||||
use super::*;
|
||||
type Combine<T> = super::Combine<T, Late>;
|
||||
type Single<T> = super::Single<T, Late>;
|
||||
|
||||
attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
|
||||
}
|
||||
};
|
||||
(
|
||||
@[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
|
||||
) => {
|
||||
pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
|
||||
let mut accepts = BTreeMap::<_, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>::new();
|
||||
let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
|
||||
$(
|
||||
{
|
||||
thread_local! {
|
||||
|
|
@ -62,9 +87,8 @@ macro_rules! attribute_groups {
|
|||
});
|
||||
};
|
||||
}
|
||||
|
||||
attribute_groups!(
|
||||
pub(crate) static ATTRIBUTE_MAPPING = [
|
||||
attribute_parsers!(
|
||||
pub(crate) static ATTRIBUTE_PARSERS = [
|
||||
// tidy-alphabetical-start
|
||||
BodyStabilityParser,
|
||||
ConfusablesParser,
|
||||
|
|
@ -79,6 +103,7 @@ attribute_groups!(
|
|||
// tidy-alphabetical-end
|
||||
|
||||
// tidy-alphabetical-start
|
||||
Single<AsPtrParser>,
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<TransparencyParser>,
|
||||
|
|
@ -86,30 +111,84 @@ attribute_groups!(
|
|||
];
|
||||
);
|
||||
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
impl Sealed for super::Early {}
|
||||
impl Sealed for super::Late {}
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
pub trait Stage: Sized + 'static + Sealed {
|
||||
type Id: Copy;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self);
|
||||
|
||||
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
impl Stage for Early {
|
||||
type Id = NodeId;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
&early::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
sess.dcx().create_err(diag).delay_as_bug()
|
||||
}
|
||||
}
|
||||
|
||||
// allow because it's a sealed trait
|
||||
#[allow(private_interfaces)]
|
||||
impl Stage for Late {
|
||||
type Id = HirId;
|
||||
|
||||
fn parsers() -> &'static group_type!(Self) {
|
||||
&late::ATTRIBUTE_PARSERS
|
||||
}
|
||||
fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
tcx.dcx().emit_err(diag)
|
||||
}
|
||||
}
|
||||
|
||||
/// used when parsing attributes for miscelaneous things *before* ast lowering
|
||||
pub struct Early;
|
||||
/// used when parsing attributes during ast lowering
|
||||
pub struct Late;
|
||||
|
||||
/// Context given to every attribute parser when accepting
|
||||
///
|
||||
/// Gives [`AttributeParser`]s enough information to create errors, for example.
|
||||
pub(crate) struct AcceptContext<'a> {
|
||||
pub(crate) group_cx: &'a FinalizeContext<'a>,
|
||||
pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
|
||||
pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>,
|
||||
/// The span of the attribute currently being parsed
|
||||
pub(crate) attr_span: Span,
|
||||
}
|
||||
|
||||
impl<'a> AcceptContext<'a> {
|
||||
pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed {
|
||||
if self.limit_diagnostics {
|
||||
self.dcx().create_err(diag).delay_as_bug()
|
||||
} else {
|
||||
self.dcx().emit_err(diag)
|
||||
}
|
||||
impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
|
||||
pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
|
||||
S::emit_err(&self.sess, diag)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
|
||||
let id = self.target_id;
|
||||
(self.emit_lint)(AttributeLint { id, span, kind: lint });
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for AcceptContext<'a> {
|
||||
type Target = FinalizeContext<'a>;
|
||||
impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
|
||||
type Target = FinalizeContext<'f, 'sess, S>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.group_cx
|
||||
&self.finalize_cx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.finalize_cx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,19 +196,29 @@ impl<'a> Deref for AcceptContext<'a> {
|
|||
///
|
||||
/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
|
||||
/// errors, for example.
|
||||
pub(crate) struct FinalizeContext<'a> {
|
||||
pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
|
||||
/// The parse context, gives access to the session and the
|
||||
/// diagnostics context.
|
||||
pub(crate) cx: &'a AttributeParser<'a>,
|
||||
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
|
||||
/// The span of the syntactical component this attribute was applied to
|
||||
pub(crate) target_span: Span,
|
||||
/// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
|
||||
pub(crate) target_id: S::Id,
|
||||
|
||||
pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
|
||||
}
|
||||
|
||||
impl<'a> Deref for FinalizeContext<'a> {
|
||||
type Target = AttributeParser<'a>;
|
||||
impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
|
||||
type Target = AttributeParser<'sess, S>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cx
|
||||
self.cx
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.cx
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,23 +230,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 +254,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 +308,25 @@ impl<'sess> AttributeParser<'sess> {
|
|||
}
|
||||
|
||||
pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
|
||||
self.sess.dcx()
|
||||
self.sess().dcx()
|
||||
}
|
||||
|
||||
/// Parse a list of attributes.
|
||||
///
|
||||
/// `target_span` is the span of the thing this list of attributes is applied to,
|
||||
/// and when `omit_doc` is set, doc attributes are filtered out.
|
||||
pub fn parse_attribute_list<'a>(
|
||||
&'a self,
|
||||
attrs: &'a [ast::Attribute],
|
||||
pub fn parse_attribute_list(
|
||||
&mut self,
|
||||
attrs: &[ast::Attribute],
|
||||
target_span: Span,
|
||||
target_id: S::Id,
|
||||
omit_doc: OmitDoc,
|
||||
|
||||
lower_span: impl Copy + Fn(Span) -> Span,
|
||||
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
|
||||
) -> Vec<Attribute> {
|
||||
let mut attributes = Vec::new();
|
||||
|
||||
let group_cx = FinalizeContext { cx: self, target_span };
|
||||
|
||||
for attr in attrs {
|
||||
// If we're only looking for a single attribute, skip all the ones we don't care about.
|
||||
if let Some(expected) = self.parse_only {
|
||||
|
|
@ -268,11 +374,18 @@ impl<'sess> AttributeParser<'sess> {
|
|||
let args = parser.args();
|
||||
let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
|
||||
|
||||
if let Some(accept) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) {
|
||||
let cx =
|
||||
AcceptContext { group_cx: &group_cx, attr_span: lower_span(attr.span) };
|
||||
if let Some(accept) = S::parsers().0.get(parts.as_slice()) {
|
||||
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
|
||||
finalize_cx: FinalizeContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target_id,
|
||||
emit_lint: &mut emit_lint,
|
||||
},
|
||||
attr_span: lower_span(attr.span),
|
||||
};
|
||||
|
||||
accept(&cx, &args)
|
||||
accept(&mut cx, args)
|
||||
} else {
|
||||
// If we're here, we must be compiling a tool attribute... Or someone
|
||||
// forgot to parse their fancy new attribute. Let's warn them in any case.
|
||||
|
|
@ -302,8 +415,13 @@ impl<'sess> AttributeParser<'sess> {
|
|||
}
|
||||
|
||||
let mut parsed_attributes = Vec::new();
|
||||
for f in &ATTRIBUTE_MAPPING.1 {
|
||||
if let Some(attr) = f(&group_cx) {
|
||||
for f in &S::parsers().1 {
|
||||
if let Some(attr) = f(&mut FinalizeContext {
|
||||
cx: self,
|
||||
target_span,
|
||||
target_id,
|
||||
emit_lint: &mut emit_lint,
|
||||
}) {
|
||||
parsed_attributes.push(Attribute::Parsed(attr));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@
|
|||
|
||||
#[macro_use]
|
||||
mod attributes;
|
||||
mod context;
|
||||
pub(crate) mod context;
|
||||
mod lints;
|
||||
pub mod parser;
|
||||
mod session_diagnostics;
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ pub use attributes::cfg::*;
|
|||
pub use attributes::util::{
|
||||
find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
|
||||
};
|
||||
pub use context::{AttributeParser, OmitDoc};
|
||||
pub use context::{AttributeParser, Early, Late, OmitDoc};
|
||||
pub use lints::emit_attribute_lint;
|
||||
|
||||
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
|
||||
|
|
|
|||
19
compiler/rustc_attr_parsing/src/lints.rs
Normal file
19
compiler/rustc_attr_parsing/src/lints.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
|
||||
use rustc_errors::LintEmitter;
|
||||
use rustc_hir::HirId;
|
||||
|
||||
use crate::session_diagnostics;
|
||||
|
||||
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
|
||||
let AttributeLint { id, span, kind } = lint;
|
||||
|
||||
match kind {
|
||||
&AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter
|
||||
.emit_node_span_lint(
|
||||
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
|
||||
*id,
|
||||
*span,
|
||||
session_diagnostics::UnusedDuplicate { this, other, warning },
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -115,7 +115,7 @@ impl<'a> ArgParser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self {
|
||||
pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
match value {
|
||||
AttrArgs::Empty => Self::NoArgs,
|
||||
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
|
||||
|
|
@ -235,7 +235,7 @@ impl<'a> Debug for MetaItemParser<'a> {
|
|||
impl<'a> MetaItemParser<'a> {
|
||||
/// Create a new parser from a [`NormalAttr`], which is stored inside of any
|
||||
/// [`ast::Attribute`](rustc_ast::Attribute)
|
||||
pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self {
|
||||
pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
Self {
|
||||
path: PathParser::Ast(&attr.item.path),
|
||||
args: ArgParser::from_attr_args(&attr.item.args, dcx),
|
||||
|
|
@ -320,13 +320,13 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit
|
|||
}
|
||||
}
|
||||
|
||||
struct MetaItemListParserContext<'a> {
|
||||
struct MetaItemListParserContext<'a, 'sess> {
|
||||
// the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside
|
||||
inside_delimiters: Peekable<TokenStreamIter<'a>>,
|
||||
dcx: DiagCtxtHandle<'a>,
|
||||
dcx: DiagCtxtHandle<'sess>,
|
||||
}
|
||||
|
||||
impl<'a> MetaItemListParserContext<'a> {
|
||||
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
||||
fn done(&mut self) -> bool {
|
||||
self.inside_delimiters.peek().is_none()
|
||||
}
|
||||
|
|
@ -507,11 +507,11 @@ pub struct MetaItemListParser<'a> {
|
|||
}
|
||||
|
||||
impl<'a> MetaItemListParser<'a> {
|
||||
fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> {
|
||||
fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx)
|
||||
}
|
||||
|
||||
fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self {
|
||||
fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self {
|
||||
MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::num::IntErrorKind;
|
|||
use rustc_ast as ast;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
|
||||
use rustc_macros::{Diagnostic, Subdiagnostic};
|
||||
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
||||
use crate::fluent_generated as fluent;
|
||||
|
|
@ -451,6 +451,17 @@ pub(crate) struct UnusedMultiple {
|
|||
pub name: Symbol,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(attr_parsing_unused_duplicate)]
|
||||
pub(crate) struct UnusedDuplicate {
|
||||
#[suggestion(code = "", applicability = "machine-applicable")]
|
||||
pub this: Span,
|
||||
#[note]
|
||||
pub other: Span,
|
||||
#[warning]
|
||||
pub warning: bool,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(attr_parsing_stability_outside_std, code = E0734)]
|
||||
pub(crate) struct StabilityOutsideStd {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,8 +141,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
|
|||
}
|
||||
|
||||
if !tcx.recursion_limit().value_within_limit(iteration) {
|
||||
// This may actually be reachable. If so, we should convert
|
||||
// this to a proper error/consider whether we should detect
|
||||
// this somewhere else.
|
||||
bug!(
|
||||
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
"unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ resolver = "2"
|
|||
|
||||
[dependencies]
|
||||
core = { path = "./sysroot_src/library/core" }
|
||||
compiler_builtins = "0.1"
|
||||
alloc = { path = "./sysroot_src/library/alloc" }
|
||||
std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
|
||||
test = { path = "./sysroot_src/library/test" }
|
||||
|
|
@ -16,6 +15,7 @@ proc_macro = { path = "./sysroot_src/library/proc_macro" }
|
|||
rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
|
||||
rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
|
||||
rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
|
||||
compiler_builtins = { path = "./sysroot_src/library/compiler-builtins/compiler-builtins" }
|
||||
|
||||
# For compiler-builtins we always use a high number of codegen units.
|
||||
# The goal here is to place every single intrinsic into its own object
|
||||
|
|
|
|||
|
|
@ -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]>());
|
||||
|
|
|
|||
|
|
@ -2,9 +2,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
|
|||
unknown feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = features must begin with a `+` to enable or `-` to disable it
|
||||
|
||||
codegen_gcc_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
|
||||
|
||||
codegen_gcc_unwinding_inline_asm =
|
||||
GCC backend does not support unwinding from inline asm
|
||||
|
||||
|
|
@ -26,10 +23,6 @@ codegen_gcc_unknown_ctarget_feature =
|
|||
.possible_feature = you might have meant: `{$rust_feature}`
|
||||
.consider_filing_feature_request = consider filing a feature request
|
||||
|
||||
codegen_gcc_unstable_ctarget_feature =
|
||||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
codegen_gcc_missing_features =
|
||||
add the missing features in a `target_feature` attribute
|
||||
|
||||
|
|
|
|||
|
|
@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
|
||||
let attribute = match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => return None,
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => return None,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
|
||||
ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
|
||||
ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
|
||||
},
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
CanonAbi::GpuKernel => {
|
||||
if arch == "amdgpu" {
|
||||
FnAttribute::GcnAmdGpuHsaKernel
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ use rustc_middle::ty::{self, AtomicOrdering, Instance, Ty, TyCtxt};
|
|||
use rustc_span::Span;
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::callconv::FnAbi;
|
||||
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi};
|
||||
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
|
||||
|
||||
use crate::common::{SignType, TypeReflection, type_is_pointer};
|
||||
use crate::context::CodegenCx;
|
||||
|
|
@ -897,7 +897,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
fn checked_binop(
|
||||
&mut self,
|
||||
oop: OverflowOp,
|
||||
typ: Ty<'_>,
|
||||
typ: Ty<'tcx>,
|
||||
lhs: Self::Value,
|
||||
rhs: Self::Value,
|
||||
) -> (Self::Value, Self::Value) {
|
||||
|
|
@ -2394,12 +2394,6 @@ impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.cx.wasm_c_abi_opt()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
self.cx.x86_abi_opt()
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@ use rustc_middle::ty::{self, ExistentialTraitRef, Instance, Ty, TyCtxt};
|
|||
use rustc_session::Session;
|
||||
use rustc_span::source_map::respan;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use rustc_target::spec::{
|
||||
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
|
||||
};
|
||||
use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, TlsModel, X86Abi};
|
||||
|
||||
#[cfg(feature = "master")]
|
||||
use crate::abi::conv_to_fn_attribute;
|
||||
|
|
@ -512,12 +510,6 @@ impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
|
||||
fn wasm_c_abi_opt(&self) -> WasmCAbi {
|
||||
self.tcx.sess.opts.unstable_opts.wasm_c_abi
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
|
||||
fn x86_abi_opt(&self) -> X86Abi {
|
||||
X86Abi {
|
||||
|
|
|
|||
|
|
@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
|
|||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_unstable_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_forbidden_ctarget_feature)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_gcc_possible_feature)]
|
||||
|
|
|
|||
|
|
@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
|||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::errors::{
|
||||
ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
|
||||
UnstableCTargetFeature,
|
||||
};
|
||||
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
|
||||
|
||||
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
|
||||
let mut features: Vec<&str> = Vec::new();
|
||||
retpoline_features_by_flags(sess, &mut features);
|
||||
features
|
||||
}
|
||||
|
||||
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
|
|
@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(feature))
|
||||
|
|
@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
|||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some(&(_, stability, _)) => {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. (It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above).
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
stability.verify_feature_enabled_by_flag(sess, enable, feature);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -626,7 +626,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
bx.lifetime_start(llscratch, scratch_size);
|
||||
|
||||
// ... where we first store the value...
|
||||
bx.store(val, llscratch, scratch_align);
|
||||
rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
|
||||
|
||||
// ... and then memcpy it to the intended destination.
|
||||
bx.memcpy(
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ extern crate rustc_index;
|
|||
#[cfg(feature = "master")]
|
||||
extern crate rustc_interface;
|
||||
extern crate rustc_macros;
|
||||
extern crate rustc_metadata;
|
||||
extern crate rustc_middle;
|
||||
extern crate rustc_session;
|
||||
extern crate rustc_span;
|
||||
|
|
@ -106,7 +105,6 @@ use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen, TargetCon
|
|||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::sync::IntoDynSyncSend;
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::util::Providers;
|
||||
|
|
@ -230,20 +228,9 @@ impl CodegenBackend for GccCodegenBackend {
|
|||
providers.global_backend_features = |tcx, ()| gcc_util::global_gcc_features(tcx.sess, true)
|
||||
}
|
||||
|
||||
fn codegen_crate(
|
||||
&self,
|
||||
tcx: TyCtxt<'_>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box<dyn Any> {
|
||||
let target_cpu = target_cpu(tcx.sess);
|
||||
let res = codegen_crate(
|
||||
self.clone(),
|
||||
tcx,
|
||||
target_cpu.to_string(),
|
||||
metadata,
|
||||
need_metadata_module,
|
||||
);
|
||||
let res = codegen_crate(self.clone(), tcx, target_cpu.to_string());
|
||||
|
||||
Box::new(res)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto =
|
|||
|
||||
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||
|
||||
codegen_llvm_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
|
||||
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
codegen_llvm_from_llvm_diag = {$message}
|
||||
|
||||
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
|
||||
|
|
@ -76,10 +71,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
|
|||
|
||||
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
|
||||
|
||||
codegen_llvm_unstable_ctarget_feature =
|
||||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
|
||||
|
||||
codegen_llvm_write_ir = failed to write LLVM IR to {$path}
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
|
|||
let llscratch = bx.alloca(scratch_size, scratch_align);
|
||||
bx.lifetime_start(llscratch, scratch_size);
|
||||
// ...store the value...
|
||||
bx.store(val, llscratch, scratch_align);
|
||||
rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
|
||||
// ... and then memcpy it to the intended destination.
|
||||
bx.memcpy(
|
||||
dst.val.llval,
|
||||
|
|
@ -649,6 +649,10 @@ impl llvm::CallConv {
|
|||
match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
|
||||
CanonAbi::RustCold => llvm::PreserveMost,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => llvm::CCallConv,
|
||||
CanonAbi::GpuKernel => {
|
||||
if arch == "amdgpu" {
|
||||
llvm::AmdgpuKernel
|
||||
|
|
|
|||
|
|
@ -1021,6 +1021,15 @@ fn llvm_fixup_input<'ll, 'tcx>(
|
|||
) if element.primitive() == Primitive::Float(Float::F16) => {
|
||||
bx.bitcast(value, bx.type_vector(bx.type_i16(), count))
|
||||
}
|
||||
(LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F16) =>
|
||||
{
|
||||
// Smaller floats are always "NaN-boxed" inside larger floats on LoongArch.
|
||||
let value = bx.bitcast(value, bx.type_i16());
|
||||
let value = bx.zext(value, bx.type_i32());
|
||||
let value = bx.or(value, bx.const_u32(0xFFFF_0000));
|
||||
bx.bitcast(value, bx.type_f32())
|
||||
}
|
||||
(Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
|
||||
match s.primitive() {
|
||||
// MIPS only supports register-length arithmetics.
|
||||
|
|
@ -1178,6 +1187,13 @@ fn llvm_fixup_output<'ll, 'tcx>(
|
|||
) if element.primitive() == Primitive::Float(Float::F16) => {
|
||||
bx.bitcast(value, bx.type_vector(bx.type_f16(), count))
|
||||
}
|
||||
(LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F16) =>
|
||||
{
|
||||
let value = bx.bitcast(value, bx.type_i32());
|
||||
let value = bx.trunc(value, bx.type_i16());
|
||||
bx.bitcast(value, bx.type_f16())
|
||||
}
|
||||
(Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
|
||||
match s.primitive() {
|
||||
// MIPS only supports register-length arithmetics.
|
||||
|
|
@ -1318,6 +1334,11 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
|
|||
) if element.primitive() == Primitive::Float(Float::F16) => {
|
||||
cx.type_vector(cx.type_i16(), count)
|
||||
}
|
||||
(LoongArch(LoongArchInlineAsmRegClass::freg), BackendRepr::Scalar(s))
|
||||
if s.primitive() == Primitive::Float(Float::F16) =>
|
||||
{
|
||||
cx.type_f32()
|
||||
}
|
||||
(Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => {
|
||||
match s.primitive() {
|
||||
// MIPS only supports register-length arithmetics.
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
|
|
@ -256,11 +257,11 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
|
|||
StackProbeType::Inline => "inline-asm",
|
||||
// Flag our internal `__rust_probestack` function as the stack probe symbol.
|
||||
// This is defined in the `compiler-builtins` crate for each architecture.
|
||||
StackProbeType::Call => "__rust_probestack",
|
||||
StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"),
|
||||
// Pick from the two above based on the LLVM version.
|
||||
StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
|
||||
if llvm_util::get_version() < min_llvm_version_for_inline {
|
||||
"__rust_probestack"
|
||||
&mangle_internal_symbol(cx.tcx, "__rust_probestack")
|
||||
} else {
|
||||
"inline-asm"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
|
|||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::ty::layout::{
|
||||
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasTypingEnv, LayoutError, LayoutOfHelpers,
|
||||
|
|
@ -484,73 +483,31 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
fn checked_binop(
|
||||
&mut self,
|
||||
oop: OverflowOp,
|
||||
ty: Ty<'_>,
|
||||
ty: Ty<'tcx>,
|
||||
lhs: Self::Value,
|
||||
rhs: Self::Value,
|
||||
) -> (Self::Value, Self::Value) {
|
||||
use rustc_middle::ty::IntTy::*;
|
||||
use rustc_middle::ty::UintTy::*;
|
||||
use rustc_middle::ty::{Int, Uint};
|
||||
let (size, signed) = ty.int_size_and_signed(self.tcx);
|
||||
let width = size.bits();
|
||||
|
||||
let new_kind = match ty.kind() {
|
||||
Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
|
||||
Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
|
||||
t @ (Uint(_) | Int(_)) => *t,
|
||||
_ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
|
||||
if oop == OverflowOp::Sub && !signed {
|
||||
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
|
||||
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
|
||||
// in the backend if profitable.
|
||||
let sub = self.sub(lhs, rhs);
|
||||
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
|
||||
return (sub, cmp);
|
||||
}
|
||||
|
||||
let oop_str = match oop {
|
||||
OverflowOp::Add => "add",
|
||||
OverflowOp::Sub => "sub",
|
||||
OverflowOp::Mul => "mul",
|
||||
};
|
||||
|
||||
let name = match oop {
|
||||
OverflowOp::Add => match new_kind {
|
||||
Int(I8) => "llvm.sadd.with.overflow.i8",
|
||||
Int(I16) => "llvm.sadd.with.overflow.i16",
|
||||
Int(I32) => "llvm.sadd.with.overflow.i32",
|
||||
Int(I64) => "llvm.sadd.with.overflow.i64",
|
||||
Int(I128) => "llvm.sadd.with.overflow.i128",
|
||||
let name = format!("llvm.{}{oop_str}.with.overflow", if signed { 's' } else { 'u' });
|
||||
|
||||
Uint(U8) => "llvm.uadd.with.overflow.i8",
|
||||
Uint(U16) => "llvm.uadd.with.overflow.i16",
|
||||
Uint(U32) => "llvm.uadd.with.overflow.i32",
|
||||
Uint(U64) => "llvm.uadd.with.overflow.i64",
|
||||
Uint(U128) => "llvm.uadd.with.overflow.i128",
|
||||
|
||||
_ => unreachable!(),
|
||||
},
|
||||
OverflowOp::Sub => match new_kind {
|
||||
Int(I8) => "llvm.ssub.with.overflow.i8",
|
||||
Int(I16) => "llvm.ssub.with.overflow.i16",
|
||||
Int(I32) => "llvm.ssub.with.overflow.i32",
|
||||
Int(I64) => "llvm.ssub.with.overflow.i64",
|
||||
Int(I128) => "llvm.ssub.with.overflow.i128",
|
||||
|
||||
Uint(_) => {
|
||||
// Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
|
||||
// to be the canonical form. It will attempt to reform llvm.usub.with.overflow
|
||||
// in the backend if profitable.
|
||||
let sub = self.sub(lhs, rhs);
|
||||
let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
|
||||
return (sub, cmp);
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
},
|
||||
OverflowOp::Mul => match new_kind {
|
||||
Int(I8) => "llvm.smul.with.overflow.i8",
|
||||
Int(I16) => "llvm.smul.with.overflow.i16",
|
||||
Int(I32) => "llvm.smul.with.overflow.i32",
|
||||
Int(I64) => "llvm.smul.with.overflow.i64",
|
||||
Int(I128) => "llvm.smul.with.overflow.i128",
|
||||
|
||||
Uint(U8) => "llvm.umul.with.overflow.i8",
|
||||
Uint(U16) => "llvm.umul.with.overflow.i16",
|
||||
Uint(U32) => "llvm.umul.with.overflow.i32",
|
||||
Uint(U64) => "llvm.umul.with.overflow.i64",
|
||||
Uint(U128) => "llvm.umul.with.overflow.i128",
|
||||
|
||||
_ => unreachable!(),
|
||||
},
|
||||
};
|
||||
|
||||
let res = self.call_intrinsic(name, &[lhs, rhs]);
|
||||
let res = self.call_intrinsic(name, &[self.type_ix(width)], &[lhs, rhs]);
|
||||
(self.extract_value(res, 0), self.extract_value(res, 1))
|
||||
}
|
||||
|
||||
|
|
@ -954,11 +911,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
||||
self.fptoint_sat(false, val, dest_ty)
|
||||
self.call_intrinsic("llvm.fptoui.sat", &[dest_ty, self.val_ty(val)], &[val])
|
||||
}
|
||||
|
||||
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
||||
self.fptoint_sat(true, val, dest_ty)
|
||||
self.call_intrinsic("llvm.fptosi.sat", &[dest_ty, self.val_ty(val)], &[val])
|
||||
}
|
||||
|
||||
fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
||||
|
|
@ -981,15 +938,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
if self.cx.type_kind(src_ty) != TypeKind::Vector {
|
||||
let float_width = self.cx.float_width(src_ty);
|
||||
let int_width = self.cx.int_width(dest_ty);
|
||||
let name = match (int_width, float_width) {
|
||||
(32, 32) => Some("llvm.wasm.trunc.unsigned.i32.f32"),
|
||||
(32, 64) => Some("llvm.wasm.trunc.unsigned.i32.f64"),
|
||||
(64, 32) => Some("llvm.wasm.trunc.unsigned.i64.f32"),
|
||||
(64, 64) => Some("llvm.wasm.trunc.unsigned.i64.f64"),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(name) = name {
|
||||
return self.call_intrinsic(name, &[val]);
|
||||
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
|
||||
return self.call_intrinsic(
|
||||
"llvm.wasm.trunc.unsigned",
|
||||
&[dest_ty, src_ty],
|
||||
&[val],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1003,15 +957,12 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
if self.cx.type_kind(src_ty) != TypeKind::Vector {
|
||||
let float_width = self.cx.float_width(src_ty);
|
||||
let int_width = self.cx.int_width(dest_ty);
|
||||
let name = match (int_width, float_width) {
|
||||
(32, 32) => Some("llvm.wasm.trunc.signed.i32.f32"),
|
||||
(32, 64) => Some("llvm.wasm.trunc.signed.i32.f64"),
|
||||
(64, 32) => Some("llvm.wasm.trunc.signed.i64.f32"),
|
||||
(64, 64) => Some("llvm.wasm.trunc.signed.i64.f64"),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(name) = name {
|
||||
return self.call_intrinsic(name, &[val]);
|
||||
if matches!((int_width, float_width), (32 | 64, 32 | 64)) {
|
||||
return self.call_intrinsic(
|
||||
"llvm.wasm.trunc.signed",
|
||||
&[dest_ty, src_ty],
|
||||
&[val],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1084,22 +1035,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
return None;
|
||||
}
|
||||
|
||||
let name = match (ty.is_signed(), ty.primitive_size(self.tcx).bits()) {
|
||||
(true, 8) => "llvm.scmp.i8.i8",
|
||||
(true, 16) => "llvm.scmp.i8.i16",
|
||||
(true, 32) => "llvm.scmp.i8.i32",
|
||||
(true, 64) => "llvm.scmp.i8.i64",
|
||||
(true, 128) => "llvm.scmp.i8.i128",
|
||||
let size = ty.primitive_size(self.tcx);
|
||||
let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" };
|
||||
|
||||
(false, 8) => "llvm.ucmp.i8.i8",
|
||||
(false, 16) => "llvm.ucmp.i8.i16",
|
||||
(false, 32) => "llvm.ucmp.i8.i32",
|
||||
(false, 64) => "llvm.ucmp.i8.i64",
|
||||
(false, 128) => "llvm.ucmp.i8.i128",
|
||||
|
||||
_ => bug!("three-way compare unsupported for type {ty:?}"),
|
||||
};
|
||||
Some(self.call_intrinsic(name, &[lhs, rhs]))
|
||||
Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]))
|
||||
}
|
||||
|
||||
/* Miscellaneous instructions */
|
||||
|
|
@ -1385,11 +1324,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
|
||||
}
|
||||
|
||||
fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
|
||||
self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
|
||||
}
|
||||
|
||||
fn call(
|
||||
|
|
@ -1454,7 +1393,8 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> {
|
|||
// Forward to the `get_static` method of `CodegenCx`
|
||||
let global = self.cx().get_static(def_id);
|
||||
if self.cx().tcx.is_thread_local_static(def_id) {
|
||||
let pointer = self.call_intrinsic("llvm.threadlocal.address", &[global]);
|
||||
let pointer =
|
||||
self.call_intrinsic("llvm.threadlocal.address", &[self.val_ty(global)], &[global]);
|
||||
// Cast to default address space if globals are in a different addrspace
|
||||
self.pointercast(pointer, self.type_ptr())
|
||||
} else {
|
||||
|
|
@ -1649,12 +1589,17 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
|||
}
|
||||
|
||||
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
|
||||
let (ty, f) = self.cx.get_intrinsic(intrinsic);
|
||||
pub(crate) fn call_intrinsic(
|
||||
&mut self,
|
||||
base_name: impl Into<Cow<'static, str>>,
|
||||
type_params: &[&'ll Type],
|
||||
args: &[&'ll Value],
|
||||
) -> &'ll Value {
|
||||
let (ty, f) = self.cx.get_intrinsic(base_name.into(), type_params);
|
||||
self.call(ty, None, None, f, args, None, None)
|
||||
}
|
||||
|
||||
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
|
||||
fn call_lifetime_intrinsic(&mut self, intrinsic: &'static str, ptr: &'ll Value, size: Size) {
|
||||
let size = size.bytes();
|
||||
if size == 0 {
|
||||
return;
|
||||
|
|
@ -1664,7 +1609,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]);
|
||||
self.call_intrinsic(intrinsic, &[self.val_ty(ptr)], &[self.cx.const_u64(size), ptr]);
|
||||
}
|
||||
}
|
||||
impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
||||
|
|
@ -1689,31 +1634,6 @@ impl<'a, 'll, CX: Borrow<SCx<'ll>>> GenericBuilder<'a, 'll, CX> {
|
|||
}
|
||||
}
|
||||
impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
||||
fn fptoint_sat(&mut self, signed: bool, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
|
||||
let src_ty = self.cx.val_ty(val);
|
||||
let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector {
|
||||
assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
|
||||
(
|
||||
self.cx.element_type(src_ty),
|
||||
self.cx.element_type(dest_ty),
|
||||
Some(self.cx.vector_length(src_ty)),
|
||||
)
|
||||
} else {
|
||||
(src_ty, dest_ty, None)
|
||||
};
|
||||
let float_width = self.cx.float_width(float_ty);
|
||||
let int_width = self.cx.int_width(int_ty);
|
||||
|
||||
let instr = if signed { "fptosi" } else { "fptoui" };
|
||||
let name = if let Some(vector_length) = vector_length {
|
||||
format!("llvm.{instr}.sat.v{vector_length}i{int_width}.v{vector_length}f{float_width}")
|
||||
} else {
|
||||
format!("llvm.{instr}.sat.i{int_width}.f{float_width}")
|
||||
};
|
||||
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
|
||||
self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None, None)
|
||||
}
|
||||
|
||||
pub(crate) fn landing_pad(
|
||||
&mut self,
|
||||
ty: &'ll Type,
|
||||
|
|
@ -1819,7 +1739,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
// llvm.type.test intrinsic. The LowerTypeTests link-time optimization pass replaces
|
||||
// calls to this intrinsic with code to test type membership.
|
||||
let typeid = self.get_metadata_value(typeid_metadata);
|
||||
let cond = self.call_intrinsic("llvm.type.test", &[llfn, typeid]);
|
||||
let cond = self.call_intrinsic("llvm.type.test", &[], &[llfn, typeid]);
|
||||
let bb_pass = self.append_sibling_block("type_test.pass");
|
||||
let bb_fail = self.append_sibling_block("type_test.fail");
|
||||
self.cond_br(cond, bb_pass, bb_fail);
|
||||
|
|
@ -1887,7 +1807,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
num_counters: &'ll Value,
|
||||
index: &'ll Value,
|
||||
) {
|
||||
self.call_intrinsic("llvm.instrprof.increment", &[fn_name, hash, num_counters, index]);
|
||||
self.call_intrinsic("llvm.instrprof.increment", &[], &[fn_name, hash, num_counters, index]);
|
||||
}
|
||||
|
||||
/// Emits a call to `llvm.instrprof.mcdc.parameters`.
|
||||
|
|
@ -1906,7 +1826,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
hash: &'ll Value,
|
||||
bitmap_bits: &'ll Value,
|
||||
) {
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[fn_name, hash, bitmap_bits]);
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.parameters", &[], &[fn_name, hash, bitmap_bits]);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
@ -1918,7 +1838,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
|
|||
mcdc_temp: &'ll Value,
|
||||
) {
|
||||
let args = &[fn_name, hash, bitmap_index, mcdc_temp];
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", args);
|
||||
self.call_intrinsic("llvm.instrprof.mcdc.tvbitmap.update", &[], args);
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ fn match_args_from_caller_to_enzyme<'ll>(
|
|||
let mul = unsafe {
|
||||
llvm::LLVMBuildMul(
|
||||
builder.llbuilder,
|
||||
cx.get_const_i64(elem_bytes_size),
|
||||
cx.get_const_int(cx.type_i64(), elem_bytes_size),
|
||||
next_outer_arg,
|
||||
UNNAMED,
|
||||
)
|
||||
|
|
@ -385,7 +385,7 @@ fn generate_enzyme_call<'ll>(
|
|||
if attrs.width > 1 {
|
||||
let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap();
|
||||
args.push(cx.get_metadata_value(enzyme_width));
|
||||
args.push(cx.get_const_i64(attrs.width as u64));
|
||||
args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64));
|
||||
}
|
||||
|
||||
let has_sret = has_sret(outer_fn);
|
||||
|
|
|
|||
|
|
@ -99,14 +99,14 @@ impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericCx<'ll, CX> {
|
|||
type DIVariable = &'ll llvm::debuginfo::DIVariable;
|
||||
}
|
||||
|
||||
impl<'ll> CodegenCx<'ll, '_> {
|
||||
impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
||||
pub(crate) fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
|
||||
let len = u64::try_from(elts.len()).expect("LLVMConstArray2 elements len overflow");
|
||||
unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) }
|
||||
}
|
||||
|
||||
pub(crate) fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
|
||||
bytes_in_context(self.llcx, bytes)
|
||||
bytes_in_context(self.llcx(), bytes)
|
||||
}
|
||||
|
||||
pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::borrow::{Borrow, Cow};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ffi::{CStr, c_char, c_uint};
|
||||
use std::marker::PhantomData;
|
||||
|
|
@ -137,7 +137,8 @@ pub(crate) struct FullCx<'ll, 'tcx> {
|
|||
eh_catch_typeinfo: Cell<Option<&'ll Value>>,
|
||||
pub rust_try_fn: Cell<Option<(&'ll Type, &'ll Value)>>,
|
||||
|
||||
intrinsics: RefCell<FxHashMap<&'static str, (&'ll Type, &'ll Value)>>,
|
||||
intrinsics:
|
||||
RefCell<FxHashMap<(Cow<'static, str>, SmallVec<[&'ll Type; 2]>), (&'ll Type, &'ll Value)>>,
|
||||
|
||||
/// A counter that is used for generating local symbol names
|
||||
local_gen_sym_counter: Cell<usize>,
|
||||
|
|
@ -678,11 +679,8 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
llvm::LLVMMetadataAsValue(self.llcx(), metadata)
|
||||
}
|
||||
|
||||
// FIXME(autodiff): We should split `ConstCodegenMethods` to pull the reusable parts
|
||||
// onto a trait that is also implemented for GenericCx.
|
||||
pub(crate) fn get_const_i64(&self, n: u64) -> &'ll Value {
|
||||
let ty = unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) };
|
||||
unsafe { llvm::LLVMConstInt(ty, n, llvm::False) }
|
||||
pub(crate) fn get_const_int(&self, ty: &'ll Type, val: u64) -> &'ll Value {
|
||||
unsafe { llvm::LLVMConstInt(ty, val, llvm::False) }
|
||||
}
|
||||
|
||||
pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> {
|
||||
|
|
@ -842,410 +840,41 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
}
|
||||
|
||||
impl<'ll> CodegenCx<'ll, '_> {
|
||||
pub(crate) fn get_intrinsic(&self, key: &str) -> (&'ll Type, &'ll Value) {
|
||||
if let Some(v) = self.intrinsics.borrow().get(key).cloned() {
|
||||
return v;
|
||||
}
|
||||
|
||||
self.declare_intrinsic(key).unwrap_or_else(|| bug!("unknown intrinsic '{}'", key))
|
||||
}
|
||||
|
||||
fn insert_intrinsic(
|
||||
pub(crate) fn get_intrinsic(
|
||||
&self,
|
||||
name: &'static str,
|
||||
args: Option<&[&'ll llvm::Type]>,
|
||||
ret: &'ll llvm::Type,
|
||||
) -> (&'ll llvm::Type, &'ll llvm::Value) {
|
||||
let fn_ty = if let Some(args) = args {
|
||||
self.type_func(args, ret)
|
||||
} else {
|
||||
self.type_variadic_func(&[], ret)
|
||||
};
|
||||
let f = self.declare_cfn(name, llvm::UnnamedAddr::No, fn_ty);
|
||||
self.intrinsics.borrow_mut().insert(name, (fn_ty, f));
|
||||
(fn_ty, f)
|
||||
base_name: Cow<'static, str>,
|
||||
type_params: &[&'ll Type],
|
||||
) -> (&'ll Type, &'ll Value) {
|
||||
*self
|
||||
.intrinsics
|
||||
.borrow_mut()
|
||||
.entry((base_name, SmallVec::from_slice(type_params)))
|
||||
.or_insert_with_key(|(base_name, type_params)| {
|
||||
self.declare_intrinsic(base_name, type_params)
|
||||
})
|
||||
}
|
||||
|
||||
fn declare_intrinsic(&self, key: &str) -> Option<(&'ll Type, &'ll Value)> {
|
||||
macro_rules! ifn {
|
||||
($name:expr, fn() -> $ret:expr) => (
|
||||
if key == $name {
|
||||
return Some(self.insert_intrinsic($name, Some(&[]), $ret));
|
||||
}
|
||||
);
|
||||
($name:expr, fn(...) -> $ret:expr) => (
|
||||
if key == $name {
|
||||
return Some(self.insert_intrinsic($name, None, $ret));
|
||||
}
|
||||
);
|
||||
($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
|
||||
if key == $name {
|
||||
return Some(self.insert_intrinsic($name, Some(&[$($arg),*]), $ret));
|
||||
}
|
||||
);
|
||||
}
|
||||
macro_rules! mk_struct {
|
||||
($($field_ty:expr),*) => (self.type_struct( &[$($field_ty),*], false))
|
||||
}
|
||||
|
||||
let ptr = self.type_ptr();
|
||||
let void = self.type_void();
|
||||
let i1 = self.type_i1();
|
||||
let t_i8 = self.type_i8();
|
||||
let t_i16 = self.type_i16();
|
||||
let t_i32 = self.type_i32();
|
||||
let t_i64 = self.type_i64();
|
||||
let t_i128 = self.type_i128();
|
||||
let t_isize = self.type_isize();
|
||||
let t_f16 = self.type_f16();
|
||||
let t_f32 = self.type_f32();
|
||||
let t_f64 = self.type_f64();
|
||||
let t_f128 = self.type_f128();
|
||||
let t_metadata = self.type_metadata();
|
||||
let t_token = self.type_token();
|
||||
|
||||
ifn!("llvm.wasm.get.exception", fn(t_token) -> ptr);
|
||||
ifn!("llvm.wasm.get.ehselector", fn(t_token) -> t_i32);
|
||||
|
||||
ifn!("llvm.wasm.trunc.unsigned.i32.f32", fn(t_f32) -> t_i32);
|
||||
ifn!("llvm.wasm.trunc.unsigned.i32.f64", fn(t_f64) -> t_i32);
|
||||
ifn!("llvm.wasm.trunc.unsigned.i64.f32", fn(t_f32) -> t_i64);
|
||||
ifn!("llvm.wasm.trunc.unsigned.i64.f64", fn(t_f64) -> t_i64);
|
||||
ifn!("llvm.wasm.trunc.signed.i32.f32", fn(t_f32) -> t_i32);
|
||||
ifn!("llvm.wasm.trunc.signed.i32.f64", fn(t_f64) -> t_i32);
|
||||
ifn!("llvm.wasm.trunc.signed.i64.f32", fn(t_f32) -> t_i64);
|
||||
ifn!("llvm.wasm.trunc.signed.i64.f64", fn(t_f64) -> t_i64);
|
||||
|
||||
ifn!("llvm.fptosi.sat.i8.f32", fn(t_f32) -> t_i8);
|
||||
ifn!("llvm.fptosi.sat.i16.f32", fn(t_f32) -> t_i16);
|
||||
ifn!("llvm.fptosi.sat.i32.f32", fn(t_f32) -> t_i32);
|
||||
ifn!("llvm.fptosi.sat.i64.f32", fn(t_f32) -> t_i64);
|
||||
ifn!("llvm.fptosi.sat.i128.f32", fn(t_f32) -> t_i128);
|
||||
ifn!("llvm.fptosi.sat.i8.f64", fn(t_f64) -> t_i8);
|
||||
ifn!("llvm.fptosi.sat.i16.f64", fn(t_f64) -> t_i16);
|
||||
ifn!("llvm.fptosi.sat.i32.f64", fn(t_f64) -> t_i32);
|
||||
ifn!("llvm.fptosi.sat.i64.f64", fn(t_f64) -> t_i64);
|
||||
ifn!("llvm.fptosi.sat.i128.f64", fn(t_f64) -> t_i128);
|
||||
|
||||
ifn!("llvm.fptoui.sat.i8.f32", fn(t_f32) -> t_i8);
|
||||
ifn!("llvm.fptoui.sat.i16.f32", fn(t_f32) -> t_i16);
|
||||
ifn!("llvm.fptoui.sat.i32.f32", fn(t_f32) -> t_i32);
|
||||
ifn!("llvm.fptoui.sat.i64.f32", fn(t_f32) -> t_i64);
|
||||
ifn!("llvm.fptoui.sat.i128.f32", fn(t_f32) -> t_i128);
|
||||
ifn!("llvm.fptoui.sat.i8.f64", fn(t_f64) -> t_i8);
|
||||
ifn!("llvm.fptoui.sat.i16.f64", fn(t_f64) -> t_i16);
|
||||
ifn!("llvm.fptoui.sat.i32.f64", fn(t_f64) -> t_i32);
|
||||
ifn!("llvm.fptoui.sat.i64.f64", fn(t_f64) -> t_i64);
|
||||
ifn!("llvm.fptoui.sat.i128.f64", fn(t_f64) -> t_i128);
|
||||
|
||||
ifn!("llvm.trap", fn() -> void);
|
||||
ifn!("llvm.debugtrap", fn() -> void);
|
||||
ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
|
||||
|
||||
ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16);
|
||||
ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32);
|
||||
ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64);
|
||||
ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128);
|
||||
|
||||
ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.pow.f128", fn(t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.sqrt.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.sqrt.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.sin.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.sin.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.sin.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.sin.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.cos.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.cos.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.cos.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.cos.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.exp.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.exp.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.exp.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.exp.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.exp2.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.exp2.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.log.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.log.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.log.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.log.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.log10.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.log10.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.log10.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.log10.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.log2.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.log2.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.log2.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.log2.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.fma.f16", fn(t_f16, t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.fma.f128", fn(t_f128, t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.fmuladd.f16", fn(t_f16, t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.fmuladd.f32", fn(t_f32, t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.fmuladd.f64", fn(t_f64, t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.fmuladd.f128", fn(t_f128, t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.fabs.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.fabs.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.minnum.f16", fn(t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.minnum.f128", fn(t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.minimum.f16", fn(t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.minimum.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.minimum.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
// There are issues on x86_64 and aarch64 with the f128 variant.
|
||||
// - https://github.com/llvm/llvm-project/issues/139380
|
||||
// - https://github.com/llvm/llvm-project/issues/139381
|
||||
// ifn!("llvm.minimum.f128", fn(t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.maxnum.f16", fn(t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.maxnum.f128", fn(t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.maximum.f16", fn(t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.maximum.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.maximum.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
// There are issues on x86_64 and aarch64 with the f128 variant.
|
||||
// - https://github.com/llvm/llvm-project/issues/139380
|
||||
// - https://github.com/llvm/llvm-project/issues/139381
|
||||
// ifn!("llvm.maximum.f128", fn(t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.floor.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.floor.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.floor.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.ceil.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.ceil.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.trunc.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.trunc.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.copysign.f16", fn(t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64);
|
||||
ifn!("llvm.copysign.f128", fn(t_f128, t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.round.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.round.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.round.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.round.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.roundeven.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.roundeven.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.rint.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.rint.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.rint.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.rint.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.nearbyint.f16", fn(t_f16) -> t_f16);
|
||||
ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32);
|
||||
ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64);
|
||||
ifn!("llvm.nearbyint.f128", fn(t_f128) -> t_f128);
|
||||
|
||||
ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8);
|
||||
ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16);
|
||||
ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32);
|
||||
ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64);
|
||||
ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.ctlz.i8", fn(t_i8, i1) -> t_i8);
|
||||
ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16);
|
||||
ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32);
|
||||
ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64);
|
||||
ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128);
|
||||
|
||||
ifn!("llvm.cttz.i8", fn(t_i8, i1) -> t_i8);
|
||||
ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16);
|
||||
ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32);
|
||||
ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64);
|
||||
ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128);
|
||||
|
||||
ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16);
|
||||
ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32);
|
||||
ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64);
|
||||
ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8);
|
||||
ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16);
|
||||
ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32);
|
||||
ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64);
|
||||
ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.fshl.i8", fn(t_i8, t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.fshl.i16", fn(t_i16, t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.fshl.i32", fn(t_i32, t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.fshl.i64", fn(t_i64, t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.fshl.i128", fn(t_i128, t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.fshr.i8", fn(t_i8, t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.fshr.i16", fn(t_i16, t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.fshr.i32", fn(t_i32, t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.fshr.i64", fn(t_i64, t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.fshr.i128", fn(t_i128, t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1});
|
||||
ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1});
|
||||
ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1});
|
||||
ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1});
|
||||
ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1});
|
||||
|
||||
ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1});
|
||||
ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1});
|
||||
ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1});
|
||||
ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1});
|
||||
ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1});
|
||||
|
||||
ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1});
|
||||
ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1});
|
||||
ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1});
|
||||
ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1});
|
||||
ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1});
|
||||
|
||||
ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1});
|
||||
ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1});
|
||||
ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1});
|
||||
ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1});
|
||||
ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1});
|
||||
|
||||
ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1});
|
||||
ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1});
|
||||
ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1});
|
||||
ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1});
|
||||
ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1});
|
||||
|
||||
ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct! {t_i8, i1});
|
||||
ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct! {t_i16, i1});
|
||||
ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct! {t_i32, i1});
|
||||
ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct! {t_i64, i1});
|
||||
ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct! {t_i128, i1});
|
||||
|
||||
ifn!("llvm.sadd.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.sadd.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.sadd.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.sadd.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.sadd.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.uadd.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.uadd.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.uadd.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.uadd.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.uadd.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.ssub.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.ssub.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.ssub.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.ssub.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.ssub.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.usub.sat.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.usub.sat.i16", fn(t_i16, t_i16) -> t_i16);
|
||||
ifn!("llvm.usub.sat.i32", fn(t_i32, t_i32) -> t_i32);
|
||||
ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64);
|
||||
ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128);
|
||||
|
||||
ifn!("llvm.scmp.i8.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.scmp.i8.i16", fn(t_i16, t_i16) -> t_i8);
|
||||
ifn!("llvm.scmp.i8.i32", fn(t_i32, t_i32) -> t_i8);
|
||||
ifn!("llvm.scmp.i8.i64", fn(t_i64, t_i64) -> t_i8);
|
||||
ifn!("llvm.scmp.i8.i128", fn(t_i128, t_i128) -> t_i8);
|
||||
|
||||
ifn!("llvm.ucmp.i8.i8", fn(t_i8, t_i8) -> t_i8);
|
||||
ifn!("llvm.ucmp.i8.i16", fn(t_i16, t_i16) -> t_i8);
|
||||
ifn!("llvm.ucmp.i8.i32", fn(t_i32, t_i32) -> t_i8);
|
||||
ifn!("llvm.ucmp.i8.i64", fn(t_i64, t_i64) -> t_i8);
|
||||
ifn!("llvm.ucmp.i8.i128", fn(t_i128, t_i128) -> t_i8);
|
||||
|
||||
ifn!("llvm.lifetime.start.p0i8", fn(t_i64, ptr) -> void);
|
||||
ifn!("llvm.lifetime.end.p0i8", fn(t_i64, ptr) -> void);
|
||||
|
||||
// FIXME: This is an infinitesimally small portion of the types you can
|
||||
// pass to this intrinsic, if we can ever lazily register intrinsics we
|
||||
// should register these when they're used, that way any type can be
|
||||
// passed.
|
||||
ifn!("llvm.is.constant.i1", fn(i1) -> i1);
|
||||
ifn!("llvm.is.constant.i8", fn(t_i8) -> i1);
|
||||
ifn!("llvm.is.constant.i16", fn(t_i16) -> i1);
|
||||
ifn!("llvm.is.constant.i32", fn(t_i32) -> i1);
|
||||
ifn!("llvm.is.constant.i64", fn(t_i64) -> i1);
|
||||
ifn!("llvm.is.constant.i128", fn(t_i128) -> i1);
|
||||
ifn!("llvm.is.constant.isize", fn(t_isize) -> i1);
|
||||
ifn!("llvm.is.constant.f16", fn(t_f16) -> i1);
|
||||
ifn!("llvm.is.constant.f32", fn(t_f32) -> i1);
|
||||
ifn!("llvm.is.constant.f64", fn(t_f64) -> i1);
|
||||
ifn!("llvm.is.constant.f128", fn(t_f128) -> i1);
|
||||
ifn!("llvm.is.constant.ptr", fn(ptr) -> i1);
|
||||
|
||||
ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
|
||||
ifn!("llvm.eh.typeid.for", fn(ptr) -> t_i32);
|
||||
ifn!("llvm.localescape", fn(...) -> void);
|
||||
ifn!("llvm.localrecover", fn(ptr, ptr, t_i32) -> ptr);
|
||||
ifn!("llvm.x86.seh.recoverfp", fn(ptr, ptr) -> ptr);
|
||||
|
||||
ifn!("llvm.assume", fn(i1) -> void);
|
||||
ifn!("llvm.prefetch", fn(ptr, t_i32, t_i32, t_i32) -> void);
|
||||
|
||||
fn declare_intrinsic(
|
||||
&self,
|
||||
base_name: &str,
|
||||
type_params: &[&'ll Type],
|
||||
) -> (&'ll Type, &'ll Value) {
|
||||
// This isn't an "LLVM intrinsic", but LLVM's optimization passes
|
||||
// recognize it like one (including turning it into `bcmp` sometimes)
|
||||
// and we use it to implement intrinsics like `raw_eq` and `compare_bytes`
|
||||
match self.sess().target.arch.as_ref() {
|
||||
"avr" | "msp430" => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i16),
|
||||
_ => ifn!("memcmp", fn(ptr, ptr, t_isize) -> t_i32),
|
||||
if base_name == "memcmp" {
|
||||
let fn_ty = self
|
||||
.type_func(&[self.type_ptr(), self.type_ptr(), self.type_isize()], self.type_int());
|
||||
let f = self.declare_cfn("memcmp", llvm::UnnamedAddr::No, fn_ty);
|
||||
|
||||
return (fn_ty, f);
|
||||
}
|
||||
|
||||
// variadic intrinsics
|
||||
ifn!("llvm.va_start", fn(ptr) -> void);
|
||||
ifn!("llvm.va_end", fn(ptr) -> void);
|
||||
ifn!("llvm.va_copy", fn(ptr, ptr) -> void);
|
||||
let intrinsic = llvm::Intrinsic::lookup(base_name.as_bytes())
|
||||
.unwrap_or_else(|| bug!("Unknown intrinsic: `{base_name}`"));
|
||||
let f = intrinsic.get_declaration(self.llmod, &type_params);
|
||||
|
||||
if self.sess().instrument_coverage() {
|
||||
ifn!("llvm.instrprof.increment", fn(ptr, t_i64, t_i32, t_i32) -> void);
|
||||
ifn!("llvm.instrprof.mcdc.parameters", fn(ptr, t_i64, t_i32) -> void);
|
||||
ifn!("llvm.instrprof.mcdc.tvbitmap.update", fn(ptr, t_i64, t_i32, ptr) -> void);
|
||||
}
|
||||
|
||||
ifn!("llvm.type.test", fn(ptr, t_metadata) -> i1);
|
||||
ifn!("llvm.type.checked.load", fn(ptr, t_i32, t_metadata) -> mk_struct! {ptr, i1});
|
||||
|
||||
if self.sess().opts.debuginfo != DebugInfo::None {
|
||||
ifn!("llvm.dbg.declare", fn(t_metadata, t_metadata) -> void);
|
||||
ifn!("llvm.dbg.value", fn(t_metadata, t_i64, t_metadata) -> void);
|
||||
}
|
||||
|
||||
ifn!("llvm.ptrmask", fn(ptr, t_isize) -> ptr);
|
||||
ifn!("llvm.threadlocal.address", fn(ptr) -> ptr);
|
||||
|
||||
None
|
||||
(self.get_type_of_global(f), f)
|
||||
}
|
||||
|
||||
pub(crate) fn eh_catch_typeinfo(&self) -> &'ll Value {
|
||||
|
|
|
|||
|
|
@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
|
|||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_unstable_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_forbidden_ctarget_feature)]
|
||||
#[note]
|
||||
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub enabled: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_llvm_possible_feature)]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty};
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_target::spec::{HasTargetSpec, PanicStrategy};
|
||||
use rustc_target::spec::PanicStrategy;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::abi::FnAbiLlvmExt;
|
||||
|
|
@ -27,137 +27,140 @@ use crate::type_of::LayoutLlvmExt;
|
|||
use crate::va_arg::emit_va_arg;
|
||||
use crate::value::Value;
|
||||
|
||||
fn get_simple_intrinsic<'ll>(
|
||||
cx: &CodegenCx<'ll, '_>,
|
||||
fn call_simple_intrinsic<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
name: Symbol,
|
||||
) -> Option<(&'ll Type, &'ll Value)> {
|
||||
let llvm_name = match name {
|
||||
sym::sqrtf16 => "llvm.sqrt.f16",
|
||||
sym::sqrtf32 => "llvm.sqrt.f32",
|
||||
sym::sqrtf64 => "llvm.sqrt.f64",
|
||||
sym::sqrtf128 => "llvm.sqrt.f128",
|
||||
args: &[OperandRef<'tcx, &'ll Value>],
|
||||
) -> Option<&'ll Value> {
|
||||
let (base_name, type_params): (&'static str, &[&'ll Type]) = match name {
|
||||
sym::sqrtf16 => ("llvm.sqrt", &[bx.type_f16()]),
|
||||
sym::sqrtf32 => ("llvm.sqrt", &[bx.type_f32()]),
|
||||
sym::sqrtf64 => ("llvm.sqrt", &[bx.type_f64()]),
|
||||
sym::sqrtf128 => ("llvm.sqrt", &[bx.type_f128()]),
|
||||
|
||||
sym::powif16 => "llvm.powi.f16.i32",
|
||||
sym::powif32 => "llvm.powi.f32.i32",
|
||||
sym::powif64 => "llvm.powi.f64.i32",
|
||||
sym::powif128 => "llvm.powi.f128.i32",
|
||||
sym::powif16 => ("llvm.powi", &[bx.type_f16(), bx.type_i32()]),
|
||||
sym::powif32 => ("llvm.powi", &[bx.type_f32(), bx.type_i32()]),
|
||||
sym::powif64 => ("llvm.powi", &[bx.type_f64(), bx.type_i32()]),
|
||||
sym::powif128 => ("llvm.powi", &[bx.type_f128(), bx.type_i32()]),
|
||||
|
||||
sym::sinf16 => "llvm.sin.f16",
|
||||
sym::sinf32 => "llvm.sin.f32",
|
||||
sym::sinf64 => "llvm.sin.f64",
|
||||
sym::sinf128 => "llvm.sin.f128",
|
||||
sym::sinf16 => ("llvm.sin", &[bx.type_f16()]),
|
||||
sym::sinf32 => ("llvm.sin", &[bx.type_f32()]),
|
||||
sym::sinf64 => ("llvm.sin", &[bx.type_f64()]),
|
||||
sym::sinf128 => ("llvm.sin", &[bx.type_f128()]),
|
||||
|
||||
sym::cosf16 => "llvm.cos.f16",
|
||||
sym::cosf32 => "llvm.cos.f32",
|
||||
sym::cosf64 => "llvm.cos.f64",
|
||||
sym::cosf128 => "llvm.cos.f128",
|
||||
sym::cosf16 => ("llvm.cos", &[bx.type_f16()]),
|
||||
sym::cosf32 => ("llvm.cos", &[bx.type_f32()]),
|
||||
sym::cosf64 => ("llvm.cos", &[bx.type_f64()]),
|
||||
sym::cosf128 => ("llvm.cos", &[bx.type_f128()]),
|
||||
|
||||
sym::powf16 => "llvm.pow.f16",
|
||||
sym::powf32 => "llvm.pow.f32",
|
||||
sym::powf64 => "llvm.pow.f64",
|
||||
sym::powf128 => "llvm.pow.f128",
|
||||
sym::powf16 => ("llvm.pow", &[bx.type_f16()]),
|
||||
sym::powf32 => ("llvm.pow", &[bx.type_f32()]),
|
||||
sym::powf64 => ("llvm.pow", &[bx.type_f64()]),
|
||||
sym::powf128 => ("llvm.pow", &[bx.type_f128()]),
|
||||
|
||||
sym::expf16 => "llvm.exp.f16",
|
||||
sym::expf32 => "llvm.exp.f32",
|
||||
sym::expf64 => "llvm.exp.f64",
|
||||
sym::expf128 => "llvm.exp.f128",
|
||||
sym::expf16 => ("llvm.exp", &[bx.type_f16()]),
|
||||
sym::expf32 => ("llvm.exp", &[bx.type_f32()]),
|
||||
sym::expf64 => ("llvm.exp", &[bx.type_f64()]),
|
||||
sym::expf128 => ("llvm.exp", &[bx.type_f128()]),
|
||||
|
||||
sym::exp2f16 => "llvm.exp2.f16",
|
||||
sym::exp2f32 => "llvm.exp2.f32",
|
||||
sym::exp2f64 => "llvm.exp2.f64",
|
||||
sym::exp2f128 => "llvm.exp2.f128",
|
||||
sym::exp2f16 => ("llvm.exp2", &[bx.type_f16()]),
|
||||
sym::exp2f32 => ("llvm.exp2", &[bx.type_f32()]),
|
||||
sym::exp2f64 => ("llvm.exp2", &[bx.type_f64()]),
|
||||
sym::exp2f128 => ("llvm.exp2", &[bx.type_f128()]),
|
||||
|
||||
sym::logf16 => "llvm.log.f16",
|
||||
sym::logf32 => "llvm.log.f32",
|
||||
sym::logf64 => "llvm.log.f64",
|
||||
sym::logf128 => "llvm.log.f128",
|
||||
sym::logf16 => ("llvm.log", &[bx.type_f16()]),
|
||||
sym::logf32 => ("llvm.log", &[bx.type_f32()]),
|
||||
sym::logf64 => ("llvm.log", &[bx.type_f64()]),
|
||||
sym::logf128 => ("llvm.log", &[bx.type_f128()]),
|
||||
|
||||
sym::log10f16 => "llvm.log10.f16",
|
||||
sym::log10f32 => "llvm.log10.f32",
|
||||
sym::log10f64 => "llvm.log10.f64",
|
||||
sym::log10f128 => "llvm.log10.f128",
|
||||
sym::log10f16 => ("llvm.log10", &[bx.type_f16()]),
|
||||
sym::log10f32 => ("llvm.log10", &[bx.type_f32()]),
|
||||
sym::log10f64 => ("llvm.log10", &[bx.type_f64()]),
|
||||
sym::log10f128 => ("llvm.log10", &[bx.type_f128()]),
|
||||
|
||||
sym::log2f16 => "llvm.log2.f16",
|
||||
sym::log2f32 => "llvm.log2.f32",
|
||||
sym::log2f64 => "llvm.log2.f64",
|
||||
sym::log2f128 => "llvm.log2.f128",
|
||||
sym::log2f16 => ("llvm.log2", &[bx.type_f16()]),
|
||||
sym::log2f32 => ("llvm.log2", &[bx.type_f32()]),
|
||||
sym::log2f64 => ("llvm.log2", &[bx.type_f64()]),
|
||||
sym::log2f128 => ("llvm.log2", &[bx.type_f128()]),
|
||||
|
||||
sym::fmaf16 => "llvm.fma.f16",
|
||||
sym::fmaf32 => "llvm.fma.f32",
|
||||
sym::fmaf64 => "llvm.fma.f64",
|
||||
sym::fmaf128 => "llvm.fma.f128",
|
||||
sym::fmaf16 => ("llvm.fma", &[bx.type_f16()]),
|
||||
sym::fmaf32 => ("llvm.fma", &[bx.type_f32()]),
|
||||
sym::fmaf64 => ("llvm.fma", &[bx.type_f64()]),
|
||||
sym::fmaf128 => ("llvm.fma", &[bx.type_f128()]),
|
||||
|
||||
sym::fmuladdf16 => "llvm.fmuladd.f16",
|
||||
sym::fmuladdf32 => "llvm.fmuladd.f32",
|
||||
sym::fmuladdf64 => "llvm.fmuladd.f64",
|
||||
sym::fmuladdf128 => "llvm.fmuladd.f128",
|
||||
sym::fmuladdf16 => ("llvm.fmuladd", &[bx.type_f16()]),
|
||||
sym::fmuladdf32 => ("llvm.fmuladd", &[bx.type_f32()]),
|
||||
sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]),
|
||||
sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]),
|
||||
|
||||
sym::fabsf16 => "llvm.fabs.f16",
|
||||
sym::fabsf32 => "llvm.fabs.f32",
|
||||
sym::fabsf64 => "llvm.fabs.f64",
|
||||
sym::fabsf128 => "llvm.fabs.f128",
|
||||
sym::fabsf16 => ("llvm.fabs", &[bx.type_f16()]),
|
||||
sym::fabsf32 => ("llvm.fabs", &[bx.type_f32()]),
|
||||
sym::fabsf64 => ("llvm.fabs", &[bx.type_f64()]),
|
||||
sym::fabsf128 => ("llvm.fabs", &[bx.type_f128()]),
|
||||
|
||||
sym::minnumf16 => "llvm.minnum.f16",
|
||||
sym::minnumf32 => "llvm.minnum.f32",
|
||||
sym::minnumf64 => "llvm.minnum.f64",
|
||||
sym::minnumf128 => "llvm.minnum.f128",
|
||||
sym::minnumf16 => ("llvm.minnum", &[bx.type_f16()]),
|
||||
sym::minnumf32 => ("llvm.minnum", &[bx.type_f32()]),
|
||||
sym::minnumf64 => ("llvm.minnum", &[bx.type_f64()]),
|
||||
sym::minnumf128 => ("llvm.minnum", &[bx.type_f128()]),
|
||||
|
||||
sym::minimumf16 => "llvm.minimum.f16",
|
||||
sym::minimumf32 => "llvm.minimum.f32",
|
||||
sym::minimumf64 => "llvm.minimum.f64",
|
||||
sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]),
|
||||
sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]),
|
||||
sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]),
|
||||
// There are issues on x86_64 and aarch64 with the f128 variant,
|
||||
// let's instead use the instrinsic fallback body.
|
||||
// sym::minimumf128 => "llvm.minimum.f128",
|
||||
sym::maxnumf16 => "llvm.maxnum.f16",
|
||||
sym::maxnumf32 => "llvm.maxnum.f32",
|
||||
sym::maxnumf64 => "llvm.maxnum.f64",
|
||||
sym::maxnumf128 => "llvm.maxnum.f128",
|
||||
// sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]),
|
||||
sym::maxnumf16 => ("llvm.maxnum", &[bx.type_f16()]),
|
||||
sym::maxnumf32 => ("llvm.maxnum", &[bx.type_f32()]),
|
||||
sym::maxnumf64 => ("llvm.maxnum", &[bx.type_f64()]),
|
||||
sym::maxnumf128 => ("llvm.maxnum", &[bx.type_f128()]),
|
||||
|
||||
sym::maximumf16 => "llvm.maximum.f16",
|
||||
sym::maximumf32 => "llvm.maximum.f32",
|
||||
sym::maximumf64 => "llvm.maximum.f64",
|
||||
sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]),
|
||||
sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]),
|
||||
sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]),
|
||||
// There are issues on x86_64 and aarch64 with the f128 variant,
|
||||
// let's instead use the instrinsic fallback body.
|
||||
// sym::maximumf128 => "llvm.maximum.f128",
|
||||
sym::copysignf16 => "llvm.copysign.f16",
|
||||
sym::copysignf32 => "llvm.copysign.f32",
|
||||
sym::copysignf64 => "llvm.copysign.f64",
|
||||
sym::copysignf128 => "llvm.copysign.f128",
|
||||
// sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]),
|
||||
sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]),
|
||||
sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]),
|
||||
sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]),
|
||||
sym::copysignf128 => ("llvm.copysign", &[bx.type_f128()]),
|
||||
|
||||
sym::floorf16 => "llvm.floor.f16",
|
||||
sym::floorf32 => "llvm.floor.f32",
|
||||
sym::floorf64 => "llvm.floor.f64",
|
||||
sym::floorf128 => "llvm.floor.f128",
|
||||
sym::floorf16 => ("llvm.floor", &[bx.type_f16()]),
|
||||
sym::floorf32 => ("llvm.floor", &[bx.type_f32()]),
|
||||
sym::floorf64 => ("llvm.floor", &[bx.type_f64()]),
|
||||
sym::floorf128 => ("llvm.floor", &[bx.type_f128()]),
|
||||
|
||||
sym::ceilf16 => "llvm.ceil.f16",
|
||||
sym::ceilf32 => "llvm.ceil.f32",
|
||||
sym::ceilf64 => "llvm.ceil.f64",
|
||||
sym::ceilf128 => "llvm.ceil.f128",
|
||||
sym::ceilf16 => ("llvm.ceil", &[bx.type_f16()]),
|
||||
sym::ceilf32 => ("llvm.ceil", &[bx.type_f32()]),
|
||||
sym::ceilf64 => ("llvm.ceil", &[bx.type_f64()]),
|
||||
sym::ceilf128 => ("llvm.ceil", &[bx.type_f128()]),
|
||||
|
||||
sym::truncf16 => "llvm.trunc.f16",
|
||||
sym::truncf32 => "llvm.trunc.f32",
|
||||
sym::truncf64 => "llvm.trunc.f64",
|
||||
sym::truncf128 => "llvm.trunc.f128",
|
||||
sym::truncf16 => ("llvm.trunc", &[bx.type_f16()]),
|
||||
sym::truncf32 => ("llvm.trunc", &[bx.type_f32()]),
|
||||
sym::truncf64 => ("llvm.trunc", &[bx.type_f64()]),
|
||||
sym::truncf128 => ("llvm.trunc", &[bx.type_f128()]),
|
||||
|
||||
// We could use any of `rint`, `nearbyint`, or `roundeven`
|
||||
// for this -- they are all identical in semantics when
|
||||
// assuming the default FP environment.
|
||||
// `rint` is what we used for $forever.
|
||||
sym::round_ties_even_f16 => "llvm.rint.f16",
|
||||
sym::round_ties_even_f32 => "llvm.rint.f32",
|
||||
sym::round_ties_even_f64 => "llvm.rint.f64",
|
||||
sym::round_ties_even_f128 => "llvm.rint.f128",
|
||||
sym::round_ties_even_f16 => ("llvm.rint", &[bx.type_f16()]),
|
||||
sym::round_ties_even_f32 => ("llvm.rint", &[bx.type_f32()]),
|
||||
sym::round_ties_even_f64 => ("llvm.rint", &[bx.type_f64()]),
|
||||
sym::round_ties_even_f128 => ("llvm.rint", &[bx.type_f128()]),
|
||||
|
||||
sym::roundf16 => "llvm.round.f16",
|
||||
sym::roundf32 => "llvm.round.f32",
|
||||
sym::roundf64 => "llvm.round.f64",
|
||||
sym::roundf128 => "llvm.round.f128",
|
||||
|
||||
sym::ptr_mask => "llvm.ptrmask",
|
||||
sym::roundf16 => ("llvm.round", &[bx.type_f16()]),
|
||||
sym::roundf32 => ("llvm.round", &[bx.type_f32()]),
|
||||
sym::roundf64 => ("llvm.round", &[bx.type_f64()]),
|
||||
sym::roundf128 => ("llvm.round", &[bx.type_f128()]),
|
||||
|
||||
_ => return None,
|
||||
};
|
||||
Some(cx.get_intrinsic(llvm_name))
|
||||
Some(bx.call_intrinsic(
|
||||
base_name,
|
||||
type_params,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
))
|
||||
}
|
||||
|
||||
impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
|
|
@ -173,36 +176,24 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
let name = tcx.item_name(instance.def_id());
|
||||
let fn_args = instance.args;
|
||||
|
||||
let simple = get_simple_intrinsic(self, name);
|
||||
let simple = call_simple_intrinsic(self, name, args);
|
||||
let llval = match name {
|
||||
_ if simple.is_some() => {
|
||||
let (simple_ty, simple_fn) = simple.unwrap();
|
||||
self.call(
|
||||
simple_ty,
|
||||
None,
|
||||
None,
|
||||
simple_fn,
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
None,
|
||||
Some(instance),
|
||||
_ if simple.is_some() => simple.unwrap(),
|
||||
sym::ptr_mask => {
|
||||
let ptr = args[0].immediate();
|
||||
self.call_intrinsic(
|
||||
"llvm.ptrmask",
|
||||
&[self.val_ty(ptr), self.type_isize()],
|
||||
&[ptr, args[1].immediate()],
|
||||
)
|
||||
}
|
||||
sym::is_val_statically_known => {
|
||||
let intrinsic_type = args[0].layout.immediate_llvm_type(self.cx);
|
||||
let kind = self.type_kind(intrinsic_type);
|
||||
let intrinsic_name = match kind {
|
||||
TypeKind::Pointer | TypeKind::Integer => {
|
||||
Some(format!("llvm.is.constant.{intrinsic_type:?}"))
|
||||
}
|
||||
// LLVM float types' intrinsic names differ from their type names.
|
||||
TypeKind::Half => Some(format!("llvm.is.constant.f16")),
|
||||
TypeKind::Float => Some(format!("llvm.is.constant.f32")),
|
||||
TypeKind::Double => Some(format!("llvm.is.constant.f64")),
|
||||
TypeKind::FP128 => Some(format!("llvm.is.constant.f128")),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(intrinsic_name) = intrinsic_name {
|
||||
self.call_intrinsic(&intrinsic_name, &[args[0].immediate()])
|
||||
if let OperandValue::Immediate(imm) = args[0].val {
|
||||
self.call_intrinsic(
|
||||
"llvm.is.constant",
|
||||
&[args[0].layout.immediate_llvm_type(self.cx)],
|
||||
&[imm],
|
||||
)
|
||||
} else {
|
||||
self.const_bool(false)
|
||||
}
|
||||
|
|
@ -246,9 +237,14 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
);
|
||||
return Ok(());
|
||||
}
|
||||
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[]),
|
||||
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
|
||||
sym::va_copy => {
|
||||
self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()])
|
||||
let dest = args[0].immediate();
|
||||
self.call_intrinsic(
|
||||
"llvm.va_copy",
|
||||
&[self.val_ty(dest)],
|
||||
&[dest, args[1].immediate()],
|
||||
)
|
||||
}
|
||||
sym::va_arg => {
|
||||
match result.layout.backend_repr {
|
||||
|
|
@ -322,14 +318,11 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
sym::prefetch_write_instruction => (1, 0),
|
||||
_ => bug!(),
|
||||
};
|
||||
let ptr = args[0].immediate();
|
||||
self.call_intrinsic(
|
||||
"llvm.prefetch",
|
||||
&[
|
||||
args[0].immediate(),
|
||||
self.const_i32(rw),
|
||||
args[1].immediate(),
|
||||
self.const_i32(cache_type),
|
||||
],
|
||||
&[self.val_ty(ptr)],
|
||||
&[ptr, self.const_i32(rw), args[1].immediate(), self.const_i32(cache_type)],
|
||||
)
|
||||
}
|
||||
sym::carrying_mul_add => {
|
||||
|
|
@ -385,11 +378,13 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
let (size, signed) = ty.int_size_and_signed(self.tcx);
|
||||
let width = size.bits();
|
||||
let llty = self.type_ix(width);
|
||||
match name {
|
||||
sym::ctlz | sym::cttz => {
|
||||
let y = self.const_bool(false);
|
||||
let ret = self.call_intrinsic(
|
||||
&format!("llvm.{name}.i{width}"),
|
||||
format!("llvm.{name}"),
|
||||
&[llty],
|
||||
&[args[0].immediate(), y],
|
||||
);
|
||||
|
||||
|
|
@ -397,62 +392,54 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
sym::ctlz_nonzero => {
|
||||
let y = self.const_bool(true);
|
||||
let llvm_name = &format!("llvm.ctlz.i{width}");
|
||||
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
|
||||
let ret =
|
||||
self.call_intrinsic("llvm.ctlz", &[llty], &[args[0].immediate(), y]);
|
||||
self.intcast(ret, result.layout.llvm_type(self), false)
|
||||
}
|
||||
sym::cttz_nonzero => {
|
||||
let y = self.const_bool(true);
|
||||
let llvm_name = &format!("llvm.cttz.i{width}");
|
||||
let ret = self.call_intrinsic(llvm_name, &[args[0].immediate(), y]);
|
||||
let ret =
|
||||
self.call_intrinsic("llvm.cttz", &[llty], &[args[0].immediate(), y]);
|
||||
self.intcast(ret, result.layout.llvm_type(self), false)
|
||||
}
|
||||
sym::ctpop => {
|
||||
let ret = self.call_intrinsic(
|
||||
&format!("llvm.ctpop.i{width}"),
|
||||
&[args[0].immediate()],
|
||||
);
|
||||
let ret =
|
||||
self.call_intrinsic("llvm.ctpop", &[llty], &[args[0].immediate()]);
|
||||
self.intcast(ret, result.layout.llvm_type(self), false)
|
||||
}
|
||||
sym::bswap => {
|
||||
if width == 8 {
|
||||
args[0].immediate() // byte swap a u8/i8 is just a no-op
|
||||
} else {
|
||||
self.call_intrinsic(
|
||||
&format!("llvm.bswap.i{width}"),
|
||||
&[args[0].immediate()],
|
||||
)
|
||||
self.call_intrinsic("llvm.bswap", &[llty], &[args[0].immediate()])
|
||||
}
|
||||
}
|
||||
sym::bitreverse => self.call_intrinsic(
|
||||
&format!("llvm.bitreverse.i{width}"),
|
||||
&[args[0].immediate()],
|
||||
),
|
||||
sym::bitreverse => {
|
||||
self.call_intrinsic("llvm.bitreverse", &[llty], &[args[0].immediate()])
|
||||
}
|
||||
sym::rotate_left | sym::rotate_right => {
|
||||
let is_left = name == sym::rotate_left;
|
||||
let val = args[0].immediate();
|
||||
let raw_shift = args[1].immediate();
|
||||
// rotate = funnel shift with first two args the same
|
||||
let llvm_name =
|
||||
&format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
|
||||
let llvm_name = format!("llvm.fsh{}", if is_left { 'l' } else { 'r' });
|
||||
|
||||
// llvm expects shift to be the same type as the values, but rust
|
||||
// always uses `u32`.
|
||||
let raw_shift = self.intcast(raw_shift, self.val_ty(val), false);
|
||||
|
||||
self.call_intrinsic(llvm_name, &[val, val, raw_shift])
|
||||
self.call_intrinsic(llvm_name, &[llty], &[val, val, raw_shift])
|
||||
}
|
||||
sym::saturating_add | sym::saturating_sub => {
|
||||
let is_add = name == sym::saturating_add;
|
||||
let lhs = args[0].immediate();
|
||||
let rhs = args[1].immediate();
|
||||
let llvm_name = &format!(
|
||||
"llvm.{}{}.sat.i{}",
|
||||
let llvm_name = format!(
|
||||
"llvm.{}{}.sat",
|
||||
if signed { 's' } else { 'u' },
|
||||
if is_add { "add" } else { "sub" },
|
||||
width
|
||||
);
|
||||
self.call_intrinsic(llvm_name, &[lhs, rhs])
|
||||
self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs])
|
||||
}
|
||||
_ => bug!(),
|
||||
}
|
||||
|
|
@ -484,11 +471,8 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
self.icmp(IntPredicate::IntEQ, a_val, b_val)
|
||||
} else {
|
||||
let n = self.const_usize(layout.size().bytes());
|
||||
let cmp = self.call_intrinsic("memcmp", &[a, b, n]);
|
||||
match self.cx.sess().target.arch.as_ref() {
|
||||
"avr" | "msp430" => self.icmp(IntPredicate::IntEQ, cmp, self.const_i16(0)),
|
||||
_ => self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)),
|
||||
}
|
||||
let cmp = self.call_intrinsic("memcmp", &[], &[a, b, n]);
|
||||
self.icmp(IntPredicate::IntEQ, cmp, self.const_int(self.type_int(), 0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -496,6 +480,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
// Here we assume that the `memcmp` provided by the target is a NOP for size 0.
|
||||
let cmp = self.call_intrinsic(
|
||||
"memcmp",
|
||||
&[],
|
||||
&[args[0].immediate(), args[1].immediate(), args[2].immediate()],
|
||||
);
|
||||
// Some targets have `memcmp` returning `i16`, but the intrinsic is always `i32`.
|
||||
|
|
@ -619,18 +604,22 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
}
|
||||
|
||||
fn abort(&mut self) {
|
||||
self.call_intrinsic("llvm.trap", &[]);
|
||||
self.call_intrinsic("llvm.trap", &[], &[]);
|
||||
}
|
||||
|
||||
fn assume(&mut self, val: Self::Value) {
|
||||
if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
|
||||
self.call_intrinsic("llvm.assume", &[val]);
|
||||
self.call_intrinsic("llvm.assume", &[], &[val]);
|
||||
}
|
||||
}
|
||||
|
||||
fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
|
||||
if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
|
||||
self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
|
||||
self.call_intrinsic(
|
||||
"llvm.expect",
|
||||
&[self.type_i1()],
|
||||
&[cond, self.const_bool(expected)],
|
||||
)
|
||||
} else {
|
||||
cond
|
||||
}
|
||||
|
|
@ -644,17 +633,20 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
) -> Self::Value {
|
||||
let typeid = self.get_metadata_value(typeid);
|
||||
let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
|
||||
let type_checked_load =
|
||||
self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]);
|
||||
let type_checked_load = self.call_intrinsic(
|
||||
"llvm.type.checked.load",
|
||||
&[],
|
||||
&[llvtable, vtable_byte_offset, typeid],
|
||||
);
|
||||
self.extract_value(type_checked_load, 0)
|
||||
}
|
||||
|
||||
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||
self.call_intrinsic("llvm.va_start", &[va_list])
|
||||
self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list])
|
||||
}
|
||||
|
||||
fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
|
||||
self.call_intrinsic("llvm.va_end", &[va_list])
|
||||
self.call_intrinsic("llvm.va_end", &[self.val_ty(va_list)], &[va_list])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -893,8 +885,8 @@ fn codegen_wasm_try<'ll, 'tcx>(
|
|||
let null = bx.const_null(bx.type_ptr());
|
||||
let funclet = bx.catch_pad(cs, &[null]);
|
||||
|
||||
let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[funclet.cleanuppad()]);
|
||||
let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[funclet.cleanuppad()]);
|
||||
let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[], &[funclet.cleanuppad()]);
|
||||
let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[], &[funclet.cleanuppad()]);
|
||||
|
||||
let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
|
||||
bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None);
|
||||
|
|
@ -1031,7 +1023,7 @@ fn codegen_emcc_try<'ll, 'tcx>(
|
|||
let selector = bx.extract_value(vals, 1);
|
||||
|
||||
// Check if the typeid we got is the one for a Rust panic.
|
||||
let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
|
||||
let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.val_ty(tydesc)], &[tydesc]);
|
||||
let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid);
|
||||
let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool());
|
||||
|
||||
|
|
@ -1522,56 +1514,37 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
}};
|
||||
}
|
||||
|
||||
let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
|
||||
let elem_ty = bx.cx.type_float_from_ty(*f);
|
||||
match f.bit_width() {
|
||||
16 => ("f16", elem_ty),
|
||||
32 => ("f32", elem_ty),
|
||||
64 => ("f64", elem_ty),
|
||||
128 => ("f128", elem_ty),
|
||||
_ => return_error!(InvalidMonomorphization::FloatingPointVector {
|
||||
span,
|
||||
name,
|
||||
f_ty: *f,
|
||||
in_ty,
|
||||
}),
|
||||
}
|
||||
let elem_ty = if let ty::Float(f) = in_elem.kind() {
|
||||
bx.cx.type_float_from_ty(*f)
|
||||
} else {
|
||||
return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
|
||||
};
|
||||
|
||||
let vec_ty = bx.type_vector(elem_ty, in_len);
|
||||
|
||||
let (intr_name, fn_ty) = match name {
|
||||
sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_relaxed_fma => ("fmuladd", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
|
||||
sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
|
||||
sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
|
||||
let intr_name = match name {
|
||||
sym::simd_ceil => "llvm.ceil",
|
||||
sym::simd_fabs => "llvm.fabs",
|
||||
sym::simd_fcos => "llvm.cos",
|
||||
sym::simd_fexp2 => "llvm.exp2",
|
||||
sym::simd_fexp => "llvm.exp",
|
||||
sym::simd_flog10 => "llvm.log10",
|
||||
sym::simd_flog2 => "llvm.log2",
|
||||
sym::simd_flog => "llvm.log",
|
||||
sym::simd_floor => "llvm.floor",
|
||||
sym::simd_fma => "llvm.fma",
|
||||
sym::simd_relaxed_fma => "llvm.fmuladd",
|
||||
sym::simd_fsin => "llvm.sin",
|
||||
sym::simd_fsqrt => "llvm.sqrt",
|
||||
sym::simd_round => "llvm.round",
|
||||
sym::simd_trunc => "llvm.trunc",
|
||||
_ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
|
||||
};
|
||||
let llvm_name = &format!("llvm.{intr_name}.v{in_len}{elem_ty_str}");
|
||||
let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
|
||||
let c = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
Ok(bx.call_intrinsic(
|
||||
intr_name,
|
||||
&[vec_ty],
|
||||
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
Ok(c)
|
||||
))
|
||||
}
|
||||
|
||||
if std::matches!(
|
||||
|
|
@ -1595,29 +1568,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
|
||||
}
|
||||
|
||||
// FIXME: use:
|
||||
// https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182
|
||||
// https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81
|
||||
fn llvm_vector_str(bx: &Builder<'_, '_, '_>, elem_ty: Ty<'_>, vec_len: u64) -> String {
|
||||
match *elem_ty.kind() {
|
||||
ty::Int(v) => format!(
|
||||
"v{}i{}",
|
||||
vec_len,
|
||||
// Normalize to prevent crash if v: IntTy::Isize
|
||||
v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
|
||||
),
|
||||
ty::Uint(v) => format!(
|
||||
"v{}i{}",
|
||||
vec_len,
|
||||
// Normalize to prevent crash if v: UIntTy::Usize
|
||||
v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
|
||||
),
|
||||
ty::Float(v) => format!("v{}f{}", vec_len, v.bit_width()),
|
||||
ty::RawPtr(_, _) => format!("v{}p0", vec_len),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -> &'ll Type {
|
||||
let elem_ty = match *elem_ty.kind() {
|
||||
ty::Int(v) => cx.type_int_from_ty(v),
|
||||
|
|
@ -1698,38 +1648,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment_ty = bx.type_i32();
|
||||
let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32);
|
||||
|
||||
// Truncate the mask vector to a vector of i1s:
|
||||
let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
|
||||
let mask_ty = bx.type_vector(bx.type_i1(), in_len);
|
||||
|
||||
// Type of the vector of pointers:
|
||||
let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
|
||||
let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len);
|
||||
|
||||
// Type of the vector of elements:
|
||||
let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
|
||||
let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len);
|
||||
|
||||
let llvm_intrinsic =
|
||||
format!("llvm.masked.gather.{llvm_elem_vec_str}.{llvm_pointer_vec_str}");
|
||||
let fn_ty = bx.type_func(
|
||||
&[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
|
||||
llvm_elem_vec_ty,
|
||||
);
|
||||
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
return Ok(bx.call_intrinsic(
|
||||
"llvm.masked.gather",
|
||||
&[llvm_elem_vec_ty, llvm_pointer_vec_ty],
|
||||
&[args[1].immediate(), alignment, mask, args[0].immediate()],
|
||||
None,
|
||||
None,
|
||||
);
|
||||
return Ok(v);
|
||||
));
|
||||
}
|
||||
|
||||
if name == sym::simd_masked_load {
|
||||
|
|
@ -1795,32 +1729,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
);
|
||||
|
||||
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
|
||||
let mask_ty = bx.type_vector(bx.type_i1(), mask_len);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment_ty = bx.type_i32();
|
||||
let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32);
|
||||
|
||||
let llvm_pointer = bx.type_ptr();
|
||||
|
||||
// Type of the vector of elements:
|
||||
let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
|
||||
let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len);
|
||||
|
||||
let llvm_intrinsic = format!("llvm.masked.load.{llvm_elem_vec_str}.p0");
|
||||
let fn_ty = bx
|
||||
.type_func(&[llvm_pointer, alignment_ty, mask_ty, llvm_elem_vec_ty], llvm_elem_vec_ty);
|
||||
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
return Ok(bx.call_intrinsic(
|
||||
"llvm.masked.load",
|
||||
&[llvm_elem_vec_ty, llvm_pointer],
|
||||
&[args[1].immediate(), alignment, mask, args[2].immediate()],
|
||||
None,
|
||||
None,
|
||||
);
|
||||
return Ok(v);
|
||||
));
|
||||
}
|
||||
|
||||
if name == sym::simd_masked_store {
|
||||
|
|
@ -1880,33 +1802,20 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
);
|
||||
|
||||
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
|
||||
let mask_ty = bx.type_vector(bx.type_i1(), mask_len);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment_ty = bx.type_i32();
|
||||
let alignment = bx.const_i32(bx.align_of(values_elem).bytes() as i32);
|
||||
|
||||
let ret_t = bx.type_void();
|
||||
|
||||
let llvm_pointer = bx.type_ptr();
|
||||
|
||||
// Type of the vector of elements:
|
||||
let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
|
||||
let llvm_elem_vec_str = llvm_vector_str(bx, values_elem, values_len);
|
||||
|
||||
let llvm_intrinsic = format!("llvm.masked.store.{llvm_elem_vec_str}.p0");
|
||||
let fn_ty = bx.type_func(&[llvm_elem_vec_ty, llvm_pointer, alignment_ty, mask_ty], ret_t);
|
||||
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
return Ok(bx.call_intrinsic(
|
||||
"llvm.masked.store",
|
||||
&[llvm_elem_vec_ty, llvm_pointer],
|
||||
&[args[2].immediate(), args[1].immediate(), alignment, mask],
|
||||
None,
|
||||
None,
|
||||
);
|
||||
return Ok(v);
|
||||
));
|
||||
}
|
||||
|
||||
if name == sym::simd_scatter {
|
||||
|
|
@ -1971,38 +1880,22 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
);
|
||||
|
||||
// Alignment of T, must be a constant integer value:
|
||||
let alignment_ty = bx.type_i32();
|
||||
let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32);
|
||||
|
||||
// Truncate the mask vector to a vector of i1s:
|
||||
let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
|
||||
let mask_ty = bx.type_vector(bx.type_i1(), in_len);
|
||||
|
||||
let ret_t = bx.type_void();
|
||||
|
||||
// Type of the vector of pointers:
|
||||
let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
|
||||
let llvm_pointer_vec_str = llvm_vector_str(bx, element_ty1, in_len);
|
||||
|
||||
// Type of the vector of elements:
|
||||
let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
|
||||
let llvm_elem_vec_str = llvm_vector_str(bx, element_ty0, in_len);
|
||||
|
||||
let llvm_intrinsic =
|
||||
format!("llvm.masked.scatter.{llvm_elem_vec_str}.{llvm_pointer_vec_str}");
|
||||
let fn_ty =
|
||||
bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t);
|
||||
let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
return Ok(bx.call_intrinsic(
|
||||
"llvm.masked.scatter",
|
||||
&[llvm_elem_vec_ty, llvm_pointer_vec_ty],
|
||||
&[args[0].immediate(), args[1].immediate(), alignment, mask],
|
||||
None,
|
||||
None,
|
||||
);
|
||||
return Ok(v);
|
||||
));
|
||||
}
|
||||
|
||||
macro_rules! arith_red {
|
||||
|
|
@ -2431,40 +2324,31 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
},
|
||||
in_len as u64,
|
||||
);
|
||||
let intrinsic_name = match name {
|
||||
sym::simd_bswap => "bswap",
|
||||
sym::simd_bitreverse => "bitreverse",
|
||||
sym::simd_ctlz => "ctlz",
|
||||
sym::simd_ctpop => "ctpop",
|
||||
sym::simd_cttz => "cttz",
|
||||
let llvm_intrinsic = match name {
|
||||
sym::simd_bswap => "llvm.bswap",
|
||||
sym::simd_bitreverse => "llvm.bitreverse",
|
||||
sym::simd_ctlz => "llvm.ctlz",
|
||||
sym::simd_ctpop => "llvm.ctpop",
|
||||
sym::simd_cttz => "llvm.cttz",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
|
||||
let llvm_intrinsic = &format!("llvm.{}.v{}i{}", intrinsic_name, in_len, int_size,);
|
||||
|
||||
return match name {
|
||||
// byte swap is no-op for i8/u8
|
||||
sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()),
|
||||
sym::simd_ctlz | sym::simd_cttz => {
|
||||
// for the (int, i1 immediate) pair, the second arg adds `(0, true) => poison`
|
||||
let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
|
||||
let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
Ok(bx.call(
|
||||
fn_ty,
|
||||
None,
|
||||
None,
|
||||
f,
|
||||
Ok(bx.call_intrinsic(
|
||||
llvm_intrinsic,
|
||||
&[vec_ty],
|
||||
&[args[0].immediate(), dont_poison_on_zero],
|
||||
None,
|
||||
None,
|
||||
))
|
||||
}
|
||||
sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => {
|
||||
// simple unary argument cases
|
||||
let fn_ty = bx.type_func(&[vec_ty], vec_ty);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
|
||||
Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()]))
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
|
@ -2495,10 +2379,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
let lhs = args[0].immediate();
|
||||
let rhs = args[1].immediate();
|
||||
let is_add = name == sym::simd_saturating_add;
|
||||
let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _;
|
||||
let (signed, elem_width, elem_ty) = match *in_elem.kind() {
|
||||
ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
|
||||
ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
|
||||
let (signed, elem_ty) = match *in_elem.kind() {
|
||||
ty::Int(i) => (true, bx.cx.type_int_from_ty(i)),
|
||||
ty::Uint(i) => (false, bx.cx.type_uint_from_ty(i)),
|
||||
_ => {
|
||||
return_error!(InvalidMonomorphization::ExpectedVectorElementType {
|
||||
span,
|
||||
|
|
@ -2508,19 +2391,14 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
|
|||
});
|
||||
}
|
||||
};
|
||||
let llvm_intrinsic = &format!(
|
||||
"llvm.{}{}.sat.v{}i{}",
|
||||
let llvm_intrinsic = format!(
|
||||
"llvm.{}{}.sat",
|
||||
if signed { 's' } else { 'u' },
|
||||
if is_add { "add" } else { "sub" },
|
||||
in_len,
|
||||
elem_width
|
||||
);
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
|
||||
|
||||
let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
|
||||
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
|
||||
let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None, None);
|
||||
return Ok(v);
|
||||
return Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[lhs, rhs]));
|
||||
}
|
||||
|
||||
span_bug!(span, "unknown SIMD intrinsic");
|
||||
|
|
|
|||
|
|
@ -340,18 +340,11 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
target_config(sess)
|
||||
}
|
||||
|
||||
fn codegen_crate<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> Box<dyn Any> {
|
||||
fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Box<dyn Any> {
|
||||
Box::new(rustc_codegen_ssa::base::codegen_crate(
|
||||
LlvmCodegenBackend(()),
|
||||
tcx,
|
||||
crate::llvm_util::target_cpu(tcx.sess).to_string(),
|
||||
metadata,
|
||||
need_metadata_module,
|
||||
))
|
||||
}
|
||||
|
||||
|
|
@ -376,14 +369,20 @@ impl CodegenBackend for LlvmCodegenBackend {
|
|||
(codegen_results, work_products)
|
||||
}
|
||||
|
||||
fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
|
||||
fn link(
|
||||
&self,
|
||||
sess: &Session,
|
||||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
use rustc_codegen_ssa::back::link::link_binary;
|
||||
|
||||
use crate::back::archive::LlvmArchiveBuilderBuilder;
|
||||
|
||||
// Run the linker on any artifacts that resulted from the LLVM run.
|
||||
// This should produce either a finished executable or library.
|
||||
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, outputs);
|
||||
link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
use std::fmt::Debug;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZero;
|
||||
use std::ptr;
|
||||
|
||||
use bitflags::bitflags;
|
||||
|
|
@ -1077,8 +1078,6 @@ unsafe extern "C" {
|
|||
|
||||
// Operations on other types
|
||||
pub(crate) fn LLVMVoidTypeInContext(C: &Context) -> &Type;
|
||||
pub(crate) fn LLVMTokenTypeInContext(C: &Context) -> &Type;
|
||||
pub(crate) fn LLVMMetadataTypeInContext(C: &Context) -> &Type;
|
||||
|
||||
// Operations on all values
|
||||
pub(crate) fn LLVMTypeOf(Val: &Value) -> &Type;
|
||||
|
|
@ -1195,6 +1194,15 @@ unsafe extern "C" {
|
|||
// Operations on functions
|
||||
pub(crate) fn LLVMSetFunctionCallConv(Fn: &Value, CC: c_uint);
|
||||
|
||||
// Operations about llvm intrinsics
|
||||
pub(crate) fn LLVMLookupIntrinsicID(Name: *const c_char, NameLen: size_t) -> c_uint;
|
||||
pub(crate) fn LLVMGetIntrinsicDeclaration<'a>(
|
||||
Mod: &'a Module,
|
||||
ID: NonZero<c_uint>,
|
||||
ParamTypes: *const &'a Type,
|
||||
ParamCount: size_t,
|
||||
) -> &'a Value;
|
||||
|
||||
// Operations on parameters
|
||||
pub(crate) fn LLVMIsAArgument(Val: &Value) -> Option<&Value>;
|
||||
pub(crate) safe fn LLVMCountParams(Fn: &Value) -> c_uint;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#![allow(non_snake_case)]
|
||||
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::num::NonZero;
|
||||
use std::ptr;
|
||||
use std::str::FromStr;
|
||||
use std::string::FromUtf8Error;
|
||||
|
|
@ -327,6 +328,28 @@ pub(crate) fn get_value_name(value: &Value) -> &[u8] {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub(crate) struct Intrinsic {
|
||||
id: NonZero<c_uint>,
|
||||
}
|
||||
|
||||
impl Intrinsic {
|
||||
pub(crate) fn lookup(name: &[u8]) -> Option<Self> {
|
||||
let id = unsafe { LLVMLookupIntrinsicID(name.as_c_char_ptr(), name.len()) };
|
||||
NonZero::new(id).map(|id| Self { id })
|
||||
}
|
||||
|
||||
pub(crate) fn get_declaration<'ll>(
|
||||
self,
|
||||
llmod: &'ll Module,
|
||||
type_params: &[&'ll Type],
|
||||
) -> &'ll Value {
|
||||
unsafe {
|
||||
LLVMGetIntrinsicDeclaration(llmod, self.id, type_params.as_ptr(), type_params.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Safe wrapper for `LLVMSetValueName2` from a byte slice
|
||||
pub(crate) fn set_value_name(value: &Value, name: &[u8]) {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ use rustc_fs_util::path_to_c_string;
|
|||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{PrintKind, PrintRequest};
|
||||
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
|
||||
use rustc_span::Symbol;
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
|
||||
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
|
||||
|
|
@ -23,8 +24,7 @@ use smallvec::{SmallVec, smallvec};
|
|||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
|
||||
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
|
||||
};
|
||||
use crate::llvm;
|
||||
|
||||
|
|
@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
|
|||
handle_native(cpu_name)
|
||||
}
|
||||
|
||||
fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
|
||||
let mut features: Vec<&str> = Vec::new();
|
||||
retpoline_features_by_flags(sess, &mut features);
|
||||
features
|
||||
}
|
||||
|
||||
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
pub(crate) fn global_llvm_features(
|
||||
|
|
@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features(
|
|||
|
||||
// Compute implied features
|
||||
let mut all_rust_features = vec![];
|
||||
for feature in sess.opts.cg.target_feature.split(',') {
|
||||
for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
|
||||
if let Some(feature) = feature.strip_prefix('+') {
|
||||
all_rust_features.extend(
|
||||
UnordSet::from(sess.target.implied_target_features(feature))
|
||||
|
|
@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features(
|
|||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, stability, _)) => {
|
||||
if let Err(reason) = stability.toggle_allowed() {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||
feature,
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
stability.verify_feature_enabled_by_flag(sess, enable, feature);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use std::borrow::Borrow;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::{fmt, ptr};
|
||||
|
||||
use libc::{c_char, c_uint};
|
||||
|
|
@ -25,6 +26,14 @@ impl PartialEq for Type {
|
|||
}
|
||||
}
|
||||
|
||||
impl Eq for Type {}
|
||||
|
||||
impl Hash for Type {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
ptr::hash(self, state);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Type {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(
|
||||
|
|
@ -49,13 +58,6 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
|
|||
pub(crate) fn type_void(&self) -> &'ll Type {
|
||||
unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) }
|
||||
}
|
||||
pub(crate) fn type_token(&self) -> &'ll Type {
|
||||
unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) }
|
||||
}
|
||||
|
||||
pub(crate) fn type_metadata(&self) -> &'ll Type {
|
||||
unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) }
|
||||
}
|
||||
|
||||
///x Creates an integer type with the given number of bits, e.g., i24
|
||||
pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type {
|
||||
|
|
|
|||
|
|
@ -198,8 +198,6 @@ codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status
|
|||
codegen_ssa_malformed_cgu_name =
|
||||
found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case).
|
||||
|
||||
codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
|
||||
|
||||
codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
|
||||
|
||||
codegen_ssa_missing_features = add the missing features in a `target_feature` attribute
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ use object::read::macho::FatArch;
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_fs_util::TempDirBuilder;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::Symbol;
|
||||
use tracing::trace;
|
||||
|
||||
use super::metadata::search_for_section;
|
||||
use super::metadata::{create_compressed_metadata_file, search_for_section};
|
||||
use crate::common;
|
||||
// Re-exporting for rustc_codegen_llvm::back::archive
|
||||
pub use crate::errors::{ArchiveBuildFailure, ExtractBundledLibsError, UnknownArchiveKind};
|
||||
|
|
@ -58,6 +59,15 @@ impl From<ImportLibraryItem> for COFFShortExport {
|
|||
pub trait ArchiveBuilderBuilder {
|
||||
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder + 'a>;
|
||||
|
||||
fn create_dylib_metadata_wrapper(
|
||||
&self,
|
||||
sess: &Session,
|
||||
metadata: &EncodedMetadata,
|
||||
symbol_name: &str,
|
||||
) -> Vec<u8> {
|
||||
create_compressed_metadata_file(sess, metadata, symbol_name)
|
||||
}
|
||||
|
||||
/// Creates a DLL Import Library <https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-creation#creating-an-import-library>.
|
||||
/// and returns the path on disk to that import library.
|
||||
/// This functions doesn't take `self` so that it can be called from
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
|||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
|
||||
use rustc_metadata::{
|
||||
NativeLibSearchFallback, find_native_static_library, walk_native_lib_search_dirs,
|
||||
EncodedMetadata, NativeLibSearchFallback, find_native_static_library,
|
||||
walk_native_lib_search_dirs,
|
||||
};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::lint::lint_level;
|
||||
|
|
@ -68,29 +69,13 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_link_info_print_request(sess: &Session, crate_types: &[CrateType]) {
|
||||
let print_native_static_libs =
|
||||
sess.opts.prints.iter().any(|p| p.kind == PrintKind::NativeStaticLibs);
|
||||
let has_staticlib = crate_types.iter().any(|ct| *ct == CrateType::Staticlib);
|
||||
if print_native_static_libs {
|
||||
if !has_staticlib {
|
||||
sess.dcx()
|
||||
.warn(format!("cannot output linkage information without staticlib crate-type"));
|
||||
sess.dcx()
|
||||
.note(format!("consider `--crate-type staticlib` to print linkage information"));
|
||||
} else if !sess.opts.output_types.should_link() {
|
||||
sess.dcx()
|
||||
.warn(format!("cannot output linkage information when --emit link is not passed"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs the linkage portion of the compilation phase. This will generate all
|
||||
/// of the requested outputs for this compilation session.
|
||||
pub fn link_binary(
|
||||
sess: &Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: CodegenResults,
|
||||
metadata: EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) {
|
||||
let _timer = sess.timer("link_binary");
|
||||
|
|
@ -142,6 +127,7 @@ pub fn link_binary(
|
|||
sess,
|
||||
archive_builder_builder,
|
||||
&codegen_results,
|
||||
&metadata,
|
||||
RlibFlavor::Normal,
|
||||
&path,
|
||||
)
|
||||
|
|
@ -152,6 +138,7 @@ pub fn link_binary(
|
|||
sess,
|
||||
archive_builder_builder,
|
||||
&codegen_results,
|
||||
&metadata,
|
||||
&out_filename,
|
||||
&path,
|
||||
);
|
||||
|
|
@ -163,6 +150,7 @@ pub fn link_binary(
|
|||
crate_type,
|
||||
&out_filename,
|
||||
&codegen_results,
|
||||
&metadata,
|
||||
path.as_ref(),
|
||||
);
|
||||
}
|
||||
|
|
@ -203,8 +191,6 @@ pub fn link_binary(
|
|||
}
|
||||
}
|
||||
|
||||
check_link_info_print_request(sess, &codegen_results.crate_info.crate_types);
|
||||
|
||||
// Remove the temporary object file and metadata if we aren't saving temps.
|
||||
sess.time("link_binary_remove_temps", || {
|
||||
// If the user requests that temporaries are saved, don't delete any.
|
||||
|
|
@ -226,11 +212,7 @@ pub fn link_binary(
|
|||
let remove_temps_from_module =
|
||||
|module: &CompiledModule| maybe_remove_temps_from_module(false, false, module);
|
||||
|
||||
// Otherwise, always remove the metadata and allocator module temporaries.
|
||||
if let Some(ref metadata_module) = codegen_results.metadata_module {
|
||||
remove_temps_from_module(metadata_module);
|
||||
}
|
||||
|
||||
// Otherwise, always remove the allocator module temporaries.
|
||||
if let Some(ref allocator_module) = codegen_results.allocator_module {
|
||||
remove_temps_from_module(allocator_module);
|
||||
}
|
||||
|
|
@ -312,6 +294,7 @@ fn link_rlib<'a>(
|
|||
sess: &'a Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
flavor: RlibFlavor,
|
||||
tmpdir: &MaybeTempDir,
|
||||
) -> Box<dyn ArchiveBuilder + 'a> {
|
||||
|
|
@ -319,12 +302,9 @@ fn link_rlib<'a>(
|
|||
|
||||
let trailing_metadata = match flavor {
|
||||
RlibFlavor::Normal => {
|
||||
let (metadata, metadata_position) = create_wrapper_file(
|
||||
sess,
|
||||
".rmeta".to_string(),
|
||||
codegen_results.metadata.stub_or_full(),
|
||||
);
|
||||
let metadata = emit_wrapper_file(sess, &metadata, tmpdir, METADATA_FILENAME);
|
||||
let (metadata, metadata_position) =
|
||||
create_wrapper_file(sess, ".rmeta".to_string(), metadata.stub_or_full());
|
||||
let metadata = emit_wrapper_file(sess, &metadata, tmpdir.as_ref(), METADATA_FILENAME);
|
||||
match metadata_position {
|
||||
MetadataPosition::First => {
|
||||
// Most of the time metadata in rlib files is wrapped in a "dummy" object
|
||||
|
|
@ -392,7 +372,7 @@ fn link_rlib<'a>(
|
|||
let src = read(path)
|
||||
.unwrap_or_else(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }));
|
||||
let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src);
|
||||
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
|
||||
let wrapper_file = emit_wrapper_file(sess, &data, tmpdir.as_ref(), filename.as_str());
|
||||
packed_bundled_libs.push(wrapper_file);
|
||||
} else {
|
||||
let path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
|
||||
|
|
@ -473,6 +453,7 @@ fn link_staticlib(
|
|||
sess: &Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
out_filename: &Path,
|
||||
tempdir: &MaybeTempDir,
|
||||
) {
|
||||
|
|
@ -481,6 +462,7 @@ fn link_staticlib(
|
|||
sess,
|
||||
archive_builder_builder,
|
||||
codegen_results,
|
||||
metadata,
|
||||
RlibFlavor::StaticlibBase,
|
||||
tempdir,
|
||||
);
|
||||
|
|
@ -694,6 +676,7 @@ fn link_natively(
|
|||
crate_type: CrateType,
|
||||
out_filename: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
tmpdir: &Path,
|
||||
) {
|
||||
info!("preparing {:?} to {:?}", crate_type, out_filename);
|
||||
|
|
@ -718,6 +701,7 @@ fn link_natively(
|
|||
tmpdir,
|
||||
temp_filename,
|
||||
codegen_results,
|
||||
metadata,
|
||||
self_contained_components,
|
||||
);
|
||||
|
||||
|
|
@ -1065,11 +1049,11 @@ fn link_natively(
|
|||
match strip {
|
||||
Strip::Debuginfo => {
|
||||
// FIXME: AIX's strip utility only offers option to strip line number information.
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"])
|
||||
strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-l"])
|
||||
}
|
||||
Strip::Symbols => {
|
||||
// Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata.
|
||||
strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"])
|
||||
strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-r"])
|
||||
}
|
||||
Strip::None => {}
|
||||
}
|
||||
|
|
@ -2095,17 +2079,25 @@ fn add_local_crate_allocator_objects(cmd: &mut dyn Linker, codegen_results: &Cod
|
|||
/// Add object files containing metadata for the current crate.
|
||||
fn add_local_crate_metadata_objects(
|
||||
cmd: &mut dyn Linker,
|
||||
sess: &Session,
|
||||
archive_builder_builder: &dyn ArchiveBuilderBuilder,
|
||||
crate_type: CrateType,
|
||||
tmpdir: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
) {
|
||||
// When linking a dynamic library, we put the metadata into a section of the
|
||||
// executable. This metadata is in a separate object file from the main
|
||||
// object file, so we link that in here.
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro)
|
||||
&& let Some(m) = &codegen_results.metadata_module
|
||||
&& let Some(obj) = &m.object
|
||||
{
|
||||
cmd.add_object(obj);
|
||||
// object file, so we create and link it in here.
|
||||
if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro) {
|
||||
let data = archive_builder_builder.create_dylib_metadata_wrapper(
|
||||
sess,
|
||||
&metadata,
|
||||
&codegen_results.crate_info.metadata_symbol,
|
||||
);
|
||||
let obj = emit_wrapper_file(sess, &data, tmpdir, "rmeta.o");
|
||||
|
||||
cmd.add_object(&obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2195,6 +2187,7 @@ fn linker_with_args(
|
|||
tmpdir: &Path,
|
||||
out_filename: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
self_contained_components: LinkSelfContainedComponents,
|
||||
) -> Command {
|
||||
let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
|
||||
|
|
@ -2269,7 +2262,15 @@ fn linker_with_args(
|
|||
// in this DAG so far because they can only depend on other native libraries
|
||||
// and such dependencies are also required to be specified.
|
||||
add_local_crate_regular_objects(cmd, codegen_results);
|
||||
add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
|
||||
add_local_crate_metadata_objects(
|
||||
cmd,
|
||||
sess,
|
||||
archive_builder_builder,
|
||||
crate_type,
|
||||
tmpdir,
|
||||
codegen_results,
|
||||
metadata,
|
||||
);
|
||||
add_local_crate_allocator_objects(cmd, codegen_results);
|
||||
|
||||
// Avoid linking to dynamic libraries unless they satisfy some undefined symbols
|
||||
|
|
|
|||
|
|
@ -379,6 +379,24 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
|
|||
};
|
||||
e_flags
|
||||
}
|
||||
Architecture::PowerPc64 => {
|
||||
const EF_PPC64_ABI_UNKNOWN: u32 = 0;
|
||||
const EF_PPC64_ABI_ELF_V1: u32 = 1;
|
||||
const EF_PPC64_ABI_ELF_V2: u32 = 2;
|
||||
|
||||
match sess.target.options.llvm_abiname.as_ref() {
|
||||
// If the flags do not correctly indicate the ABI,
|
||||
// linkers such as ld.lld assume that the ppc64 object files are always ELFv2
|
||||
// which leads to broken binaries if ELFv1 is used for the object files.
|
||||
"elfv1" => EF_PPC64_ABI_ELF_V1,
|
||||
"elfv2" => EF_PPC64_ABI_ELF_V2,
|
||||
"" if sess.target.options.binary_format.to_object() == BinaryFormat::Elf => {
|
||||
bug!("No ABI specified for this PPC64 ELF target");
|
||||
}
|
||||
// Fall back
|
||||
_ => EF_PPC64_ABI_UNKNOWN,
|
||||
}
|
||||
}
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
|||
use rustc_incremental::{
|
||||
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||
};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_metadata::fs::copy_to_stdout;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
|
|
@ -142,7 +141,6 @@ impl ModuleConfig {
|
|||
|| match kind {
|
||||
ModuleKind::Regular => sess.opts.output_types.contains_key(&OutputType::Object),
|
||||
ModuleKind::Allocator => false,
|
||||
ModuleKind::Metadata => sess.opts.output_types.contains_key(&OutputType::Metadata),
|
||||
};
|
||||
|
||||
let emit_obj = if !should_emit_obj {
|
||||
|
|
@ -350,7 +348,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
|
|||
pub output_filenames: Arc<OutputFilenames>,
|
||||
pub invocation_temp: Option<String>,
|
||||
pub regular_module_config: Arc<ModuleConfig>,
|
||||
pub metadata_module_config: Arc<ModuleConfig>,
|
||||
pub allocator_module_config: Arc<ModuleConfig>,
|
||||
pub tm_factory: TargetMachineFactoryFn<B>,
|
||||
pub msvc_imps_needed: bool,
|
||||
|
|
@ -395,7 +392,6 @@ impl<B: WriteBackendMethods> CodegenContext<B> {
|
|||
pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
|
||||
match kind {
|
||||
ModuleKind::Regular => &self.regular_module_config,
|
||||
ModuleKind::Metadata => &self.metadata_module_config,
|
||||
ModuleKind::Allocator => &self.allocator_module_config,
|
||||
}
|
||||
}
|
||||
|
|
@ -474,8 +470,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
backend: B,
|
||||
tcx: TyCtxt<'_>,
|
||||
target_cpu: String,
|
||||
metadata: EncodedMetadata,
|
||||
metadata_module: Option<CompiledModule>,
|
||||
) -> OngoingCodegen<B> {
|
||||
let (coordinator_send, coordinator_receive) = channel();
|
||||
|
||||
|
|
@ -485,7 +479,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
let crate_info = CrateInfo::new(tcx, target_cpu);
|
||||
|
||||
let regular_config = ModuleConfig::new(ModuleKind::Regular, tcx, no_builtins);
|
||||
let metadata_config = ModuleConfig::new(ModuleKind::Metadata, tcx, no_builtins);
|
||||
let allocator_config = ModuleConfig::new(ModuleKind::Allocator, tcx, no_builtins);
|
||||
|
||||
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
|
||||
|
|
@ -499,15 +492,12 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
|
|||
codegen_worker_send,
|
||||
coordinator_receive,
|
||||
Arc::new(regular_config),
|
||||
Arc::new(metadata_config),
|
||||
Arc::new(allocator_config),
|
||||
coordinator_send.clone(),
|
||||
);
|
||||
|
||||
OngoingCodegen {
|
||||
backend,
|
||||
metadata,
|
||||
metadata_module,
|
||||
crate_info,
|
||||
|
||||
codegen_worker_receive,
|
||||
|
|
@ -843,12 +833,6 @@ pub(crate) fn compute_per_cgu_lto_type(
|
|||
sess_crate_types: &[CrateType],
|
||||
module_kind: ModuleKind,
|
||||
) -> ComputedLtoType {
|
||||
// Metadata modules never participate in LTO regardless of the lto
|
||||
// settings.
|
||||
if module_kind == ModuleKind::Metadata {
|
||||
return ComputedLtoType::No;
|
||||
}
|
||||
|
||||
// If the linker does LTO, we don't have to do it. Note that we
|
||||
// keep doing full LTO, if it is requested, as not to break the
|
||||
// assumption that the output will be a single module.
|
||||
|
|
@ -1029,10 +1013,7 @@ fn finish_intra_module_work<B: ExtraBackendMethods>(
|
|||
let dcx = cgcx.create_dcx();
|
||||
let dcx = dcx.handle();
|
||||
|
||||
if !cgcx.opts.unstable_opts.combine_cgu
|
||||
|| module.kind == ModuleKind::Metadata
|
||||
|| module.kind == ModuleKind::Allocator
|
||||
{
|
||||
if !cgcx.opts.unstable_opts.combine_cgu || module.kind == ModuleKind::Allocator {
|
||||
let module = B::codegen(cgcx, dcx, module, module_config)?;
|
||||
Ok(WorkItemResult::Finished(module))
|
||||
} else {
|
||||
|
|
@ -1123,7 +1104,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
codegen_worker_send: Sender<CguMessage>,
|
||||
coordinator_receive: Receiver<Box<dyn Any + Send>>,
|
||||
regular_config: Arc<ModuleConfig>,
|
||||
metadata_config: Arc<ModuleConfig>,
|
||||
allocator_config: Arc<ModuleConfig>,
|
||||
tx_to_llvm_workers: Sender<Box<dyn Any + Send>>,
|
||||
) -> thread::JoinHandle<Result<CompiledModules, ()>> {
|
||||
|
|
@ -1216,7 +1196,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
diag_emitter: shared_emitter.clone(),
|
||||
output_filenames: Arc::clone(tcx.output_filenames(())),
|
||||
regular_module_config: regular_config,
|
||||
metadata_module_config: metadata_config,
|
||||
allocator_module_config: allocator_config,
|
||||
tm_factory: backend.target_machine_factory(tcx.sess, ol, backend_features),
|
||||
msvc_imps_needed: msvc_imps_needed(tcx),
|
||||
|
|
@ -1673,7 +1652,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
|
|||
assert!(compiled_allocator_module.is_none());
|
||||
compiled_allocator_module = Some(compiled_module);
|
||||
}
|
||||
ModuleKind::Metadata => bug!("Should be handled separately"),
|
||||
}
|
||||
}
|
||||
Ok(WorkItemResult::NeedsLink(module)) => {
|
||||
|
|
@ -2055,8 +2033,6 @@ impl<B: ExtraBackendMethods> Drop for Coordinator<B> {
|
|||
|
||||
pub struct OngoingCodegen<B: ExtraBackendMethods> {
|
||||
pub backend: B,
|
||||
pub metadata: EncodedMetadata,
|
||||
pub metadata_module: Option<CompiledModule>,
|
||||
pub crate_info: CrateInfo,
|
||||
pub codegen_worker_receive: Receiver<CguMessage>,
|
||||
pub shared_emitter_main: SharedEmitterMain,
|
||||
|
|
@ -2096,12 +2072,10 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
|
|||
|
||||
(
|
||||
CodegenResults {
|
||||
metadata: self.metadata,
|
||||
crate_info: self.crate_info,
|
||||
|
||||
modules: compiled_modules.modules,
|
||||
allocator_module: compiled_modules.allocator_module,
|
||||
metadata_module: self.metadata_module,
|
||||
},
|
||||
work_products,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,10 @@ use rustc_data_structures::unord::UnordMap;
|
|||
use rustc_hir::ItemId;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||
use rustc_middle::middle::{exported_symbols, lang_items};
|
||||
use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
|
||||
use rustc_middle::middle::lang_items;
|
||||
use rustc_middle::mir::BinOp;
|
||||
use rustc_middle::mir::interpret::ErrorHandled;
|
||||
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem, MonoItemPartitions};
|
||||
|
|
@ -28,7 +27,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
|
|||
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
|
||||
use rustc_session::config::{self, CrateType, EntryFnType};
|
||||
use rustc_span::{DUMMY_SP, Symbol, sym};
|
||||
use rustc_symbol_mangling::mangle_internal_symbol;
|
||||
use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
|
||||
|
|
@ -37,7 +36,6 @@ use tracing::{debug, info};
|
|||
|
||||
use crate::assert_module_sources::CguReuse;
|
||||
use crate::back::link::are_upstream_rust_objects_already_included;
|
||||
use crate::back::metadata::create_compressed_metadata_file;
|
||||
use crate::back::write::{
|
||||
ComputedLtoType, OngoingCodegen, compute_per_cgu_lto_type, start_async_codegen,
|
||||
submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
|
||||
|
|
@ -48,8 +46,7 @@ use crate::mir::operand::OperandValue;
|
|||
use crate::mir::place::PlaceRef;
|
||||
use crate::traits::*;
|
||||
use crate::{
|
||||
CachedModuleCodegen, CodegenLintLevels, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind,
|
||||
errors, meth, mir,
|
||||
CachedModuleCodegen, CodegenLintLevels, CrateInfo, ModuleCodegen, ModuleKind, errors, meth, mir,
|
||||
};
|
||||
|
||||
pub(crate) fn bin_op_to_icmp_predicate(op: BinOp, signed: bool) -> IntPredicate {
|
||||
|
|
@ -669,12 +666,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
backend: B,
|
||||
tcx: TyCtxt<'_>,
|
||||
target_cpu: String,
|
||||
metadata: EncodedMetadata,
|
||||
need_metadata_module: bool,
|
||||
) -> OngoingCodegen<B> {
|
||||
// Skip crate items and just output metadata in -Z no-codegen mode.
|
||||
if tcx.sess.opts.unstable_opts.no_codegen || !tcx.sess.opts.output_types.should_codegen() {
|
||||
let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu, metadata, None);
|
||||
let ongoing_codegen = start_async_codegen(backend, tcx, target_cpu);
|
||||
|
||||
ongoing_codegen.codegen_finished(tcx);
|
||||
|
||||
|
|
@ -707,39 +702,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
|
|||
}
|
||||
}
|
||||
|
||||
let metadata_module = need_metadata_module.then(|| {
|
||||
// Emit compressed metadata object.
|
||||
let metadata_cgu_name =
|
||||
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("metadata")).to_string();
|
||||
tcx.sess.time("write_compressed_metadata", || {
|
||||
let file_name = tcx.output_filenames(()).temp_path_for_cgu(
|
||||
OutputType::Metadata,
|
||||
&metadata_cgu_name,
|
||||
tcx.sess.invocation_temp.as_deref(),
|
||||
);
|
||||
let data = create_compressed_metadata_file(
|
||||
tcx.sess,
|
||||
&metadata,
|
||||
&exported_symbols::metadata_symbol_name(tcx),
|
||||
);
|
||||
if let Err(error) = std::fs::write(&file_name, data) {
|
||||
tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite { error });
|
||||
}
|
||||
CompiledModule {
|
||||
name: metadata_cgu_name,
|
||||
kind: ModuleKind::Metadata,
|
||||
object: Some(file_name),
|
||||
dwarf_object: None,
|
||||
bytecode: None,
|
||||
assembly: None,
|
||||
llvm_ir: None,
|
||||
links_from_incr_cache: Vec::new(),
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
let ongoing_codegen =
|
||||
start_async_codegen(backend.clone(), tcx, target_cpu, metadata, metadata_module);
|
||||
let ongoing_codegen = start_async_codegen(backend.clone(), tcx, target_cpu);
|
||||
|
||||
// Codegen an allocator shim, if necessary.
|
||||
if let Some(kind) = allocator_kind_for_codegen(tcx) {
|
||||
|
|
@ -1010,6 +973,7 @@ impl CrateInfo {
|
|||
windows_subsystem,
|
||||
natvis_debugger_visualizers: Default::default(),
|
||||
lint_levels: CodegenLintLevels::from_tcx(tcx),
|
||||
metadata_symbol: exported_symbols::metadata_symbol_name(tcx),
|
||||
};
|
||||
|
||||
info.native_libraries.reserve(n_crates);
|
||||
|
|
|
|||
|
|
@ -777,12 +777,6 @@ pub(crate) struct MultipleMainFunctions {
|
|||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_metadata_object_file_write)]
|
||||
pub(crate) struct MetadataObjectFileWrite {
|
||||
pub error: Error,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_invalid_windows_subsystem)]
|
||||
pub(crate) struct InvalidWindowsSubsystem {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ use rustc_data_structures::unord::UnordMap;
|
|||
use rustc_hir::CRATE_HIR_ID;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_metadata::EncodedMetadata;
|
||||
use rustc_middle::dep_graph::WorkProduct;
|
||||
use rustc_middle::lint::LevelAndSource;
|
||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||
|
|
@ -169,7 +170,6 @@ pub(crate) struct CachedModuleCodegen {
|
|||
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable)]
|
||||
pub enum ModuleKind {
|
||||
Regular,
|
||||
Metadata,
|
||||
Allocator,
|
||||
}
|
||||
|
||||
|
|
@ -233,6 +233,7 @@ pub struct CrateInfo {
|
|||
pub windows_subsystem: Option<String>,
|
||||
pub natvis_debugger_visualizers: BTreeSet<DebuggerVisualizerFile>,
|
||||
pub lint_levels: CodegenLintLevels,
|
||||
pub metadata_symbol: String,
|
||||
}
|
||||
|
||||
/// Target-specific options that get set in `cfg(...)`.
|
||||
|
|
@ -257,8 +258,6 @@ pub struct TargetConfig {
|
|||
pub struct CodegenResults {
|
||||
pub modules: Vec<CompiledModule>,
|
||||
pub allocator_module: Option<CompiledModule>,
|
||||
pub metadata_module: Option<CompiledModule>,
|
||||
pub metadata: rustc_metadata::EncodedMetadata,
|
||||
pub crate_info: CrateInfo,
|
||||
}
|
||||
|
||||
|
|
@ -303,6 +302,7 @@ impl CodegenResults {
|
|||
sess: &Session,
|
||||
rlink_file: &Path,
|
||||
codegen_results: &CodegenResults,
|
||||
metadata: &EncodedMetadata,
|
||||
outputs: &OutputFilenames,
|
||||
) -> Result<usize, io::Error> {
|
||||
let mut encoder = FileEncoder::new(rlink_file)?;
|
||||
|
|
@ -312,6 +312,7 @@ impl CodegenResults {
|
|||
encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());
|
||||
encoder.emit_str(sess.cfg_version);
|
||||
Encodable::encode(codegen_results, &mut encoder);
|
||||
Encodable::encode(metadata, &mut encoder);
|
||||
Encodable::encode(outputs, &mut encoder);
|
||||
encoder.finish().map_err(|(_path, err)| err)
|
||||
}
|
||||
|
|
@ -319,7 +320,7 @@ impl CodegenResults {
|
|||
pub fn deserialize_rlink(
|
||||
sess: &Session,
|
||||
data: Vec<u8>,
|
||||
) -> Result<(Self, OutputFilenames), CodegenErrors> {
|
||||
) -> Result<(Self, EncodedMetadata, OutputFilenames), CodegenErrors> {
|
||||
// The Decodable machinery is not used here because it panics if the input data is invalid
|
||||
// and because its internal representation may change.
|
||||
if !data.starts_with(RLINK_MAGIC) {
|
||||
|
|
@ -350,8 +351,9 @@ impl CodegenResults {
|
|||
}
|
||||
|
||||
let codegen_results = CodegenResults::decode(&mut decoder);
|
||||
let metadata = EncodedMetadata::decode(&mut decoder);
|
||||
let outputs = OutputFilenames::decode(&mut decoder);
|
||||
Ok((codegen_results, outputs))
|
||||
Ok((codegen_results, metadata, outputs))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::cmp;
|
||||
|
||||
use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
|
||||
use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_data_structures::packed::Pu128;
|
||||
|
|
@ -13,7 +13,7 @@ use rustc_middle::{bug, span_bug};
|
|||
use rustc_session::config::OptLevel;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
|
||||
use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use super::operand::OperandRef;
|
||||
|
|
@ -558,8 +558,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
|
||||
};
|
||||
let ty = bx.cast_backend_type(cast_ty);
|
||||
bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi)
|
||||
load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi)
|
||||
}
|
||||
};
|
||||
bx.ret(llval);
|
||||
|
|
@ -1618,8 +1617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
MemFlags::empty(),
|
||||
);
|
||||
// ...and then load it with the ABI type.
|
||||
let cast_ty = bx.cast_backend_type(cast);
|
||||
llval = bx.load(cast_ty, llscratch, scratch_align);
|
||||
llval = load_cast(bx, cast, llscratch, scratch_align);
|
||||
bx.lifetime_end(llscratch, scratch_size);
|
||||
} else {
|
||||
// We can't use `PlaceRef::load` here because the argument
|
||||
|
|
@ -1969,3 +1967,47 @@ enum ReturnDest<'tcx, V> {
|
|||
/// Store a direct return value to an operand local place.
|
||||
DirectOperand(mir::Local),
|
||||
}
|
||||
|
||||
fn load_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
cast: &CastTarget,
|
||||
ptr: Bx::Value,
|
||||
align: Align,
|
||||
) -> Bx::Value {
|
||||
let cast_ty = bx.cast_backend_type(cast);
|
||||
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_ty = bx.reg_backend_type(&cast.prefix[0].unwrap());
|
||||
let second_ty = bx.reg_backend_type(&cast.rest.unit);
|
||||
let first = bx.load(first_ty, ptr, align);
|
||||
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
|
||||
let second = bx.load(second_ty, second_ptr, align.restrict_for_offset(offset_from_start));
|
||||
let res = bx.cx().const_poison(cast_ty);
|
||||
let res = bx.insert_value(res, first, 0);
|
||||
bx.insert_value(res, second, 1)
|
||||
} else {
|
||||
bx.load(cast_ty, ptr, align)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn store_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
cast: &CastTarget,
|
||||
value: Bx::Value,
|
||||
ptr: Bx::Value,
|
||||
align: Align,
|
||||
) {
|
||||
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);
|
||||
assert!(cast.prefix[0].is_some());
|
||||
let first = bx.extract_value(value, 0);
|
||||
let second = bx.extract_value(value, 1);
|
||||
bx.store(first, ptr, align);
|
||||
let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
|
||||
bx.store(second, second_ptr, align.restrict_for_offset(offset_from_start));
|
||||
} else {
|
||||
bx.store(value, ptr, align);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
|
||||
llsize
|
||||
}
|
||||
sym::min_align_of_val => {
|
||||
sym::align_of_val => {
|
||||
let tp_ty = fn_args.type_at(0);
|
||||
let (_, meta) = args[0].val.pointer_parts();
|
||||
let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
|
||||
|
|
|
|||
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