Merge from rust-lang/rust

This commit is contained in:
Laurențiu Nicola 2025-06-18 09:23:24 +03:00
commit 96e1d731ee
2305 changed files with 30472 additions and 16390 deletions

View file

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

View file

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

View file

@ -80,9 +80,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.18"
version = "0.6.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
dependencies = [
"anstyle",
"anstyle-parse",
@ -95,58 +95,58 @@ dependencies = [
[[package]]
name = "anstyle"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
[[package]]
name = "anstyle-lossy"
version = "1.1.3"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "934ff8719effd2023a48cf63e69536c1c3ced9d3895068f6f5cc9a4ff845e59b"
checksum = "04d3a5dc826f84d0ea11882bb8054ff7f3d482602e11bb181101303a279ea01f"
dependencies = [
"anstyle",
]
[[package]]
name = "anstyle-parse"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "anstyle-svg"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3607949e9f6de49ea4bafe12f5e4fd73613ebf24795e48587302a8cc0e4bb35"
checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a"
dependencies = [
"anstream",
"anstyle",
"anstyle-lossy",
"anstyle-parse",
"html-escape",
"unicode-width 0.2.0",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.7"
version = "3.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
dependencies = [
"anstyle",
"once_cell",
"once_cell_polyfill",
"windows-sys 0.59.0",
]
@ -266,9 +266,9 @@ dependencies = [
[[package]]
name = "bitflags"
version = "2.9.0"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
[[package]]
name = "blake3"
@ -341,15 +341,15 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.17.0"
version = "3.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
[[package]]
name = "bytecount"
version = "0.6.8"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
[[package]]
name = "bytes"
@ -359,9 +359,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "camino"
version = "1.1.9"
version = "1.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
dependencies = [
"serde",
]
@ -487,9 +487,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.38"
version = "4.5.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
dependencies = [
"clap_builder",
"clap_derive",
@ -507,9 +507,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.38"
version = "4.5.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
dependencies = [
"anstream",
"anstyle",
@ -642,16 +642,16 @@ dependencies = [
[[package]]
name = "color-eyre"
version = "0.6.4"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec"
checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d"
dependencies = [
"backtrace",
"color-spantrace",
"eyre",
"indenter",
"once_cell",
"owo-colors 4.2.0",
"owo-colors 4.2.1",
"tracing-error",
]
@ -678,21 +678,21 @@ dependencies = [
[[package]]
name = "color-spantrace"
version = "0.2.2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5"
checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427"
dependencies = [
"once_cell",
"owo-colors 4.2.0",
"owo-colors 4.2.1",
"tracing-core",
"tracing-error",
]
[[package]]
name = "colorchoice"
version = "1.0.3"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
[[package]]
name = "colored"
@ -851,9 +851,9 @@ dependencies = [
[[package]]
name = "curl"
version = "0.4.47"
version = "0.4.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265"
checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b"
dependencies = [
"curl-sys",
"libc",
@ -861,14 +861,14 @@ dependencies = [
"openssl-sys",
"schannel",
"socket2",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
name = "curl-sys"
version = "0.4.80+curl-8.12.1"
version = "0.4.82+curl-8.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734"
checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be"
dependencies = [
"cc",
"libc",
@ -876,7 +876,7 @@ dependencies = [
"openssl-sys",
"pkg-config",
"vcpkg",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@ -1142,9 +1142,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.11"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
dependencies = [
"libc",
"windows-sys 0.59.0",
@ -1207,9 +1207,9 @@ dependencies = [
[[package]]
name = "flate2"
version = "1.1.1"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
dependencies = [
"crc32fast",
"miniz_oxide",
@ -1487,9 +1487,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.3"
version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
dependencies = [
"allocator-api2",
"equivalent",
@ -1511,9 +1511,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.3.9"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
[[package]]
name = "hex"
@ -1700,9 +1700,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
[[package]]
name = "icu_properties"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
dependencies = [
"displaydoc",
"icu_collections",
@ -1716,9 +1716,9 @@ dependencies = [
[[package]]
name = "icu_properties_data"
version = "2.0.0"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
[[package]]
name = "icu_provider"
@ -1933,9 +1933,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.13"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
dependencies = [
"jiff-static",
"log",
@ -1946,9 +1946,9 @@ dependencies = [
[[package]]
name = "jiff-static"
version = "0.2.13"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
dependencies = [
"proc-macro2",
"quote",
@ -2002,9 +2002,9 @@ dependencies = [
[[package]]
name = "jsonpath-rust"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9"
checksum = "5b37465feaf9d41f74df7da98c6c1c31ca8ea06d11b5bf7869c8f1ccc51a793f"
dependencies = [
"pest",
"pest_derive",
@ -2080,9 +2080,9 @@ dependencies = [
[[package]]
name = "libloading"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-targets 0.53.0",
@ -2170,9 +2170,9 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.12"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
@ -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"

View file

@ -381,6 +381,15 @@
# "miri", "cargo-miri" # for dev/nightly channels
#]
# Specify build configuration specific for some tool, such as enabled features.
# This option has no effect on which tools are enabled: refer to the `tools` option for that.
#
# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]`
#
# The default value for the `features` array is `[]`. However, please note that other flags in
# `bootstrap.toml` might influence the features enabled for some tools.
#tool.TOOL_NAME.features = [FEATURE1, FEATURE2]
# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
#verbose = 0

View file

@ -28,6 +28,9 @@ pub enum CanonAbi {
Rust,
RustCold,
/// An ABI that rustc does not know how to call or define.
Custom,
/// ABIs relevant to 32-bit Arm targets
Arm(ArmCall),
/// ABI relevant to GPUs: the entry point for a GPU kernel
@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
CanonAbi::C => ExternAbi::C { unwind: false },
CanonAbi::Rust => ExternAbi::Rust,
CanonAbi::RustCold => ExternAbi::RustCold,
CanonAbi::Custom => ExternAbi::Custom,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,

View file

@ -40,6 +40,11 @@ pub enum ExternAbi {
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
Unadjusted,
/// An ABI that rustc does not know how to call or define. Functions with this ABI can
/// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
/// be called from inline assembly.
Custom,
/// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
/// and only valid on platforms that have a UEFI standard
EfiApi,
@ -141,6 +146,7 @@ abi_impls! {
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
Cdecl { unwind: false } =><= "cdecl",
Cdecl { unwind: true } =><= "cdecl-unwind",
Custom =><= "custom",
EfiApi =><= "efiapi",
Fastcall { unwind: false } =><= "fastcall",
Fastcall { unwind: true } =><= "fastcall-unwind",

View file

@ -97,12 +97,12 @@ pub struct Path {
pub tokens: Option<LazyAttrTokenStream>,
}
// Succeeds if the path has a single segment that is arg-free and matches the given symbol.
impl PartialEq<Symbol> for Path {
#[inline]
fn eq(&self, name: &Symbol) -> bool {
if let [segment] = self.segments.as_ref()
&& segment.args.is_none()
&& segment.ident.name == *name
&& segment == name
{
true
} else {
@ -111,6 +111,15 @@ impl PartialEq<Symbol> for Path {
}
}
// Succeeds if the path has segments that are arg-free and match the given symbols.
impl PartialEq<&[Symbol]> for Path {
#[inline]
fn eq(&self, names: &&[Symbol]) -> bool {
self.segments.len() == names.len()
&& self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2)
}
}
impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
self.segments.len().hash_stable(hcx, hasher);
@ -166,6 +175,14 @@ pub struct PathSegment {
pub args: Option<P<GenericArgs>>,
}
// Succeeds if the path segment is arg-free and matches the given symbol.
impl PartialEq<Symbol> for PathSegment {
#[inline]
fn eq(&self, name: &Symbol) -> bool {
self.args.is_none() && self.ident.name == *name
}
}
impl PathSegment {
pub fn from_ident(ident: Ident) -> Self {
PathSegment { ident, id: DUMMY_NODE_ID, args: None }
@ -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 {

View file

@ -11,7 +11,7 @@ use std::ops::DerefMut;
use std::panic;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_span::source_map::Spanned;
use rustc_span::{Ident, Span};
use smallvec::{Array, SmallVec, smallvec};
use thin_vec::ThinVec;
@ -19,7 +19,7 @@ use thin_vec::ThinVec;
use crate::ast::*;
use crate::ptr::P;
use crate::tokenstream::*;
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit, visit_opt, walk_list};
use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list};
pub trait ExpectOne<A: Array> {
fn expect_one(self, err: &'static str) -> A::Item;
@ -32,7 +32,22 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
}
}
pub trait MutVisitor: Sized {
mod sealed {
use rustc_ast_ir::visit::VisitorResult;
/// This is for compatibility with the regular `Visitor`.
pub trait MutVisitorResult {
type Result: VisitorResult;
}
impl<T> MutVisitorResult for T {
type Result = ();
}
}
use sealed::MutVisitorResult;
pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
// Methods in this trait have one of three forms:
//
// fn visit_t(&mut self, t: &mut T); // common
@ -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

View file

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

View file

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

View file

@ -73,16 +73,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Merge attributes into the inner expression.
if !e.attrs.is_empty() {
let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);
let attrs = &*self.arena.alloc_from_iter(
self.lower_attrs_vec(&e.attrs, e.span)
.into_iter()
.chain(old_attrs.iter().cloned()),
);
if attrs.is_empty() {
let new_attrs = self
.lower_attrs_vec(&e.attrs, e.span, ex.hir_id)
.into_iter()
.chain(old_attrs.iter().cloned());
let new_attrs = &*self.arena.alloc_from_iter(new_attrs);
if new_attrs.is_empty() {
return ex;
}
self.attrs.insert(ex.hir_id.local_id, attrs);
self.attrs.insert(ex.hir_id.local_id, new_attrs);
}
return ex;
}
@ -2035,7 +2034,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let ret_expr = self.checked_return(Some(from_residual_expr));
self.arena.alloc(self.expr(try_span, ret_expr))
};
self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span);
self.lower_attrs(ret_expr.hir_id, &attrs, span);
let break_pat = self.pat_cf_break(try_span, residual_local);
self.arm(break_pat, ret_expr)

View file

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

View file

@ -51,6 +51,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
use rustc_hir::lints::DelayedLint;
use rustc_hir::{
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
@ -141,6 +142,8 @@ struct LoweringContext<'a, 'hir> {
allow_for_await: Arc<[Symbol]>,
allow_async_fn_traits: Arc<[Symbol]>,
delayed_lints: Vec<DelayedLint>,
attribute_parser: AttributeParser<'hir>,
}
@ -190,6 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
delayed_lints: Vec::new(),
}
}
@ -198,6 +202,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
struct SpanLowerer {
is_incremental: bool,
def_id: LocalDefId,
}
impl SpanLowerer {
fn lower(&self, span: Span) -> Span {
if self.is_incremental {
span.with_parent(Some(self.def_id))
} else {
// Do not make spans relative when not using incremental compilation.
span
}
}
}
#[extension(trait ResolverAstLoweringExt)]
impl ResolverAstLowering {
fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
@ -503,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
) -> LocalDefId {
let parent = self.current_hir_id_owner.def_id;
debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
assert_ne!(node_id, ast::DUMMY_NODE_ID);
assert!(
self.opt_local_def_id(node_id).is_none(),
"adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}",
@ -573,6 +593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
let current_delayed_lints = std::mem::take(&mut self.delayed_lints);
// Do not reset `next_node_id` and `node_id_to_def_id`:
// we want `f` to be able to refer to the `LocalDefId`s that the caller created.
@ -586,10 +607,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
let item = f(self);
debug_assert_eq!(owner_id, item.def_id());
assert_eq!(owner_id, item.def_id());
// `f` should have consumed all the elements in these vectors when constructing `item`.
debug_assert!(self.impl_trait_defs.is_empty());
debug_assert!(self.impl_trait_bounds.is_empty());
assert!(self.impl_trait_defs.is_empty());
assert!(self.impl_trait_bounds.is_empty());
let info = self.make_owner_info(item);
self.attrs = current_attrs;
@ -606,6 +627,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.item_local_id_counter = current_local_counter;
self.impl_trait_defs = current_impl_trait_defs;
self.impl_trait_bounds = current_impl_trait_bounds;
self.delayed_lints = current_delayed_lints;
debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id));
self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info)));
@ -616,6 +638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let mut bodies = std::mem::take(&mut self.bodies);
let define_opaque = std::mem::take(&mut self.define_opaque);
let trait_map = std::mem::take(&mut self.trait_map);
let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice();
#[cfg(debug_assertions)]
for (id, attrs) in attrs.iter() {
@ -629,14 +652,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let bodies = SortedMap::from_presorted_elements(bodies);
// Don't hash unless necessary, because it's expensive.
let (opt_hash_including_bodies, attrs_hash) =
self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) =
self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
let num_nodes = self.item_local_id_counter.as_usize();
let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
let delayed_lints =
hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash };
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints })
}
/// This method allocates a new `HirId` for the given `NodeId`.
@ -759,15 +784,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
}
fn span_lowerer(&self) -> SpanLowerer {
SpanLowerer {
is_incremental: self.tcx.sess.opts.incremental.is_some(),
def_id: self.current_hir_id_owner.def_id,
}
}
/// Intercept all spans entering HIR.
/// Mark a span as relative to the current owning item.
fn lower_span(&self, span: Span) -> Span {
if self.tcx.sess.opts.incremental.is_some() {
span.with_parent(Some(self.current_hir_id_owner.def_id))
} else {
// Do not make spans relative when not using incremental compilation.
span
}
self.span_lowerer().lower(span)
}
fn lower_ident(&self, ident: Ident) -> Ident {
@ -889,9 +916,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
if attrs.is_empty() {
&[]
} else {
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id);
debug_assert_eq!(id.owner, self.current_hir_id_owner);
assert_eq!(id.owner, self.current_hir_id_owner);
let ret = self.arena.alloc_from_iter(lowered_attrs);
// this is possible if an item contained syntactical attribute,
@ -909,16 +936,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> {
self.attribute_parser
.parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s))
fn lower_attrs_vec(
&mut self,
attrs: &[Attribute],
target_span: Span,
target_hir_id: HirId,
) -> Vec<hir::Attribute> {
let l = self.span_lowerer();
self.attribute_parser.parse_attribute_list(
attrs,
target_span,
target_hir_id,
OmitDoc::Lower,
|s| l.lower(s),
|l| {
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
},
)
}
fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
debug_assert_eq!(id.owner, self.current_hir_id_owner);
debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
assert_eq!(id.owner, self.current_hir_id_owner);
assert_eq!(target_id.owner, self.current_hir_id_owner);
if let Some(&a) = self.attrs.get(&target_id.local_id) {
debug_assert!(!a.is_empty());
assert!(!a.is_empty());
self.attrs.insert(id.local_id, a);
}
}
@ -1397,7 +1438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
self.resolver.get_lifetime_res(t.id)
{
debug_assert_eq!(start.plus(1), end);
assert_eq!(start.plus(1), end);
start
} else {
self.next_node_id()
@ -1805,16 +1846,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let res = match res {
LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
LifetimeRes::Fresh { param, .. } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
assert_eq!(ident.name, kw::UnderscoreLifetime);
let param = self.local_def_id(param);
hir::LifetimeKind::Param(param)
}
LifetimeRes::Infer => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
assert_eq!(ident.name, kw::UnderscoreLifetime);
hir::LifetimeKind::Infer
}
LifetimeRes::Static { .. } => {
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
hir::LifetimeKind::Static
}
LifetimeRes::Error => hir::LifetimeKind::Error,
@ -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 {

View file

@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
feature: sym::cmse_nonsecure_entry,
explain: GateReason::Experimental,
}),
ExternAbi::Custom => {
Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
}
}
}

View file

@ -1,3 +1,20 @@
ast_passes_abi_custom_coroutine =
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
ast_passes_abi_custom_invalid_signature =
invalid signature for `extern "custom"` function
.note = functions with the `"custom"` ABI cannot have any parameters or return type
.suggestion = remove the parameters and return type
ast_passes_abi_custom_safe_foreign_function =
foreign functions with the `"custom"` ABI cannot be safe
.suggestion = remove the `safe` keyword from this definition
ast_passes_abi_custom_safe_function =
functions with the `"custom"` ABI must be unsafe
.suggestion = add the `unsafe` keyword to this definition
ast_passes_assoc_const_without_body =
associated constant in `impl` without body
.suggestion = provide a definition for the constant

View file

@ -18,6 +18,7 @@
use std::mem;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use itertools::{Either, Itertools};
use rustc_abi::ExternAbi;
@ -81,6 +82,7 @@ struct AstValidator<'a> {
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
extern_mod_safety: Option<Safety>,
extern_mod_abi: Option<ExternAbi>,
lint_node_id: NodeId,
@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
self.outer_trait_or_trait_impl = old;
}
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
fn with_in_extern_mod(
&mut self,
extern_mod_safety: Safety,
abi: Option<ExternAbi>,
f: impl FnOnce(&mut Self),
) {
let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
f(self);
self.extern_mod_safety = old;
self.extern_mod_safety = old_safety;
self.extern_mod_abi = old_abi;
}
fn with_tilde_const(
@ -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,

View file

@ -824,3 +824,67 @@ pub(crate) struct MissingAbi {
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_safe_foreign_function)]
pub(crate) struct AbiCustomSafeForeignFunction {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "",
style = "verbose"
)]
pub safe_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_safe_function)]
pub(crate) struct AbiCustomSafeFunction {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "unsafe ",
style = "verbose"
)]
pub unsafe_span: Span,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_coroutine)]
pub(crate) struct AbiCustomCoroutine {
#[primary_span]
pub span: Span,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "",
style = "verbose"
)]
pub coroutine_kind_span: Span,
pub coroutine_kind_str: &'static str,
}
#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_invalid_signature)]
#[note]
pub(crate) struct AbiCustomInvalidSignature {
#[primary_span]
pub spans: Vec<Span>,
#[suggestion(
ast_passes_suggestion,
applicability = "maybe-incorrect",
code = "{padding}fn {symbol}()",
style = "verbose"
)]
pub suggestion_span: Span,
pub symbol: Symbol,
pub padding: &'static str,
}

View file

@ -36,6 +36,16 @@ macro_rules! gate_alt {
feature_err(&$visitor.sess, $name, $span, $explain).emit();
}
}};
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
for note in $notes {
diag.note(*note);
}
diag.emit();
}
}};
}
/// The case involving a multispan.
@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
// Check feature gates for built-in attributes.
if let Some(BuiltinAttribute {
gate: AttributeGate::Gated(_, name, descr, has_feature),
gate: AttributeGate::Gated { feature, message, check, notes, .. },
..
}) = attr_info
{
gate_alt!(self, has_feature(self.features), *name, attr.span, *descr);
gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
}
// Check unstable flavors of the `#[doc]` attribute.
if attr.has_name(sym::doc) {

View file

@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String {
State::new().item_to_string(i)
}
pub fn assoc_item_to_string(i: &ast::AssocItem) -> String {
State::new().assoc_item_to_string(i)
}
pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String {
State::new().foreign_item_to_string(i)
}
pub fn stmt_to_string(s: &ast::Stmt) -> String {
State::new().stmt_to_string(s)
}
pub fn path_to_string(p: &ast::Path) -> String {
State::new().path_to_string(p)
}

View file

@ -1063,6 +1063,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
Self::to_string(|s| s.print_item(i))
}
fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
Self::to_string(|s| s.print_assoc_item(i))
}
fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
Self::to_string(|s| s.print_foreign_item(i))
}
fn path_to_string(&self, p: &ast::Path) -> String {
Self::to_string(|s| s.print_path(p, false, 0))
}

View file

@ -7,8 +7,8 @@ use rustc_ast::util::classify;
use rustc_ast::util::literal::escape_byte_str_symbol;
use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
use rustc_ast::{
self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
self as ast, BinOpKind, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece,
FormatCount, FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
};
use crate::pp::Breaks::Inconsistent;
@ -214,13 +214,6 @@ impl<'a> State<'a> {
}
fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
let needs_paren = match func.kind {
// In order to call a named field, needs parens: `(self.fun)()`
// But not for an unnamed field: `self.0()`
ast::ExprKind::Field(_, name) => !name.is_numeric(),
_ => func.precedence() < ExprPrecedence::Unambiguous,
};
// Independent of parenthesization related to precedence, we must
// parenthesize `func` if this is a statement context in which without
// parentheses, a statement boundary would occur inside `func` or
@ -237,8 +230,16 @@ impl<'a> State<'a> {
// because the latter is valid syntax but with the incorrect meaning.
// It's a match-expression followed by tuple-expression, not a function
// call.
self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression());
let func_fixup = fixup.leftmost_subexpression_with_operator(true);
let needs_paren = match func.kind {
// In order to call a named field, needs parens: `(self.fun)()`
// But not for an unnamed field: `self.0()`
ast::ExprKind::Field(_, name) => !name.is_numeric(),
_ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous,
};
self.print_expr_cond_paren(func, needs_paren, func_fixup);
self.print_call_post(args)
}
@ -281,9 +282,24 @@ impl<'a> State<'a> {
rhs: &ast::Expr,
fixup: FixupContext,
) {
let operator_can_begin_expr = match op {
| BinOpKind::Sub // -x
| BinOpKind::Mul // *x
| BinOpKind::And // &&x
| BinOpKind::Or // || x
| BinOpKind::BitAnd // &x
| BinOpKind::BitOr // |x| x
| BinOpKind::Shl // <<T as Trait>::Type as Trait>::CONST
| BinOpKind::Lt // <T as Trait>::CONST
=> true,
_ => false,
};
let left_fixup = fixup.leftmost_subexpression_with_operator(operator_can_begin_expr);
let binop_prec = op.precedence();
let left_prec = lhs.precedence();
let right_prec = rhs.precedence();
let left_prec = left_fixup.precedence(lhs);
let right_prec = fixup.precedence(rhs);
let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
@ -312,18 +328,18 @@ impl<'a> State<'a> {
_ => {}
}
self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
self.print_expr_cond_paren(lhs, left_needs_paren, left_fixup);
self.space();
self.word_space(op.as_str());
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
self.print_expr_cond_paren(rhs, right_needs_paren, fixup.rightmost_subexpression());
}
fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
self.word(op.as_str());
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Prefix,
fixup.subsequent_subexpression(),
fixup.precedence(expr) < ExprPrecedence::Prefix,
fixup.rightmost_subexpression(),
);
}
@ -344,8 +360,8 @@ impl<'a> State<'a> {
}
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Prefix,
fixup.subsequent_subexpression(),
fixup.precedence(expr) < ExprPrecedence::Prefix,
fixup.rightmost_subexpression(),
);
}
@ -590,8 +606,8 @@ impl<'a> State<'a> {
self.word_space("=");
self.print_expr_cond_paren(
rhs,
rhs.precedence() < ExprPrecedence::Assign,
fixup.subsequent_subexpression(),
fixup.precedence(rhs) < ExprPrecedence::Assign,
fixup.rightmost_subexpression(),
);
}
ast::ExprKind::AssignOp(op, lhs, rhs) => {
@ -604,8 +620,8 @@ impl<'a> State<'a> {
self.word_space(op.node.as_str());
self.print_expr_cond_paren(
rhs,
rhs.precedence() < ExprPrecedence::Assign,
fixup.subsequent_subexpression(),
fixup.precedence(rhs) < ExprPrecedence::Assign,
fixup.rightmost_subexpression(),
);
}
ast::ExprKind::Field(expr, ident) => {
@ -618,10 +634,11 @@ impl<'a> State<'a> {
self.print_ident(*ident);
}
ast::ExprKind::Index(expr, index, _) => {
let expr_fixup = fixup.leftmost_subexpression_with_operator(true);
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Unambiguous,
fixup.leftmost_subexpression(),
expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous,
expr_fixup,
);
self.word("[");
self.print_expr(index, FixupContext::default());
@ -634,10 +651,11 @@ impl<'a> State<'a> {
// a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
let fake_prec = ExprPrecedence::LOr;
if let Some(e) = start {
let start_fixup = fixup.leftmost_subexpression_with_operator(true);
self.print_expr_cond_paren(
e,
e.precedence() < fake_prec,
fixup.leftmost_subexpression(),
start_fixup.precedence(e) < fake_prec,
start_fixup,
);
}
match limits {
@ -647,8 +665,8 @@ impl<'a> State<'a> {
if let Some(e) = end {
self.print_expr_cond_paren(
e,
e.precedence() < fake_prec,
fixup.subsequent_subexpression(),
fixup.precedence(e) < fake_prec,
fixup.rightmost_subexpression(),
);
}
}
@ -665,11 +683,10 @@ impl<'a> State<'a> {
self.space();
self.print_expr_cond_paren(
expr,
// Parenthesize if required by precedence, or in the
// case of `break 'inner: loop { break 'inner 1 } + 1`
expr.precedence() < ExprPrecedence::Jump
|| (opt_label.is_none() && classify::leading_labeled_expr(expr)),
fixup.subsequent_subexpression(),
// Parenthesize `break 'inner: loop { break 'inner 1 } + 1`
// ^---------------------------------^
opt_label.is_none() && classify::leading_labeled_expr(expr),
fixup.rightmost_subexpression(),
);
}
}
@ -684,11 +701,7 @@ impl<'a> State<'a> {
self.word("return");
if let Some(expr) = result {
self.word(" ");
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Jump,
fixup.subsequent_subexpression(),
);
self.print_expr(expr, fixup.rightmost_subexpression());
}
}
ast::ExprKind::Yeet(result) => {
@ -697,21 +710,13 @@ impl<'a> State<'a> {
self.word("yeet");
if let Some(expr) = result {
self.word(" ");
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Jump,
fixup.subsequent_subexpression(),
);
self.print_expr(expr, fixup.rightmost_subexpression());
}
}
ast::ExprKind::Become(result) => {
self.word("become");
self.word(" ");
self.print_expr_cond_paren(
result,
result.precedence() < ExprPrecedence::Jump,
fixup.subsequent_subexpression(),
);
self.print_expr(result, fixup.rightmost_subexpression());
}
ast::ExprKind::InlineAsm(a) => {
// FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`.
@ -761,11 +766,7 @@ impl<'a> State<'a> {
if let Some(expr) = e {
self.space();
self.print_expr_cond_paren(
expr,
expr.precedence() < ExprPrecedence::Jump,
fixup.subsequent_subexpression(),
);
self.print_expr(expr, fixup.rightmost_subexpression());
}
}
ast::ExprKind::Yield(YieldKind::Postfix(e)) => {

View file

@ -1,5 +1,6 @@
use rustc_ast::Expr;
use rustc_ast::util::{classify, parser};
use rustc_ast::util::classify;
use rustc_ast::util::parser::{self, ExprPrecedence};
use rustc_ast::{Expr, ExprKind, YieldKind};
// The default amount of fixing is minimal fixing, so all fixups are set to `false` by `Default`.
// Fixups should be turned on in a targeted fashion where needed.
@ -93,6 +94,24 @@ pub(crate) struct FixupContext {
/// }
/// ```
parenthesize_exterior_struct_lit: bool,
/// This is the difference between:
///
/// ```ignore (illustrative)
/// let _ = (return) - 1; // without paren, this would return -1
///
/// let _ = return + 1; // no paren because '+' cannot begin expr
/// ```
next_operator_can_begin_expr: bool,
/// This is the difference between:
///
/// ```ignore (illustrative)
/// let _ = 1 + return 1; // no parens if rightmost subexpression
///
/// let _ = 1 + (return 1) + 1; // needs parens
/// ```
next_operator_can_continue_expr: bool,
}
impl FixupContext {
@ -134,6 +153,8 @@ impl FixupContext {
match_arm: false,
leftmost_subexpression_in_match_arm: self.match_arm
|| self.leftmost_subexpression_in_match_arm,
next_operator_can_begin_expr: false,
next_operator_can_continue_expr: true,
..self
}
}
@ -148,19 +169,34 @@ impl FixupContext {
leftmost_subexpression_in_stmt: false,
match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
leftmost_subexpression_in_match_arm: false,
next_operator_can_begin_expr: false,
next_operator_can_continue_expr: true,
..self
}
}
/// Transform this fixup into the one that should apply when printing any
/// subexpression that is neither a leftmost subexpression nor surrounded in
/// delimiters.
/// Transform this fixup into the one that should apply when printing a
/// leftmost subexpression followed by punctuation that is legal as the
/// first token of an expression.
pub(crate) fn leftmost_subexpression_with_operator(
self,
next_operator_can_begin_expr: bool,
) -> Self {
FixupContext { next_operator_can_begin_expr, ..self.leftmost_subexpression() }
}
/// Transform this fixup into the one that should apply when printing the
/// rightmost subexpression of the current expression.
///
/// This is for any subexpression that has a different first token than the
/// current expression, and is not surrounded by a paren/bracket/brace. For
/// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
/// `$a.f($b)`.
pub(crate) fn subsequent_subexpression(self) -> Self {
/// The rightmost subexpression is any subexpression that has a different
/// first token than the current expression, but has the same last token.
///
/// For example in `$a + $b` and `-$b`, the subexpression `$b` is a
/// rightmost subexpression.
///
/// Not every expression has a rightmost subexpression. For example neither
/// `[$b]` nor `$a.f($b)` have one.
pub(crate) fn rightmost_subexpression(self) -> Self {
FixupContext {
stmt: false,
leftmost_subexpression_in_stmt: false,
@ -193,6 +229,39 @@ impl FixupContext {
/// "let chain".
pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
|| parser::needs_par_as_let_scrutinee(expr.precedence())
|| parser::needs_par_as_let_scrutinee(self.precedence(expr))
}
/// Determines the effective precedence of a subexpression. Some expressions
/// have higher or lower precedence when adjacent to particular operators.
pub(crate) fn precedence(self, expr: &Expr) -> ExprPrecedence {
if self.next_operator_can_begin_expr {
// Decrease precedence of value-less jumps when followed by an
// operator that would otherwise get interpreted as beginning a
// value for the jump.
if let ExprKind::Break(..)
| ExprKind::Ret(..)
| ExprKind::Yeet(..)
| ExprKind::Yield(YieldKind::Prefix(..)) = expr.kind
{
return ExprPrecedence::Jump;
}
}
if !self.next_operator_can_continue_expr {
// Increase precedence of expressions that extend to the end of
// current statement or group.
if let ExprKind::Break(..)
| ExprKind::Closure(..)
| ExprKind::Ret(..)
| ExprKind::Yeet(..)
| ExprKind::Yield(YieldKind::Prefix(..))
| ExprKind::Range(None, ..) = expr.kind
{
return ExprPrecedence::Prefix;
}
}
expr.precedence()
}
}

View file

@ -28,7 +28,7 @@ impl<'a> State<'a> {
}
}
fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
self.ann.pre(self, AnnNode::SubItem(id));
self.hardbreak_if_not_bol();
@ -548,7 +548,7 @@ impl<'a> State<'a> {
}
}
fn print_assoc_item(&mut self, item: &ast::AssocItem) {
pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
self.ann.pre(self, AnnNode::SubItem(id));
self.hardbreak_if_not_bol();

View file

@ -57,14 +57,6 @@ impl OptimizeAttr {
}
}
#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
pub enum DiagnosticAttribute {
// tidy-alphabetical-start
DoNotRecommend,
OnUnimplemented,
// tidy-alphabetical-end
}
#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)]
pub enum ReprAttr {
ReprInt(IntType),
@ -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

View file

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

View file

@ -0,0 +1,14 @@
use rustc_macros::HashStable_Generic;
use rustc_span::Span;
#[derive(Clone, Debug, HashStable_Generic)]
pub struct AttributeLint<Id> {
pub id: Id,
pub span: Span,
pub kind: AttributeLintKind,
}
#[derive(Clone, Debug, HashStable_Generic)]
pub enum AttributeLintKind {
UnusedDuplicate { this: Span, other: Span, warning: bool },
}

View file

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

View file

@ -131,7 +131,15 @@ attr_parsing_unsupported_literal_generic =
attr_parsing_unsupported_literal_suggestion =
consider removing the prefix
attr_parsing_unused_duplicate =
unused attribute
.suggestion = remove this attribute
.note = attribute also specified here
.warn = {-passes_previously_accepted}
attr_parsing_unused_multiple =
multiple `{$name}` attributes
.suggestion = remove this attribute
.note = attribute also specified here
-attr_parsing_perviously_accepted =
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!

View file

@ -4,41 +4,43 @@ use rustc_attr_data_structures::AttributeKind;
use rustc_span::{Span, Symbol, sym};
use super::{CombineAttributeParser, ConvertFn};
use crate::context::AcceptContext;
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::session_diagnostics;
pub(crate) struct AllowInternalUnstableParser;
impl CombineAttributeParser for AllowInternalUnstableParser {
const PATH: &'static [Symbol] = &[sym::allow_internal_unstable];
impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
const PATH: &[Symbol] = &[sym::allow_internal_unstable];
type Item = (Symbol, Span);
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
fn extend<'a>(
cx: &'a AcceptContext<'a>,
args: &'a ArgParser<'a>,
) -> impl IntoIterator<Item = Self::Item> + 'a {
parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span))
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> {
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
.into_iter()
.zip(iter::repeat(cx.attr_span))
}
}
pub(crate) struct AllowConstFnUnstableParser;
impl CombineAttributeParser for AllowConstFnUnstableParser {
const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable];
impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
type Item = Symbol;
const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
fn extend<'a>(
cx: &'a AcceptContext<'a>,
args: &'a ArgParser<'a>,
) -> impl IntoIterator<Item = Self::Item> + 'a {
parse_unstable(cx, args, Self::PATH[0])
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> + 'c {
parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
}
}
fn parse_unstable<'a>(
cx: &AcceptContext<'_>,
args: &'a ArgParser<'a>,
fn parse_unstable<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
args: &ArgParser<'_>,
symbol: Symbol,
) -> impl IntoIterator<Item = Symbol> {
let mut res = Vec::new();

View file

@ -3,7 +3,7 @@ use rustc_span::{Span, Symbol, sym};
use thin_vec::ThinVec;
use super::{AcceptMapping, AttributeParser};
use crate::context::FinalizeContext;
use crate::context::{FinalizeContext, Stage};
use crate::session_diagnostics;
#[derive(Default)]
@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser {
first_span: Option<Span>,
}
impl AttributeParser for ConfusablesParser {
const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| {
impl<S: Stage> AttributeParser<S> for ConfusablesParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
let Some(list) = args.list() else {
// FIXME(jdonszelmann): error when not a list? Bring validation code here.
// NOTE: currently subsequent attributes are silently ignored using
@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser {
this.first_span.get_or_insert(cx.attr_span);
})];
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if self.confusables.is_empty() {
return None;
}

View file

@ -1,17 +1,17 @@
use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
use rustc_span::{Span, Symbol, sym};
use super::SingleAttributeParser;
use super::util::parse_version;
use crate::context::AcceptContext;
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::session_diagnostics;
use crate::session_diagnostics::UnsupportedLiteralReason;
pub(crate) struct DeprecationParser;
fn get(
cx: &AcceptContext<'_>,
fn get<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
name: Symbol,
param_span: Span,
arg: &ArgParser<'_>,
@ -41,19 +41,12 @@ fn get(
}
}
impl SingleAttributeParser for DeprecationParser {
const PATH: &'static [Symbol] = &[sym::deprecated];
impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
const PATH: &[Symbol] = &[sym::deprecated];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) {
// FIXME(jdonszelmann): merge with errors from check_attrs.rs
cx.emit_err(session_diagnostics::UnusedMultiple {
this: cx.attr_span,
other: first_span,
name: sym::deprecated,
});
}
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let features = cx.features();
let mut since = None;

View file

@ -0,0 +1,97 @@
// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here.
// note: need to model better how duplicate attr errors work when not using
// SingleAttributeParser which is what we have two of here.
use rustc_attr_data_structures::lints::AttributeLintKind;
use rustc_attr_data_structures::{AttributeKind, InlineAttr};
use rustc_feature::{AttributeTemplate, template};
use rustc_span::{Symbol, sym};
use super::{AcceptContext, AttributeOrder, OnDuplicate};
use crate::attributes::SingleAttributeParser;
use crate::context::Stage;
use crate::parser::ArgParser;
pub(crate) struct InlineParser;
impl<S: Stage> SingleAttributeParser<S> for InlineParser {
const PATH: &'static [Symbol] = &[sym::inline];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
match args {
ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
ArgParser::List(list) => {
let Some(l) = list.single() else {
cx.expected_single_argument(list.span);
return None;
};
match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) {
Some(sym::always) => {
Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
}
Some(sym::never) => {
Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
}
_ => {
cx.expected_specific_argument(l.span(), vec!["always", "never"]);
return None;
}
}
}
ArgParser::NameValue(_) => {
let suggestions =
<Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline");
cx.emit_lint(
AttributeLintKind::IllFormedAttributeInput { suggestions },
cx.attr_span,
);
return None;
}
}
}
}
pub(crate) struct RustcForceInlineParser;
impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
let reason = match args {
ArgParser::NoArgs => None,
ArgParser::List(list) => {
let Some(l) = list.single() else {
cx.expected_single_argument(list.span);
return None;
};
let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
cx.expected_string_literal(l.span());
return None;
};
Some(reason)
}
ArgParser::NameValue(v) => {
let Some(reason) = v.value_as_str() else {
cx.expected_string_literal(v.value_span);
return None;
};
Some(reason)
}
};
Some(AttributeKind::Inline(
InlineAttr::Force { attr_span: cx.attr_span, reason },
cx.attr_span,
))
}
}

View file

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

View file

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

View file

@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use super::{CombineAttributeParser, ConvertFn};
use crate::context::AcceptContext;
use crate::context::{AcceptContext, Stage};
use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
use crate::session_diagnostics;
use crate::session_diagnostics::IncorrectReprFormatGenericCause;
@ -19,15 +19,15 @@ use crate::session_diagnostics::IncorrectReprFormatGenericCause;
// FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct?
pub(crate) struct ReprParser;
impl CombineAttributeParser for ReprParser {
impl<S: Stage> CombineAttributeParser<S> for ReprParser {
type Item = (ReprAttr, Span);
const PATH: &'static [Symbol] = &[sym::repr];
const PATH: &[Symbol] = &[sym::repr];
const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
fn extend<'a>(
cx: &'a AcceptContext<'a>,
args: &'a ArgParser<'a>,
) -> impl IntoIterator<Item = Self::Item> + 'a {
fn extend<'c>(
cx: &'c mut AcceptContext<'_, '_, S>,
args: &'c ArgParser<'_>,
) -> impl IntoIterator<Item = Self::Item> + 'c {
let mut reprs = Vec::new();
let Some(list) = args.list() else {
@ -91,7 +91,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> {
}
}
fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> {
fn parse_repr<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
param: &MetaItemParser<'_>,
) -> Option<ReprAttr> {
use ReprAttr::*;
// FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
@ -180,8 +183,8 @@ enum AlignKind {
Align,
}
fn parse_repr_align(
cx: &AcceptContext<'_>,
fn parse_repr_align<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
list: &MetaItemListParser<'_>,
param_span: Span,
align_kind: AlignKind,

View file

@ -8,8 +8,8 @@ use rustc_errors::ErrorGuaranteed;
use rustc_span::{Span, Symbol, sym};
use super::util::parse_version;
use super::{AcceptMapping, AttributeParser, SingleAttributeParser};
use crate::context::{AcceptContext, FinalizeContext};
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::{ArgParser, MetaItemParser};
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
@ -31,7 +31,7 @@ pub(crate) struct StabilityParser {
impl StabilityParser {
/// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
if let Some((_, _)) = self.stability {
cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
true
@ -41,8 +41,8 @@ impl StabilityParser {
}
}
impl AttributeParser for StabilityParser {
const ATTRIBUTES: AcceptMapping<Self> = &[
impl<S: Stage> AttributeParser<S> for StabilityParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[
(&[sym::stable], |this, cx, args| {
reject_outside_std!(cx);
if !this.check_duplicate(cx)
@ -65,7 +65,7 @@ impl AttributeParser for StabilityParser {
}),
];
fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if let Some(atum) = self.allowed_through_unstable_modules {
if let Some((
Stability {
@ -95,8 +95,8 @@ pub(crate) struct BodyStabilityParser {
stability: Option<(DefaultBodyStability, Span)>,
}
impl AttributeParser for BodyStabilityParser {
const ATTRIBUTES: AcceptMapping<Self> =
impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
const ATTRIBUTES: AcceptMapping<Self, S> =
&[(&[sym::rustc_default_body_unstable], |this, cx, args| {
reject_outside_std!(cx);
if this.stability.is_some() {
@ -107,7 +107,7 @@ impl AttributeParser for BodyStabilityParser {
}
})];
fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
let (stability, span) = self.stability?;
Some(AttributeKind::BodyStability { stability, span })
@ -116,13 +116,12 @@ impl AttributeParser for BodyStabilityParser {
pub(crate) struct ConstStabilityIndirectParser;
// FIXME(jdonszelmann): single word attribute group when we have these
impl SingleAttributeParser for ConstStabilityIndirectParser {
const PATH: &'static [Symbol] = &[sym::rustc_const_stable_indirect];
impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
// ignore
fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {}
fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
Some(AttributeKind::ConstStabilityIndirect)
}
}
@ -135,7 +134,7 @@ pub(crate) struct ConstStabilityParser {
impl ConstStabilityParser {
/// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
if let Some((_, _)) = self.stability {
cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
true
@ -145,8 +144,8 @@ impl ConstStabilityParser {
}
}
impl AttributeParser for ConstStabilityParser {
const ATTRIBUTES: AcceptMapping<Self> = &[
impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
const ATTRIBUTES: AcceptMapping<Self, S> = &[
(&[sym::rustc_const_stable], |this, cx, args| {
reject_outside_std!(cx);
@ -176,7 +175,7 @@ impl AttributeParser for ConstStabilityParser {
}),
];
fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
if self.promotable {
if let Some((ref mut stab, _)) = self.stability {
stab.promotable = true;
@ -196,8 +195,8 @@ impl AttributeParser for ConstStabilityParser {
///
/// Emits an error when either the option was already Some, or the arguments weren't of form
/// `name = value`
fn insert_value_into_option_or_error(
cx: &AcceptContext<'_>,
fn insert_value_into_option_or_error<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
param: &MetaItemParser<'_>,
item: &mut Option<Symbol>,
) -> Option<()> {
@ -223,8 +222,8 @@ fn insert_value_into_option_or_error(
/// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
/// its stability information.
pub(crate) fn parse_stability(
cx: &AcceptContext<'_>,
pub(crate) fn parse_stability<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
args: &ArgParser<'_>,
) -> Option<(Symbol, StabilityLevel)> {
let mut feature = None;
@ -289,8 +288,8 @@ pub(crate) fn parse_stability(
// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
/// attribute, and return the feature name and its stability information.
pub(crate) fn parse_unstability(
cx: &AcceptContext<'_>,
pub(crate) fn parse_unstability<S: Stage>(
cx: &AcceptContext<'_, '_, S>,
args: &ArgParser<'_>,
) -> Option<(Symbol, StabilityLevel)> {
let mut feature = None;
@ -299,6 +298,7 @@ pub(crate) fn parse_unstability(
let mut issue_num = None;
let mut is_soft = false;
let mut implied_by = None;
let mut old_name = None;
for param in args.list()?.mixed() {
let Some(param) = param.meta_item() else {
cx.emit_err(session_diagnostics::UnsupportedLiteral {
@ -346,11 +346,12 @@ pub(crate) fn parse_unstability(
Some(sym::implied_by) => {
insert_value_into_option_or_error(cx, &param, &mut implied_by)?
}
Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &mut old_name)?,
_ => {
cx.emit_err(session_diagnostics::UnknownMetaItem {
span: param.span(),
item: param.path().to_string(),
expected: &["feature", "reason", "issue", "soft", "implied_by"],
expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
});
return None;
}
@ -375,6 +376,7 @@ pub(crate) fn parse_unstability(
issue: issue_num,
is_soft,
implied_by,
old_name,
};
Some((feature, level))
}

View file

@ -1,8 +1,9 @@
use rustc_attr_data_structures::AttributeKind;
use rustc_span::hygiene::Transparency;
use rustc_span::{Span, Symbol, sym};
use rustc_span::{Symbol, sym};
use super::{AcceptContext, SingleAttributeParser};
use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
pub(crate) struct TransparencyParser;
@ -10,14 +11,14 @@ pub(crate) struct TransparencyParser;
// FIXME(jdonszelmann): make these proper diagnostics
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
impl SingleAttributeParser for TransparencyParser {
const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency];
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
});
fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) {
cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes");
}
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
match args.name_value().and_then(|nv| nv.value_as_str()) {
Some(sym::transparent) => Some(Transparency::Transparent),
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),

View file

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

View file

@ -85,7 +85,8 @@
#[macro_use]
mod attributes;
mod context;
pub(crate) mod context;
mod lints;
pub mod parser;
mod session_diagnostics;
@ -93,6 +94,7 @@ pub use attributes::cfg::*;
pub use attributes::util::{
find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
};
pub use context::{AttributeParser, OmitDoc};
pub use context::{AttributeParser, Early, Late, OmitDoc};
pub use lints::emit_attribute_lint;
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }

View file

@ -0,0 +1,19 @@
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
use rustc_errors::LintEmitter;
use rustc_hir::HirId;
use crate::session_diagnostics;
pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
let AttributeLint { id, span, kind } = lint;
match kind {
&AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter
.emit_node_span_lint(
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
*id,
*span,
session_diagnostics::UnusedDuplicate { this, other, warning },
),
}
}

View file

@ -115,7 +115,7 @@ impl<'a> ArgParser<'a> {
}
}
pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self {
pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
match value {
AttrArgs::Empty => Self::NoArgs,
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
@ -235,7 +235,7 @@ impl<'a> Debug for MetaItemParser<'a> {
impl<'a> MetaItemParser<'a> {
/// Create a new parser from a [`NormalAttr`], which is stored inside of any
/// [`ast::Attribute`](rustc_ast::Attribute)
pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self {
pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self {
Self {
path: PathParser::Ast(&attr.item.path),
args: ArgParser::from_attr_args(&attr.item.args, dcx),
@ -320,13 +320,13 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit
}
}
struct MetaItemListParserContext<'a> {
struct MetaItemListParserContext<'a, 'sess> {
// the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside
inside_delimiters: Peekable<TokenStreamIter<'a>>,
dcx: DiagCtxtHandle<'a>,
dcx: DiagCtxtHandle<'sess>,
}
impl<'a> MetaItemListParserContext<'a> {
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
fn done(&mut self) -> bool {
self.inside_delimiters.peek().is_none()
}
@ -507,11 +507,11 @@ pub struct MetaItemListParser<'a> {
}
impl<'a> MetaItemListParser<'a> {
fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> {
fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx)
}
fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self {
fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self {
MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span)
}

View file

@ -3,7 +3,7 @@ use std::num::IntErrorKind;
use rustc_ast as ast;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_span::{Span, Symbol};
use crate::fluent_generated as fluent;
@ -451,6 +451,17 @@ pub(crate) struct UnusedMultiple {
pub name: Symbol,
}
#[derive(LintDiagnostic)]
#[diag(attr_parsing_unused_duplicate)]
pub(crate) struct UnusedDuplicate {
#[suggestion(code = "", applicability = "machine-applicable")]
pub this: Span,
#[note]
pub other: Span,
#[warning]
pub warning: bool,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
pub(crate) struct StabilityOutsideStd {

View file

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

View file

@ -3229,8 +3229,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
Applicability::MaybeIncorrect,
);
}
let mutability = if matches!(borrow.kind(), BorrowKind::Mut { .. }) {
"mut "
} else {
""
};
if !is_format_arguments_item {
let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
let addition = format!(
"let {}binding = {};\n{}",
mutability,
s,
" ".repeat(p)
);
err.multipart_suggestion_verbose(
msg,
vec![

View file

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

View file

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

View file

@ -141,8 +141,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
}
if !tcx.recursion_limit().value_within_limit(iteration) {
// This may actually be reachable. If so, we should convert
// this to a proper error/consider whether we should detect
// this somewhere else.
bug!(
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
"unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
);
}

View file

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

View file

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

View file

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

View file

@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> {
match item {
Annotatable::Item(item) => {
let is_packed = matches!(
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true),
AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id),
Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
);

View file

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

View file

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

View file

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

View file

@ -204,11 +204,8 @@ fn main() {
assert_eq!(intrinsics::size_of_val(a) as u8, 16);
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
assert_eq!(
intrinsics::min_align_of_val(&a) as u8,
intrinsics::min_align_of::<&str>() as u8
);
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
assert!(!intrinsics::needs_drop::<u8>());
assert!(!intrinsics::needs_drop::<[u8]>());

View file

@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv(
CanonAbi::Rust | CanonAbi::C => default_call_conv,
CanonAbi::RustCold => CallConv::Cold,
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
CanonAbi::Custom => default_call_conv,
CanonAbi::X86(x86_call) => match x86_call {
X86Call::SysV64 => CallConv::SystemV,
X86Call::Win64 => CallConv::WindowsFastcall,

View file

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

View file

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

View file

@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta);
ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
}
sym::min_align_of_val => {
sym::align_of_val => {
intrinsic_args!(fx, args => (ptr); intrinsic);
let layout = fx.layout_of(generic_args.type_at(0));
@ -613,7 +613,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
intrinsic_args!(fx, args => (vtable); intrinsic);
let vtable = vtable.load_scalar(fx);
let align = crate::vtable::min_align_of_obj(fx, vtable);
let align = crate::vtable::align_of_obj(fx, vtable);
ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
}

View file

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

View file

@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>(
// load size/align from vtable
(
crate::vtable::size_of_obj(fx, info.unwrap()),
crate::vtable::min_align_of_obj(fx, info.unwrap()),
crate::vtable::align_of_obj(fx, info.unwrap()),
)
}
ty::Slice(_) | ty::Str => {

View file

@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
)
}
pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
fx.bcx.ins().load(
fx.pointer_type,

View file

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

View file

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

View file

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

View file

@ -153,7 +153,7 @@ fn main() {
let slice = &[0, 1] as &[i32];
let slice_ptr = slice as *const [i32] as *const i32;
let align = intrinsics::min_align_of::<*const i32>();
let align = intrinsics::align_of::<*const i32>();
assert_eq!(slice_ptr as usize % align, 0);
//return;
@ -194,8 +194,8 @@ fn main() {
assert_eq!(intrinsics::size_of_val(a) as u8, 8);
assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
assert!(!intrinsics::needs_drop::<u8>());
assert!(!intrinsics::needs_drop::<[u8]>());

View file

@ -2,9 +2,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
unknown feature specified for `-Ctarget-feature`: `{$feature}`
.note = features must begin with a `+` to enable or `-` to disable it
codegen_gcc_forbidden_ctarget_feature =
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
codegen_gcc_unwinding_inline_asm =
GCC backend does not support unwinding from inline asm
@ -26,10 +23,6 @@ codegen_gcc_unknown_ctarget_feature =
.possible_feature = you might have meant: `{$rust_feature}`
.consider_filing_feature_request = consider filing a feature request
codegen_gcc_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future
codegen_gcc_missing_features =
add the missing features in a `target_feature` attribute

View file

@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
let attribute = match conv {
CanonAbi::C | CanonAbi::Rust => return None,
CanonAbi::RustCold => FnAttribute::Cold,
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.
CanonAbi::Custom => return None,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
},
CanonAbi::RustCold => FnAttribute::Cold,
CanonAbi::GpuKernel => {
if arch == "amdgpu" {
FnAttribute::GcnAmdGpuHsaKernel

View file

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

View file

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

View file

@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
pub rust_feature: PossibleFeature<'a>,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_gcc_forbidden_ctarget_feature)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_gcc_possible_feature)]

View file

@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_session::Session;
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
use smallvec::{SmallVec, smallvec};
use crate::errors::{
ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
UnstableCTargetFeature,
};
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
let mut features: Vec<&str> = Vec::new();
retpoline_features_by_flags(sess, &mut features);
features
}
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(feature))
@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
sess.dcx().emit_warn(unknown_feature);
}
Some(&(_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. (It makes little sense
// to hard-error here since we just warn about fully unknown
// features above).
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
stability.verify_feature_enabled_by_flag(sess, enable, feature);
}
}

View file

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

View file

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

View file

@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto =
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
codegen_llvm_forbidden_ctarget_feature =
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
codegen_llvm_from_llvm_diag = {$message}
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
@ -76,10 +71,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
codegen_llvm_unstable_ctarget_feature =
unstable feature specified for `-Ctarget-feature`: `{$feature}`
.note = this feature is not stably supported; its behavior can change in the future
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
codegen_llvm_write_ir = failed to write LLVM IR to {$path}

View file

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

View file

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

View file

@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
use smallvec::SmallVec;
@ -256,11 +257,11 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
StackProbeType::Inline => "inline-asm",
// Flag our internal `__rust_probestack` function as the stack probe symbol.
// This is defined in the `compiler-builtins` crate for each architecture.
StackProbeType::Call => "__rust_probestack",
StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"),
// Pick from the two above based on the LLVM version.
StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
if llvm_util::get_version() < min_llvm_version_for_inline {
"__rust_probestack"
&mangle_internal_symbol(cx.tcx, "__rust_probestack")
} else {
"inline-asm"
}

View file

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

View file

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

View file

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

View file

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

View file

@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
pub rust_feature: PossibleFeature<'a>,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_unstable_ctarget_feature)]
#[note]
pub(crate) struct UnstableCTargetFeature<'a> {
pub feature: &'a str,
}
#[derive(Diagnostic)]
#[diag(codegen_llvm_forbidden_ctarget_feature)]
#[note]
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
pub(crate) struct ForbiddenCTargetFeature<'a> {
pub feature: &'a str,
pub enabled: &'a str,
pub reason: &'a str,
}
#[derive(Subdiagnostic)]
pub(crate) enum PossibleFeature<'a> {
#[help(codegen_llvm_possible_feature)]

View file

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

View file

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

View file

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

View file

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

View file

@ -16,6 +16,7 @@ use rustc_fs_util::path_to_c_string;
use rustc_middle::bug;
use rustc_session::Session;
use rustc_session::config::{PrintKind, PrintRequest};
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
use rustc_span::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
@ -23,8 +24,7 @@ use smallvec::{SmallVec, smallvec};
use crate::back::write::create_informational_target_machine;
use crate::errors::{
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
};
use crate::llvm;
@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
handle_native(cpu_name)
}
fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
let mut features: Vec<&str> = Vec::new();
retpoline_features_by_flags(sess, &mut features);
features
}
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
/// `--target` and similar).
pub(crate) fn global_llvm_features(
@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features(
// Compute implied features
let mut all_rust_features = vec![];
for feature in sess.opts.cg.target_feature.split(',') {
for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
if let Some(feature) = feature.strip_prefix('+') {
all_rust_features.extend(
UnordSet::from(sess.target.implied_target_features(feature))
@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features(
sess.dcx().emit_warn(unknown_feature);
}
Some((_, stability, _)) => {
if let Err(reason) = stability.toggle_allowed() {
sess.dcx().emit_warn(ForbiddenCTargetFeature {
feature,
enabled: if enable { "enabled" } else { "disabled" },
reason,
});
} else if stability.requires_nightly().is_some() {
// An unstable feature. Warn about using it. It makes little sense
// to hard-error here since we just warn about fully unknown
// features above.
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
}
stability.verify_feature_enabled_by_flag(sess, enable, feature);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -118,7 +118,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
llsize
}
sym::min_align_of_val => {
sym::align_of_val => {
let tp_ty = fn_args.type_at(0);
let (_, meta) = args[0].val.pointer_parts();
let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);

Some files were not shown because too many files have changed in this diff Show more